diff --git a/tests/migration/src/commonMain/graphql/operations.graphql b/tests/migration/src/commonMain/graphql/operations.graphql index 34795e160..38005b0e7 100644 --- a/tests/migration/src/commonMain/graphql/operations.graphql +++ b/tests/migration/src/commonMain/graphql/operations.graphql @@ -32,6 +32,14 @@ query RepositoryListQuery { id name } + owner { + id + name + repositories { + id + stars + } + } } } diff --git a/tests/migration/src/commonMain/graphql/schema.graphqls b/tests/migration/src/commonMain/graphql/schema.graphqls index a754708e7..8363e6ec7 100644 --- a/tests/migration/src/commonMain/graphql/schema.graphqls +++ b/tests/migration/src/commonMain/graphql/schema.graphqls @@ -19,6 +19,7 @@ type Repository { id: ID! stars: Int! starGazers: [User!]! + owner: User! } type Project { diff --git a/tests/migration/src/commonTest/kotlin/MigrationTest.kt b/tests/migration/src/commonTest/kotlin/MigrationTest.kt index 5ee96765c..9a7029317 100644 --- a/tests/migration/src/commonTest/kotlin/MigrationTest.kt +++ b/tests/migration/src/commonTest/kotlin/MigrationTest.kt @@ -53,7 +53,19 @@ private val REPOSITORY_LIST_RESPONSE = """ "id": "1", "name": "Jane" } + ], + "owner": { + "__typename": "User", + "id": "2", + "name": "Owner", + "repositories": [ + { + "__typename": "Repository", + "id": "0", + "stars": 10 + } ] + } } ] } @@ -69,9 +81,21 @@ private val REPOSITORY_LIST_DATA = RepositoryListQuery.Data( RepositoryListQuery.StarGazer(id = "0", name = "John", __typename = "User"), RepositoryListQuery.StarGazer(id = "1", name = "Jane", __typename = "User"), ), - __typename = "Repository" - ) - ) + __typename = "Repository", + owner = RepositoryListQuery.Owner( + id = "2", + name = "Owner", + __typename = "User", + repositories = listOf( + RepositoryListQuery.Repository1( + id = "0", + stars = 10, + __typename = "Repository", + ), + ), + ), + ), + ), ) class MigrationTest { @@ -172,35 +196,36 @@ private suspend fun CacheManager.migrateFrom(legacyStore: LegacyApolloStore) { } private fun LegacyNormalizedCache.allRecordsSequence(): Sequence { - suspend fun SequenceScope.yieldRecordsRecursively(cache: LegacyNormalizedCache, cacheKeys: List) { - for (cacheKeysChunk in cacheKeys.chunked(50)) { - val records = cache.loadRecords(cacheKeysChunk.map{it.key}, LegacyCacheHeaders.NONE) + val visited = mutableSetOf() + suspend fun SequenceScope.yieldRecordsRecursively(cacheKeys: Sequence) { + val unvisitedCacheKeys = cacheKeys.filter { visited.add(it.key) } + for (cacheKeysChunk in unvisitedCacheKeys.chunked(50)) { + val records = loadRecords(cacheKeysChunk.map { it.key }, LegacyCacheHeaders.NONE) yieldAll(records) - val references = records.flatMap{it.references()} - yieldRecordsRecursively(cache, references) + val references = records.asSequence().flatMap { it.references() } + yieldRecordsRecursively(references) } } return sequence { - yieldRecordsRecursively(this@allRecordsSequence, listOf(LegacyCacheKey.rootKey())) + yieldRecordsRecursively(sequenceOf(LegacyCacheKey.rootKey())) } } -private fun LegacyRecord.references(): List { - fun LegacyRecordValue.references(): List { - return when (this) { - is LegacyCacheKey -> listOf(this) - is List<*> -> this.flatMap { it.references() } - is Map<*, *> -> this.values.flatMap { it.references() } - else -> emptyList() +private fun LegacyRecord.references(): Sequence { + fun LegacyRecordValue.valueReferences(): Sequence = sequence { + when (val value = this@valueReferences) { + is LegacyCacheKey -> yield(value) + is List<*> -> yieldAll(value.flatMap { it.valueReferences() }) + is Map<*, *> -> yieldAll(value.values.flatMap { it.valueReferences() }) } } - return fields.values.flatMap { it.references() } + return fields.values.asSequence().flatMap { it.valueReferences() } } private fun LegacyRecord.toRecord(): Record = Record( key = CacheKey(key), fields = fields.mapValues { (_, value) -> value.toRecordValue() }, - mutationId = mutationId + mutationId = mutationId, ) private fun LegacyRecordValue.toRecordValue(): RecordValue = when (this) {