From c26a0245fef9bcfef0dd2b2f8fe5d15830aae051 Mon Sep 17 00:00:00 2001 From: BoD Date: Tue, 28 Jan 2025 14:59:37 +0100 Subject: [PATCH 01/11] Add support for partial responses --- gradle/libs.versions.toml | 1 + normalized-cache-incubating/build.gradle.kts | 1 + .../cache/normalized/ApolloStore.kt | 19 + .../cache/normalized/ClientCacheExtensions.kt | 61 +- .../api/OperationCacheExtensions.kt | 6 + .../internal/ApolloCacheInterceptor.kt | 50 +- .../normalized/internal/CacheBatchReader.kt | 109 ++-- .../normalized/internal/DefaultApolloStore.kt | 87 +++ tests/partial-results/build.gradle.kts | 42 ++ .../src/commonMain/graphql/extra.graphqls | 8 + .../src/commonMain/graphql/operation.graphql | 75 +++ .../src/commonMain/graphql/schema.graphqls | 24 + .../kotlin/test/CachePartialResultTest.kt | 534 ++++++++++++++++++ 13 files changed, 970 insertions(+), 47 deletions(-) create mode 100644 tests/partial-results/build.gradle.kts create mode 100644 tests/partial-results/src/commonMain/graphql/extra.graphqls create mode 100644 tests/partial-results/src/commonMain/graphql/operation.graphql create mode 100644 tests/partial-results/src/commonMain/graphql/schema.graphqls create mode 100644 tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c63c76df..9174ca9f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,6 +19,7 @@ apollo-compiler = { group = "com.apollographql.apollo", name = "apollo-compiler" apollo-cache = { group = "com.apollographql.apollo", name = "apollo-normalized-cache", version.ref = "apollo" } apollo-cache-sqlite = { group = "com.apollographql.apollo", name = "apollo-normalized-cache-sqlite", version.ref = "apollo" } apollo-plugin = { group = "com.apollographql.apollo", name = "apollo-gradle-plugin", version.ref = "apollo" } +apollo-execution = { group = "com.apollographql.apollo", name = "apollo-execution", version.ref = "apollo" } atomicfu-library = { group = "org.jetbrains.kotlinx", name = "atomicfu", version.ref = "atomicfu" } atomicfu-plugin = { group = "org.jetbrains.kotlinx", name = "atomicfu-gradle-plugin", version.ref = "atomicfu" } kotlin-test = { group = "org.jetbrains.kotlin", name = "kotlin-test" } # the Kotlin plugin resolves the version diff --git a/normalized-cache-incubating/build.gradle.kts b/normalized-cache-incubating/build.gradle.kts index 8327047c..03e1c8ed 100644 --- a/normalized-cache-incubating/build.gradle.kts +++ b/normalized-cache-incubating/build.gradle.kts @@ -22,6 +22,7 @@ kotlin { implementation(libs.okio) api(libs.uuid) implementation(libs.atomicfu.library) + implementation(libs.apollo.execution) } } diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ApolloStore.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ApolloStore.kt index 6395e463..cf0d6539 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ApolloStore.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ApolloStore.kt @@ -1,5 +1,6 @@ package com.apollographql.cache.normalized +import com.apollographql.apollo.api.ApolloResponse import com.apollographql.apollo.api.CustomScalarAdapters import com.apollographql.apollo.api.Executable import com.apollographql.apollo.api.Fragment @@ -71,6 +72,24 @@ interface ApolloStore { cacheHeaders: CacheHeaders = CacheHeaders.NONE, ): ReadResult + /** + * Reads an operation from the store, returning only the present data. + * Missing fields are returned as `null` if their type is nullable, bubbling up to their parent otherwise. + * When a field is missing, a corresponding [com.apollographql.apollo.api.Error] is present in [ApolloResponse.errors]. + * + * This is a synchronous operation that might block if the underlying cache is doing IO. + * + * @param operation the operation to read + * + * @throws [com.apollographql.apollo.exception.ApolloException] on cache read errors + */ + suspend fun readOperationPartial( + operation: Operation, + schema: String, + customScalarAdapters: CustomScalarAdapters = CustomScalarAdapters.Empty, + cacheHeaders: CacheHeaders = CacheHeaders.NONE, + ): ApolloResponse + /** * Reads a fragment from the store. * diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ClientCacheExtensions.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ClientCacheExtensions.kt index 2dbb1850..dd061a83 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ClientCacheExtensions.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ClientCacheExtensions.kt @@ -272,6 +272,16 @@ fun MutableExecutionOptions.storeReceiveDate(storeReceiveDate: Boolean) = StoreReceiveDateContext(storeReceiveDate) ) +/** + * @param retrievePartialResponses Whether to return partial data from the cache (`true`), or no data with a [CacheMissException] whenever a field + * is missing (`false`). + * + * Default: false + */ +fun MutableExecutionOptions.retrievePartialResponses(retrievePartialResponses: Boolean) = addExecutionContext( + RetrievePartialResponsesContext(retrievePartialResponses) +) + /** * @param storeExpirationDate Whether to store the expiration date in the cache. * @@ -405,19 +415,43 @@ internal val ExecutionOptions.cacheHeaders: CacheHeaders internal val ApolloRequest.watchContext: WatchContext? get() = executionContext[WatchContext] -/** - * @param isCacheHit true if this was a cache hit - * @param cacheMissException the exception while reading the cache. Note that it's possible to have [isCacheHit] == false && [cacheMissException] == null - * if no cache read was attempted - */ +internal val ApolloRequest.retrievePartialResponses + get() = executionContext[RetrievePartialResponsesContext]?.value ?: false + + class CacheInfo private constructor( val cacheStartMillis: Long, val cacheEndMillis: Long, val networkStartMillis: Long, val networkEndMillis: Long, + + /** + * True if the response is from the cache, false if it's from the network. + */ + val isFromCache: Boolean, + + /** + * True if all the fields are found in the cache, false for full or partial cache misses. + */ val isCacheHit: Boolean, + + /** + * The exception that occurred while reading the cache. + * Always `null` if [isFromCache] is false, or when partial responses are enabled. + * @see MutableExecutionOptions.retrievePartialResponses + */ val cacheMissException: CacheMissException?, + + /** + * The exception that occurred while reading the network. + * Always `null` if [isFromCache] is true. + */ val networkException: ApolloException?, + + /** + * True if at least one field in the response is stale. + * Always `false` if [isFromCache] is false. + */ val isStale: Boolean, ) : ExecutionContext.Element { override val key: ExecutionContext.Key<*> @@ -430,6 +464,7 @@ class CacheInfo private constructor( .cacheEndMillis(cacheEndMillis) .networkStartMillis(networkStartMillis) .networkEndMillis(networkEndMillis) + .fromCache(isFromCache) .cacheHit(isCacheHit) .cacheMissException(cacheMissException) .networkException(networkException) @@ -441,6 +476,7 @@ class CacheInfo private constructor( private var cacheEndMillis: Long = 0 private var networkStartMillis: Long = 0 private var networkEndMillis: Long = 0 + private var fromCache: Boolean = false private var cacheHit: Boolean = false private var cacheMissException: CacheMissException? = null private var networkException: ApolloException? = null @@ -462,6 +498,10 @@ class CacheInfo private constructor( this.networkEndMillis = networkEndMillis } + fun fromCache(fromCache: Boolean) = apply { + this.fromCache = fromCache + } + fun cacheHit(cacheHit: Boolean) = apply { this.cacheHit = cacheHit } @@ -483,6 +523,7 @@ class CacheInfo private constructor( cacheEndMillis = cacheEndMillis, networkStartMillis = networkStartMillis, networkEndMillis = networkEndMillis, + isFromCache = fromCache, isCacheHit = cacheHit, cacheMissException = cacheMissException, networkException = networkException, @@ -499,7 +540,7 @@ class CacheInfo private constructor( */ val ApolloResponse.isFromCache: Boolean get() { - return cacheInfo?.isCacheHit == true || exception is CacheMissException + return cacheInfo?.isFromCache == true } val ApolloResponse.cacheInfo @@ -559,7 +600,6 @@ internal class StoreExpirationDateContext(val value: Boolean) : ExecutionContext companion object Key : ExecutionContext.Key } - internal class WriteToCacheAsynchronouslyContext(val value: Boolean) : ExecutionContext.Element { override val key: ExecutionContext.Key<*> get() = Key @@ -597,6 +637,13 @@ internal class FetchFromCacheContext(val value: Boolean) : ExecutionContext.Elem companion object Key : ExecutionContext.Key } +internal class RetrievePartialResponsesContext(val value: Boolean) : ExecutionContext.Element { + override val key: ExecutionContext.Key<*> + get() = Key + + companion object Key : ExecutionContext.Key +} + internal fun ApolloRequest.Builder.fetchFromCache(fetchFromCache: Boolean) = apply { addExecutionContext(FetchFromCacheContext(fetchFromCache)) } diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/api/OperationCacheExtensions.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/api/OperationCacheExtensions.kt index 6741e464..839bee7c 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/api/OperationCacheExtensions.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/api/OperationCacheExtensions.kt @@ -53,6 +53,7 @@ fun Executable.readDataFromCache( cacheHeaders = cacheHeaders, variables = variables, fieldKeyGenerator = fieldKeyGenerator, + retrievePartialResponses = false, ).toData(adapter(), customScalarAdapters, variables) } @@ -73,6 +74,7 @@ fun Executable.readDataFromCache( cacheHeaders = cacheHeaders, variables = variables, fieldKeyGenerator = fieldKeyGenerator, + retrievePartialResponses = false, ).toData(adapter(), customScalarAdapters, variables) } @@ -83,6 +85,7 @@ internal fun Executable.readDataFromCacheInternal( cacheHeaders: CacheHeaders, variables: Executable.Variables, fieldKeyGenerator: FieldKeyGenerator, + retrievePartialResponses: Boolean, ): CacheBatchReaderData = readInternal( cacheKey = cacheKey, cache = cache, @@ -90,6 +93,7 @@ internal fun Executable.readDataFromCacheInternal( cacheHeaders = cacheHeaders, variables = variables, fieldKeyGenerator = fieldKeyGenerator, + retrievePartialResponses = retrievePartialResponses, ) @@ -100,6 +104,7 @@ private fun Executable.readInternal( cacheHeaders: CacheHeaders, variables: Executable.Variables, fieldKeyGenerator: FieldKeyGenerator, + retrievePartialResponses: Boolean, ): CacheBatchReaderData { return CacheBatchReader( cache = cache, @@ -110,6 +115,7 @@ private fun Executable.readInternal( rootSelections = rootField().selections, rootField = rootField(), fieldKeyGenerator = fieldKeyGenerator, + retrievePartialResponses = retrievePartialResponses, ).collectData() } diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/ApolloCacheInterceptor.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/ApolloCacheInterceptor.kt index 531a6197..d6234407 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/ApolloCacheInterceptor.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/ApolloCacheInterceptor.kt @@ -26,6 +26,7 @@ import com.apollographql.cache.normalized.doNotStore import com.apollographql.cache.normalized.fetchFromCache import com.apollographql.cache.normalized.memoryCacheOnly import com.apollographql.cache.normalized.optimisticData +import com.apollographql.cache.normalized.retrievePartialResponses import com.apollographql.cache.normalized.storePartialResponses import com.apollographql.cache.normalized.storeReceiveDate import com.apollographql.cache.normalized.writeToCacheAsynchronously @@ -201,18 +202,53 @@ internal class ApolloCacheInterceptor( } } - private fun readFromCache( + private suspend fun readFromCache( request: ApolloRequest, customScalarAdapters: CustomScalarAdapters, ): ApolloResponse { - val operation = request.operation + var cacheHeaders = request.cacheHeaders + if (request.memoryCacheOnly) { + cacheHeaders += CacheHeaders.Builder().addHeader(ApolloCacheHeaders.MEMORY_CACHE_ONLY, "true").build() + } + return if (request.retrievePartialResponses) { + readFromCachePartial(request, customScalarAdapters, cacheHeaders) + } else { + readFromCacheThrowCacheMiss(request, customScalarAdapters, cacheHeaders) + } + } + + private suspend fun readFromCachePartial( + request: ApolloRequest, + customScalarAdapters: CustomScalarAdapters, + cacheHeaders: CacheHeaders, + ): ApolloResponse { val startMillis = currentTimeMillis() + val response = store.readOperationPartial( + operation = request.operation, + schema = cacheHeaders.headerValue("schema")!!, // TODO + customScalarAdapters = customScalarAdapters, + cacheHeaders = cacheHeaders, + ) + return response.newBuilder() + .requestUuid(request.requestUuid) + .cacheInfo( + response.cacheInfo!!.newBuilder() + .cacheStartMillis(startMillis) + .cacheEndMillis(currentTimeMillis()) + .build() + ) + .isLast(true) + .build() + } + private fun readFromCacheThrowCacheMiss( + request: ApolloRequest, + customScalarAdapters: CustomScalarAdapters, + cacheHeaders: CacheHeaders, + ): ApolloResponse { + val operation = request.operation + val startMillis = currentTimeMillis() val readResult = try { - var cacheHeaders = request.cacheHeaders - if (request.memoryCacheOnly) { - cacheHeaders += CacheHeaders.Builder().addHeader(ApolloCacheHeaders.MEMORY_CACHE_ONLY, "true").build() - } store.readOperation( operation = operation, customScalarAdapters = customScalarAdapters, @@ -229,6 +265,7 @@ internal class ApolloCacheInterceptor( CacheInfo.Builder() .cacheStartMillis(startMillis) .cacheEndMillis(currentTimeMillis()) + .fromCache(true) .cacheHit(false) .cacheMissException(e) .stale(e.stale) @@ -249,6 +286,7 @@ internal class ApolloCacheInterceptor( CacheInfo.Builder() .cacheStartMillis(startMillis) .cacheEndMillis(currentTimeMillis()) + .fromCache(true) .cacheHit(true) .stale(readResult.cacheHeaders.headerValue(ApolloCacheHeaders.STALE) == "true") .build() diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/CacheBatchReader.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/CacheBatchReader.kt index 3e239af8..180d56b6 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/CacheBatchReader.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/CacheBatchReader.kt @@ -5,6 +5,7 @@ import com.apollographql.apollo.api.CompiledField import com.apollographql.apollo.api.CompiledFragment import com.apollographql.apollo.api.CompiledSelection import com.apollographql.apollo.api.CustomScalarAdapters +import com.apollographql.apollo.api.Error import com.apollographql.apollo.api.Executable import com.apollographql.apollo.api.json.MapJsonReader import com.apollographql.apollo.exception.CacheMissException @@ -31,6 +32,7 @@ internal class CacheBatchReader( private val rootSelections: List, private val rootField: CompiledField, private val fieldKeyGenerator: FieldKeyGenerator, + private val retrievePartialResponses: Boolean, ) { /** * @param key: the key of the record we need to fetch @@ -45,10 +47,11 @@ internal class CacheBatchReader( ) /** - * The objects read from the cache with only the fields that are selected and maybe some values changed - * The key is the path to the object + * The objects read from the cache, as a `Map` with only the fields that are selected and maybe some values changed. + * Can also be an [Error] in case of a cache miss. + * The key is the path to the object. */ - private val data = mutableMapOf, Map>() + private val data = mutableMapOf, Any>() /** * True if at least one of the resolved fields is stale @@ -61,9 +64,6 @@ internal class CacheBatchReader( val fields = mutableListOf() } - /** - * - */ private fun collect(selections: List, parentType: String, typename: String?, state: CollectState) { selections.forEach { compiledSelection -> when (compiledSelection) { @@ -116,7 +116,13 @@ internal class CacheBatchReader( // This happens the very first time we read the cache record = Record(pendingReference.key, emptyMap()) } else { - throw CacheMissException(pendingReference.key) + if (retrievePartialResponses) { + data[pendingReference.path] = + cacheMissError(key = pendingReference.key, fieldName = null, stale = false, path = pendingReference.path) + return@forEach + } else { + throw CacheMissException(pendingReference.key) + } } } @@ -128,18 +134,26 @@ internal class CacheBatchReader( return@mapNotNull null } - val value = cacheResolver.resolveField( - ResolverContext( - field = it, - variables = variables, - parent = record, - parentKey = record.key, - parentType = pendingReference.parentType, - cacheHeaders = cacheHeaders, - fieldKeyGenerator = fieldKeyGenerator, - path = pendingReference.fieldPath + it, - ) - ).unwrap() + val value = try { + cacheResolver.resolveField( + ResolverContext( + field = it, + variables = variables, + parent = record, + parentKey = record.key, + parentType = pendingReference.parentType, + cacheHeaders = cacheHeaders, + fieldKeyGenerator = fieldKeyGenerator, + path = pendingReference.fieldPath + it, + ) + ).unwrap() + } catch (e: CacheMissException) { + if (retrievePartialResponses) { + cacheMissError(e, pendingReference.path + it.responseName) + } else { + throw e + } + } value.registerCacheKeys(pendingReference.path + it.responseName, pendingReference.fieldPath + it, it.selections, it.type.rawType().name) it.responseName to value @@ -204,18 +218,26 @@ internal class CacheBatchReader( return@mapNotNull null } - val value = cacheResolver.resolveField( - ResolverContext( - field = it, - variables = variables, - parent = this, - parentKey = "", - parentType = parentType, - cacheHeaders = cacheHeaders, - fieldKeyGenerator = fieldKeyGenerator, - path = fieldPath + it, - ) - ).unwrap() + val value = try { + cacheResolver.resolveField( + ResolverContext( + field = it, + variables = variables, + parent = this, + parentKey = "", + parentType = parentType, + cacheHeaders = cacheHeaders, + fieldKeyGenerator = fieldKeyGenerator, + path = fieldPath + it, + ) + ).unwrap() + } catch (e: CacheMissException) { + if (retrievePartialResponses) { + cacheMissError(e, path + it.responseName) + } else { + throw e + } + } value.registerCacheKeys(path + it.responseName, fieldPath + it, it.selections, it.type.rawType().name) } } @@ -223,7 +245,7 @@ internal class CacheBatchReader( } internal class CacheBatchReaderData( - private val data: Map, Map>, + private val data: Map, Any>, val cacheHeaders: CacheHeaders, ) { fun toData( @@ -239,7 +261,7 @@ internal class CacheBatchReader( } @Suppress("UNCHECKED_CAST") - private fun toMap(): Map { + internal fun toMap(): Map { return data[emptyList()].replaceCacheKeys(emptyList()) as Map } @@ -263,10 +285,29 @@ internal class CacheBatchReader( } else -> { - // Scalar value + // Scalar value or CacheMissException this } } } } + + private fun cacheMissError(key: String, fieldName: String?, stale: Boolean, path: List): Error { + val message = if (fieldName == null) { + "Object '$key' not found in the cache" + } else { + if (stale) { + "Field '$key' on object '$fieldName' is stale in the cache" + } else { + "Object '$key' has no field named '$fieldName' in the cache" + } + } + return Error.Builder(message) + .path(path) + .build() + } + + private fun cacheMissError(exception: CacheMissException, path: List): Error { + return cacheMissError(key = exception.key, fieldName = exception.fieldName, stale = exception.stale, path = path) + } } diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt index 2c4a8981..a93b41e2 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt @@ -1,11 +1,20 @@ package com.apollographql.cache.normalized.internal +import com.apollographql.apollo.api.ApolloResponse import com.apollographql.apollo.api.CustomScalarAdapters +import com.apollographql.apollo.api.Error +import com.apollographql.apollo.api.ExecutionContext import com.apollographql.apollo.api.Fragment import com.apollographql.apollo.api.Operation +import com.apollographql.apollo.api.json.jsonReader import com.apollographql.apollo.api.variables +import com.apollographql.apollo.execution.ExecutableSchema +import com.apollographql.apollo.execution.GraphQLRequest +import com.apollographql.apollo.execution.GraphQLResponse import com.apollographql.cache.normalized.ApolloStore import com.apollographql.cache.normalized.ApolloStore.ReadResult +import com.apollographql.cache.normalized.CacheInfo +import com.apollographql.cache.normalized.api.ApolloCacheHeaders import com.apollographql.cache.normalized.api.CacheHeaders import com.apollographql.cache.normalized.api.CacheKey import com.apollographql.cache.normalized.api.CacheKeyGenerator @@ -19,7 +28,9 @@ import com.apollographql.cache.normalized.api.Record import com.apollographql.cache.normalized.api.RecordMerger import com.apollographql.cache.normalized.api.normalize import com.apollographql.cache.normalized.api.readDataFromCacheInternal +import com.apollographql.cache.normalized.cacheInfo import com.benasher44.uuid.Uuid +import com.benasher44.uuid.uuid4 import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.asSharedFlow @@ -118,6 +129,7 @@ internal class DefaultApolloStore( cacheKey = CacheKey.rootKey(), variables = variables, fieldKeyGenerator = fieldKeyGenerator, + retrievePartialResponses = false, ) return ReadResult( data = batchReaderData.toData(operation.adapter(), customScalarAdapters, variables), @@ -125,6 +137,80 @@ internal class DefaultApolloStore( ) } + override suspend fun readOperationPartial( + operation: Operation, + schema: String, + customScalarAdapters: CustomScalarAdapters, + cacheHeaders: CacheHeaders, + ): ApolloResponse { + val variables = operation.variables(customScalarAdapters, true) + val batchReaderData = operation.readDataFromCacheInternal( + cache = cache, + cacheResolver = cacheResolver, + cacheHeaders = cacheHeaders, + cacheKey = CacheKey.rootKey(), + variables = variables, + fieldKeyGenerator = fieldKeyGenerator, + retrievePartialResponses = true, + ) + val dataAsMapWithCacheMisses: Map = batchReaderData.toMap() + val graphQLRequest = GraphQLRequest.Builder() + .document(operation.document()) + .variables(variables.valueMap) + .build() + val graphQLResponse: GraphQLResponse = ExecutableSchema.Builder() + .schema(schema) + .resolver { resolveInfo -> + dataAsMapWithCacheMisses.valueAtPath(resolveInfo.path) + } + .build() + .execute(graphQLRequest, ExecutionContext.Empty) + + @Suppress("UNCHECKED_CAST") + val dataAsMapWithNullFields = graphQLResponse.data as Map? + val falseVariablesCustomScalarAdapter = + customScalarAdapters.newBuilder().falseVariables(variables.valueMap.filter { it.value == false }.keys).build() + val data = dataAsMapWithNullFields?.let { operation.adapter().fromJson(it.jsonReader(), falseVariablesCustomScalarAdapter) } + return ApolloResponse.Builder(operation, uuid4()) + .data(data) + .errors(graphQLResponse.errors) + .cacheInfo( + CacheInfo.Builder() + .fromCache(true) + .stale(batchReaderData.cacheHeaders.headerValue(ApolloCacheHeaders.STALE) == "true") + .cacheHit(graphQLResponse.errors.isNullOrEmpty()) + .build() + ) + .build() + } + + private fun Map.valueAtPath(path: List): Any? { + var value: Any? = this + for (key in path) { + value = when (value) { + is List<*> -> { + value[key as Int] + } + + is Map<*, *> -> { + @Suppress("UNCHECKED_CAST") + value as Map + value[key] + } + + is Error -> { + // Short circuit if we encounter a cache miss error + return value + } + + else -> { + error("Unknown value type: $value") + } + } + } + return value + } + override fun readFragment( fragment: Fragment, cacheKey: CacheKey, @@ -140,6 +226,7 @@ internal class DefaultApolloStore( cacheKey = cacheKey, variables = variables, fieldKeyGenerator = fieldKeyGenerator, + retrievePartialResponses = false, ) return ReadResult( data = batchReaderData.toData(fragment.adapter(), customScalarAdapters, variables), diff --git a/tests/partial-results/build.gradle.kts b/tests/partial-results/build.gradle.kts new file mode 100644 index 00000000..70b43a0f --- /dev/null +++ b/tests/partial-results/build.gradle.kts @@ -0,0 +1,42 @@ +plugins { + alias(libs.plugins.kotlin.multiplatform) + alias(libs.plugins.apollo) +} + +kotlin { + configureKmp( + withJs = false, + withWasm = false, + withAndroid = false, + withApple = AppleTargets.Host, + ) + + sourceSets { + getByName("commonMain") { + dependencies { + implementation(libs.apollo.runtime) + implementation("com.apollographql.cache:normalized-cache-incubating") + } + } + + getByName("commonTest") { + dependencies { + implementation(libs.apollo.testing.support) + implementation(libs.apollo.mockserver) + implementation(libs.kotlin.test) + } + } + + getByName("jvmTest") { + dependencies { + implementation(libs.slf4j.nop) + } + } + } +} + +apollo { + service("service") { + packageName.set("test") + } +} diff --git a/tests/partial-results/src/commonMain/graphql/extra.graphqls b/tests/partial-results/src/commonMain/graphql/extra.graphqls new file mode 100644 index 00000000..cc0acb33 --- /dev/null +++ b/tests/partial-results/src/commonMain/graphql/extra.graphqls @@ -0,0 +1,8 @@ +extend schema +@link( + url: "https://specs.apollo.dev/kotlin_labs/v0.3", + import: ["@fieldPolicy", "@typePolicy"] +) + +extend type User @typePolicy(keyFields: "id") +extend type Query @fieldPolicy(forField: "users", keyArgs: "ids") diff --git a/tests/partial-results/src/commonMain/graphql/operation.graphql b/tests/partial-results/src/commonMain/graphql/operation.graphql new file mode 100644 index 00000000..667cdab7 --- /dev/null +++ b/tests/partial-results/src/commonMain/graphql/operation.graphql @@ -0,0 +1,75 @@ +query MeWithoutNickNameWithEmailQuery { + me { + firstName + lastName + email + + ... on User { + id + } + } +} + +query MeWithoutNickNameWithoutEmailQuery { + me { + id + firstName + lastName + } +} + +query MeWithNickNameQuery { + me { + id + firstName + lastName + nickName + } +} + +query UsersQuery($ids: [ID!]!) { + users(ids: $ids) { + id + firstName + lastName + email + } +} + +query MeWithBestFriendQuery { + me { + id + firstName + lastName + bestFriend { + id + firstName + lastName + } + projects { + lead { + id + firstName + lastName + } + users { + id + firstName + lastName + } + } + } +} + +query DefaultProjectQuery($id: ID! = "42") { + project(id: $id) { + id + name + description + } + project2: project(id: "44") { + id + name + description + } +} diff --git a/tests/partial-results/src/commonMain/graphql/schema.graphqls b/tests/partial-results/src/commonMain/graphql/schema.graphqls new file mode 100644 index 00000000..609e7d42 --- /dev/null +++ b/tests/partial-results/src/commonMain/graphql/schema.graphqls @@ -0,0 +1,24 @@ +type Query { + me: User! + users(ids: [ID!]!): [User]! + project(id: ID! = "1"): Project +} + +type User { + id: ID! + firstName: String! + lastName: String! + nickName: String + email: String! + bestFriend: User + projects: [Project!]! + mainProject: Project! +} + +type Project { + id: ID! + name: String! + description: String + lead: User + users: [User!]! +} diff --git a/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt b/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt new file mode 100644 index 00000000..8c3a7082 --- /dev/null +++ b/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt @@ -0,0 +1,534 @@ +package test + +import com.apollographql.apollo.ApolloClient +import com.apollographql.apollo.api.Error +import com.apollographql.apollo.api.Error.Location +import com.apollographql.apollo.testing.internal.runTest +import com.apollographql.cache.normalized.ApolloStore +import com.apollographql.cache.normalized.FetchPolicy +import com.apollographql.cache.normalized.api.CacheHeaders +import com.apollographql.cache.normalized.api.CacheKey +import com.apollographql.cache.normalized.api.IdCacheKeyGenerator +import com.apollographql.cache.normalized.api.IdCacheKeyResolver +import com.apollographql.cache.normalized.api.NormalizedCache +import com.apollographql.cache.normalized.apolloStore +import com.apollographql.cache.normalized.cacheHeaders +import com.apollographql.cache.normalized.fetchPolicy +import com.apollographql.cache.normalized.memory.MemoryCacheFactory +import com.apollographql.cache.normalized.normalizedCache +import com.apollographql.cache.normalized.retrievePartialResponses +import com.apollographql.cache.normalized.store +import com.apollographql.cache.normalized.storePartialResponses +import com.apollographql.mockserver.MockServer +import com.apollographql.mockserver.enqueueString +import okio.use +import kotlin.test.Test +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals +import kotlin.test.assertNull + +class CachePartialResultTest { + private lateinit var mockServer: MockServer + + private fun setUp() { + mockServer = MockServer() + } + + private fun tearDown() { + mockServer.close() + } + + @Test + fun simple() = runTest(before = { setUp() }, after = { tearDown() }) { + mockServer.enqueueString( + // language=JSON + """ + { + "data": { + "me": { + "__typename": "User", + "id": "1", + "firstName": "John", + "lastName": "Smith", + "email": "jsmith@example.com" + } + } + } + """ + ) + ApolloClient.Builder() + .serverUrl(mockServer.url()) + .normalizedCache(MemoryCacheFactory()) + .cacheHeaders(CacheHeaders.builder() + .addHeader("schema", SCHEMA) + .build() + ) + .retrievePartialResponses(true) + .build() + .use { apolloClient -> + val networkResult = apolloClient.query(MeWithoutNickNameWithEmailQuery()) + .fetchPolicy(FetchPolicy.NetworkOnly) + .execute() + assertEquals( + MeWithoutNickNameWithEmailQuery.Data( + MeWithoutNickNameWithEmailQuery.Me( + __typename = "User", + firstName = "John", + lastName = "Smith", + email = "jsmith@example.com", + id = "1", + onUser = MeWithoutNickNameWithEmailQuery.OnUser( + id = "1" + ) + ) + ), + networkResult.data + ) + + val cacheResult = apolloClient.query(MeWithoutNickNameWithoutEmailQuery()) + .fetchPolicy(FetchPolicy.CacheOnly) + .execute() + assertEquals( + MeWithoutNickNameWithoutEmailQuery.Data( + MeWithoutNickNameWithoutEmailQuery.Me( + id = "1", + firstName = "John", + lastName = "Smith", + __typename = "User" + ) + ), + cacheResult.data + ) + + val cacheMissResult = apolloClient.query(MeWithNickNameQuery()) + .fetchPolicy(FetchPolicy.CacheOnly) + .execute() + assertEquals( + MeWithNickNameQuery.Data( + MeWithNickNameQuery.Me( + id = "1", + firstName = "John", + lastName = "Smith", + nickName = null, + __typename = "User" + ) + ), + cacheMissResult.data + ) + assertErrorsEquals( + listOf( + Error.Builder("Object 'User:1' has no field named 'nickName' in the cache").path(listOf("me", "nickName")).build() + ), + cacheMissResult.errors + ) + } + } + + @Test + fun lists() = runTest(before = { setUp() }, after = { tearDown() }) { + mockServer.enqueueString( + // language=JSON + """ + { + "data": { + "users": [ + { + "__typename": "User", + "id": "1", + "firstName": "John", + "lastName": "Smith", + "email": "jsmith@example.com" + }, + { + "__typename": "User", + "id": "2", + "firstName": "Jane", + "lastName": "Doe", + "email": "jdoe@example.com" + }, + null + ] + }, + "errors": [ + { + "message": "User `3` not found", + "path": ["users", 2] + } + ] + } + """ + ) + ApolloClient.Builder() + .serverUrl(mockServer.url()) + .cacheHeaders(CacheHeaders.builder() + .addHeader("schema", SCHEMA) + .build() + ) + .store( + ApolloStore( + normalizedCacheFactory = MemoryCacheFactory(), + cacheKeyGenerator = IdCacheKeyGenerator(), + cacheResolver = IdCacheKeyResolver() + ) + ) + .retrievePartialResponses(true) + .build() + .use { apolloClient -> + val networkResult = apolloClient.query(UsersQuery(listOf("1", "2", "3"))) + .fetchPolicy(FetchPolicy.NetworkOnly) + .storePartialResponses(true) + .execute() + assertEquals( + UsersQuery.Data( + users = listOf( + UsersQuery.User( + __typename = "User", + id = "1", + firstName = "John", + lastName = "Smith", + email = "jsmith@example.com", + ), + UsersQuery.User( + __typename = "User", + id = "2", + firstName = "Jane", + lastName = "Doe", + email = "jdoe@example.com", + ), + null, + ) + ), + networkResult.data + ) + + val cacheResult = apolloClient.query(UsersQuery(listOf("1", "2", "3"))) + .fetchPolicy(FetchPolicy.CacheOnly) + .execute() + assertEquals( + networkResult.data, + cacheResult.data, + ) + assertErrorsEquals( + listOf( + Error.Builder("Object 'User:3' not found in the cache").path(listOf("users", 2)).build() + ), + cacheResult.errors + ) + } + } + + @Test + fun composite() = runTest(before = { setUp() }, after = { tearDown() }) { + mockServer.enqueueString( + // language=JSON + """ + { + "data": { + "me": { + "__typename": "User", + "id": "1", + "firstName": "John", + "lastName": "Smith", + "bestFriend": { + "__typename": "User", + "id": "2", + "firstName": "Jane", + "lastName": "Doe" + }, + "projects": [ + { + "__typename": "Project", + "lead": { + "__typename": "User", + "id": "3", + "firstName": "Amanda", + "lastName": "Brown" + }, + "users": [ + { + "__typename": "User", + "id": "4", + "firstName": "Alice", + "lastName": "White" + } + ] + } + ] + } + } + } + """ + ) + ApolloClient.Builder() + .serverUrl(mockServer.url()) + .normalizedCache(MemoryCacheFactory()) + .cacheHeaders(CacheHeaders.builder() + .addHeader("schema", SCHEMA) + .build() + ) + .retrievePartialResponses(true) + .build() + .use { apolloClient -> + // Prime the cache + val networkResult = apolloClient.query(MeWithBestFriendQuery()) + .fetchPolicy(FetchPolicy.NetworkOnly) + .execute() + assertEquals( + MeWithBestFriendQuery.Data( + MeWithBestFriendQuery.Me( + __typename = "User", + id = "1", + firstName = "John", + lastName = "Smith", + bestFriend = MeWithBestFriendQuery.BestFriend( + __typename = "User", + id = "2", + firstName = "Jane", + lastName = "Doe" + ), + projects = listOf( + MeWithBestFriendQuery.Project( + lead = MeWithBestFriendQuery.Lead( + __typename = "User", + id = "3", + firstName = "Amanda", + lastName = "Brown" + ), + users = listOf( + MeWithBestFriendQuery.User( + __typename = "User", + id = "4", + firstName = "Alice", + lastName = "White" + ) + ) + ) + ) + ) + ), + networkResult.data + ) + + // Remove project lead from the cache + apolloClient.apolloStore.remove(CacheKey("User", "3")) + val cacheResult = apolloClient.query(MeWithBestFriendQuery()) + .fetchPolicy(FetchPolicy.CacheOnly) + .execute() + assertEquals( + MeWithBestFriendQuery.Data( + MeWithBestFriendQuery.Me( + __typename = "User", + id = "1", + firstName = "John", + lastName = "Smith", + bestFriend = MeWithBestFriendQuery.BestFriend( + __typename = "User", + id = "2", + firstName = "Jane", + lastName = "Doe" + ), + projects = listOf( + MeWithBestFriendQuery.Project( + lead = null, + users = listOf( + MeWithBestFriendQuery.User( + __typename = "User", + id = "4", + firstName = "Alice", + lastName = "White" + ) + ) + ) + ) + ) + ), + cacheResult.data + ) + assertErrorsEquals( + listOf( + Error.Builder("Object 'User:3' not found in the cache").path(listOf("me", "projects", 0, "lead")).build() + ), + cacheResult.errors + ) + + // Remove best friend from the cache + apolloClient.apolloStore.remove(CacheKey("User", "2")) + val cacheResult2 = apolloClient.query(MeWithBestFriendQuery()) + .fetchPolicy(FetchPolicy.CacheOnly) + .execute() + assertEquals( + MeWithBestFriendQuery.Data( + MeWithBestFriendQuery.Me( + __typename = "User", + id = "1", + firstName = "John", + lastName = "Smith", + bestFriend = null, + projects = listOf( + MeWithBestFriendQuery.Project( + lead = null, + users = listOf( + MeWithBestFriendQuery.User( + __typename = "User", + id = "4", + firstName = "Alice", + lastName = "White" + ) + ) + ) + ) + ) + ), + cacheResult2.data + ) + assertErrorsEquals( + listOf( + Error.Builder("Object 'User:2' not found in the cache").path(listOf("me", "bestFriend")).build(), + Error.Builder("Object 'User:3' not found in the cache").path(listOf("me", "projects", 0, "lead")).build(), + ), + cacheResult2.errors + ) + + // Remove project user from the cache + apolloClient.apolloStore.remove(CacheKey("User", "4")) + val cacheResult3 = apolloClient.query(MeWithBestFriendQuery()) + .fetchPolicy(FetchPolicy.CacheOnly) + .execute() + // Due to null bubbling the whole data is null + assertNull(cacheResult3.data) + assertErrorsEquals( + listOf( + Error.Builder("Object 'User:4' not found in the cache").path(listOf("me", "projects", 0, "users", 0)).build() + ), + cacheResult3.errors + ) + } + } + + @Test + fun argumentsAndAliases() = runTest(before = { setUp() }, after = { tearDown() }) { + mockServer.enqueueString( + // language=JSON + """ + { + "data": { + "project": { + "__typename": "Project", + "id": "42", + "name": "El Dorado", + "description": "The lost city of gold" + }, + "project2": { + "__typename": "Project", + "id": "44", + "name": "Atlantis", + "description": "The lost city of water" + } + } + } + """ + ) + ApolloClient.Builder() + .serverUrl(mockServer.url()) + .store( + ApolloStore( + normalizedCacheFactory = MemoryCacheFactory(), + cacheKeyGenerator = IdCacheKeyGenerator(), + cacheResolver = IdCacheKeyResolver() + ) + ) + .cacheHeaders(CacheHeaders.builder() + .addHeader("schema", SCHEMA) + .build() + ) + .retrievePartialResponses(true) + .build() + .use { apolloClient -> + val networkResult = apolloClient.query(DefaultProjectQuery()) + .fetchPolicy(FetchPolicy.NetworkOnly) + .execute() + assertEquals( + DefaultProjectQuery.Data( + project = DefaultProjectQuery.Project( + id = "42", + name = "El Dorado", + description = "The lost city of gold" + ), + project2 = DefaultProjectQuery.Project2( + id = "44", + name = "Atlantis", + description = "The lost city of water" + ) + ), + networkResult.data + ) + + println(NormalizedCache.prettifyDump(apolloClient.apolloStore.dump())) + + val cacheResult = apolloClient.query(DefaultProjectQuery()) + .fetchPolicy(FetchPolicy.CacheOnly) + .execute() + assertEquals( + networkResult.data, + cacheResult.data + ) + } + } +} + +private const val SCHEMA = """ +type Query { + me: User! + users(ids: [ID!]!): [User]! + project(id: ID! = "42"): Project +} + +type User { + id: ID! + firstName: String! + lastName: String! + nickName: String + email: String! + bestFriend: User + projects: [Project!]! + mainProject: Project! +} + +type Project { + id: ID! + name: String! + description: String + lead: User + users: [User!]! +} +""" + +/** + * Helps using assertEquals. + */ +private data class ComparableError( + val message: String, + val locations: List?, + val path: List?, + val extensions: Map?, + val nonStandardFields: Map?, +) + +private fun assertErrorsEquals(expected: Iterable?, actual: Iterable?) = + assertContentEquals(expected?.map { + ComparableError( + message = it.message, + locations = it.locations, + path = it.path, + extensions = it.extensions, + nonStandardFields = it.nonStandardFields + ) + }, actual?.map { + ComparableError( + message = it.message, + locations = it.locations, + path = it.path, + extensions = it.extensions, + nonStandardFields = it.nonStandardFields + ) + }) From f26c8fcd5e840ac17038fcff8e279d516a1d8a95 Mon Sep 17 00:00:00 2001 From: BoD Date: Wed, 29 Jan 2025 12:14:27 +0100 Subject: [PATCH 02/11] Update API dump --- .../api/normalized-cache-incubating.api | 7 +- .../api/normalized-cache-incubating.klib.api | 345 ++++++++++++------ ...ormalized-cache-sqlite-incubating.klib.api | 64 +++- 3 files changed, 278 insertions(+), 138 deletions(-) diff --git a/normalized-cache-incubating/api/normalized-cache-incubating.api b/normalized-cache-incubating/api/normalized-cache-incubating.api index b0ce82f6..1dccbf37 100644 --- a/normalized-cache-incubating/api/normalized-cache-incubating.api +++ b/normalized-cache-incubating/api/normalized-cache-incubating.api @@ -9,6 +9,7 @@ public abstract interface class com/apollographql/cache/normalized/ApolloStore { public abstract fun publish (Ljava/util/Set;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun readFragment (Lcom/apollographql/apollo/api/Fragment;Lcom/apollographql/cache/normalized/api/CacheKey;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;)Lcom/apollographql/cache/normalized/ApolloStore$ReadResult; public abstract fun readOperation (Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;)Lcom/apollographql/cache/normalized/ApolloStore$ReadResult; + public abstract fun readOperationPartial (Lcom/apollographql/apollo/api/Operation;Ljava/lang/String;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun remove (Lcom/apollographql/cache/normalized/api/CacheKey;Z)Z public abstract fun remove (Ljava/util/List;Z)I public abstract fun rollbackOptimisticUpdates (Ljava/util/UUID;)Ljava/util/Set; @@ -25,6 +26,7 @@ public final class com/apollographql/cache/normalized/ApolloStore$Companion { public final class com/apollographql/cache/normalized/ApolloStore$DefaultImpls { public static synthetic fun readFragment$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/apollo/api/Fragment;Lcom/apollographql/cache/normalized/api/CacheKey;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;ILjava/lang/Object;)Lcom/apollographql/cache/normalized/ApolloStore$ReadResult; public static synthetic fun readOperation$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;ILjava/lang/Object;)Lcom/apollographql/cache/normalized/ApolloStore$ReadResult; + public static synthetic fun readOperationPartial$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/apollo/api/Operation;Ljava/lang/String;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; public static synthetic fun remove$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/cache/normalized/api/CacheKey;ZILjava/lang/Object;)Z public static synthetic fun remove$default (Lcom/apollographql/cache/normalized/ApolloStore;Ljava/util/List;ZILjava/lang/Object;)I public static synthetic fun writeFragment$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/apollo/api/Fragment;Lcom/apollographql/cache/normalized/api/CacheKey;Lcom/apollographql/apollo/api/Fragment$Data;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;ILjava/lang/Object;)Ljava/util/Set; @@ -46,7 +48,7 @@ public final class com/apollographql/cache/normalized/ApolloStoreKt { public final class com/apollographql/cache/normalized/CacheInfo : com/apollographql/apollo/api/ExecutionContext$Element { public static final field Key Lcom/apollographql/cache/normalized/CacheInfo$Key; - public synthetic fun (JJJJZLcom/apollographql/apollo/exception/CacheMissException;Lcom/apollographql/apollo/exception/ApolloException;ZLkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (JJJJZZLcom/apollographql/apollo/exception/CacheMissException;Lcom/apollographql/apollo/exception/ApolloException;ZLkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun getCacheEndMillis ()J public final fun getCacheMissException ()Lcom/apollographql/apollo/exception/CacheMissException; public final fun getCacheStartMillis ()J @@ -55,6 +57,7 @@ public final class com/apollographql/cache/normalized/CacheInfo : com/apollograp public final fun getNetworkException ()Lcom/apollographql/apollo/exception/ApolloException; public final fun getNetworkStartMillis ()J public final fun isCacheHit ()Z + public final fun isFromCache ()Z public final fun isStale ()Z public final fun newBuilder ()Lcom/apollographql/cache/normalized/CacheInfo$Builder; } @@ -66,6 +69,7 @@ public final class com/apollographql/cache/normalized/CacheInfo$Builder { public final fun cacheHit (Z)Lcom/apollographql/cache/normalized/CacheInfo$Builder; public final fun cacheMissException (Lcom/apollographql/apollo/exception/CacheMissException;)Lcom/apollographql/cache/normalized/CacheInfo$Builder; public final fun cacheStartMillis (J)Lcom/apollographql/cache/normalized/CacheInfo$Builder; + public final fun fromCache (Z)Lcom/apollographql/cache/normalized/CacheInfo$Builder; public final fun networkEndMillis (J)Lcom/apollographql/cache/normalized/CacheInfo$Builder; public final fun networkException (Lcom/apollographql/apollo/exception/ApolloException;)Lcom/apollographql/cache/normalized/CacheInfo$Builder; public final fun networkStartMillis (J)Lcom/apollographql/cache/normalized/CacheInfo$Builder; @@ -151,6 +155,7 @@ public final class com/apollographql/cache/normalized/NormalizedCache { public static final fun optimisticUpdates (Lcom/apollographql/apollo/api/ApolloRequest$Builder;Lcom/apollographql/apollo/api/Mutation$Data;)Lcom/apollographql/apollo/api/ApolloRequest$Builder; public static final fun refetchPolicy (Lcom/apollographql/apollo/api/MutableExecutionOptions;Lcom/apollographql/cache/normalized/FetchPolicy;)Ljava/lang/Object; public static final fun refetchPolicyInterceptor (Lcom/apollographql/apollo/api/MutableExecutionOptions;Lcom/apollographql/apollo/interceptor/ApolloInterceptor;)Ljava/lang/Object; + public static final fun retrievePartialResponses (Lcom/apollographql/apollo/api/MutableExecutionOptions;Z)Ljava/lang/Object; public static final fun store (Lcom/apollographql/apollo/ApolloClient$Builder;Lcom/apollographql/cache/normalized/ApolloStore;Z)Lcom/apollographql/apollo/ApolloClient$Builder; public static synthetic fun store$default (Lcom/apollographql/apollo/ApolloClient$Builder;Lcom/apollographql/cache/normalized/ApolloStore;ZILjava/lang/Object;)Lcom/apollographql/apollo/ApolloClient$Builder; public static final fun storeExpirationDate (Lcom/apollographql/apollo/api/MutableExecutionOptions;Z)Ljava/lang/Object; diff --git a/normalized-cache-incubating/api/normalized-cache-incubating.klib.api b/normalized-cache-incubating/api/normalized-cache-incubating.klib.api index ffcf6097..cfbb211e 100644 --- a/normalized-cache-incubating/api/normalized-cache-incubating.klib.api +++ b/normalized-cache-incubating/api/normalized-cache-incubating.klib.api @@ -6,41 +6,53 @@ // - Show declarations: true // Library unique name: -abstract class com.apollographql.cache.normalized.api/CacheKeyResolver : com.apollographql.cache.normalized.api/CacheResolver { // com.apollographql.cache.normalized.api/CacheKeyResolver|null[0] - abstract fun cacheKeyForField(com.apollographql.cache.normalized.api/ResolverContext): com.apollographql.cache.normalized.api/CacheKey? // com.apollographql.cache.normalized.api/CacheKeyResolver.cacheKeyForField|cacheKeyForField(com.apollographql.cache.normalized.api.ResolverContext){}[0] - constructor () // com.apollographql.cache.normalized.api/CacheKeyResolver.|(){}[0] - final fun resolveField(com.apollographql.cache.normalized.api/ResolverContext): kotlin/Any? // com.apollographql.cache.normalized.api/CacheKeyResolver.resolveField|resolveField(com.apollographql.cache.normalized.api.ResolverContext){}[0] - open fun listOfCacheKeysForField(com.apollographql.cache.normalized.api/ResolverContext): kotlin.collections/List? // com.apollographql.cache.normalized.api/CacheKeyResolver.listOfCacheKeysForField|listOfCacheKeysForField(com.apollographql.cache.normalized.api.ResolverContext){}[0] -} -abstract class com.apollographql.cache.normalized.api/NormalizedCacheFactory { // com.apollographql.cache.normalized.api/NormalizedCacheFactory|null[0] - abstract fun create(): com.apollographql.cache.normalized.api/NormalizedCache // com.apollographql.cache.normalized.api/NormalizedCacheFactory.create|create(){}[0] - constructor () // com.apollographql.cache.normalized.api/NormalizedCacheFactory.|(){}[0] +final enum class com.apollographql.cache.normalized/FetchPolicy : kotlin/Enum { // com.apollographql.cache.normalized/FetchPolicy|null[0] + enum entry CacheAndNetwork // com.apollographql.cache.normalized/FetchPolicy.CacheAndNetwork|null[0] + enum entry CacheFirst // com.apollographql.cache.normalized/FetchPolicy.CacheFirst|null[0] + enum entry CacheOnly // com.apollographql.cache.normalized/FetchPolicy.CacheOnly|null[0] + enum entry NetworkFirst // com.apollographql.cache.normalized/FetchPolicy.NetworkFirst|null[0] + enum entry NetworkOnly // com.apollographql.cache.normalized/FetchPolicy.NetworkOnly|null[0] + + final val entries // com.apollographql.cache.normalized/FetchPolicy.entries|#static{}entries[0] + final fun (): kotlin.enums/EnumEntries // com.apollographql.cache.normalized/FetchPolicy.entries.|#static(){}[0] + + final fun valueOf(kotlin/String): com.apollographql.cache.normalized/FetchPolicy // com.apollographql.cache.normalized/FetchPolicy.valueOf|valueOf#static(kotlin.String){}[0] + final fun values(): kotlin/Array // com.apollographql.cache.normalized/FetchPolicy.values|values#static(){}[0] } + abstract interface com.apollographql.cache.normalized.api/CacheKeyGenerator { // com.apollographql.cache.normalized.api/CacheKeyGenerator|null[0] abstract fun cacheKeyForObject(kotlin.collections/Map, com.apollographql.cache.normalized.api/CacheKeyGeneratorContext): com.apollographql.cache.normalized.api/CacheKey? // com.apollographql.cache.normalized.api/CacheKeyGenerator.cacheKeyForObject|cacheKeyForObject(kotlin.collections.Map;com.apollographql.cache.normalized.api.CacheKeyGeneratorContext){}[0] } + abstract interface com.apollographql.cache.normalized.api/CacheResolver { // com.apollographql.cache.normalized.api/CacheResolver|null[0] abstract fun resolveField(com.apollographql.cache.normalized.api/ResolverContext): kotlin/Any? // com.apollographql.cache.normalized.api/CacheResolver.resolveField|resolveField(com.apollographql.cache.normalized.api.ResolverContext){}[0] + final class ResolvedValue { // com.apollographql.cache.normalized.api/CacheResolver.ResolvedValue|null[0] constructor (kotlin/Any?, com.apollographql.cache.normalized.api/CacheHeaders) // com.apollographql.cache.normalized.api/CacheResolver.ResolvedValue.|(kotlin.Any?;com.apollographql.cache.normalized.api.CacheHeaders){}[0] + final val cacheHeaders // com.apollographql.cache.normalized.api/CacheResolver.ResolvedValue.cacheHeaders|{}cacheHeaders[0] final fun (): com.apollographql.cache.normalized.api/CacheHeaders // com.apollographql.cache.normalized.api/CacheResolver.ResolvedValue.cacheHeaders.|(){}[0] final val value // com.apollographql.cache.normalized.api/CacheResolver.ResolvedValue.value|{}value[0] final fun (): kotlin/Any? // com.apollographql.cache.normalized.api/CacheResolver.ResolvedValue.value.|(){}[0] } } + abstract interface com.apollographql.cache.normalized.api/EmbeddedFieldsProvider { // com.apollographql.cache.normalized.api/EmbeddedFieldsProvider|null[0] abstract fun getEmbeddedFields(com.apollographql.cache.normalized.api/EmbeddedFieldsContext): kotlin.collections/List // com.apollographql.cache.normalized.api/EmbeddedFieldsProvider.getEmbeddedFields|getEmbeddedFields(com.apollographql.cache.normalized.api.EmbeddedFieldsContext){}[0] } + abstract interface com.apollographql.cache.normalized.api/FieldKeyGenerator { // com.apollographql.cache.normalized.api/FieldKeyGenerator|null[0] abstract fun getFieldKey(com.apollographql.cache.normalized.api/FieldKeyContext): kotlin/String // com.apollographql.cache.normalized.api/FieldKeyGenerator.getFieldKey|getFieldKey(com.apollographql.cache.normalized.api.FieldKeyContext){}[0] } + abstract interface com.apollographql.cache.normalized.api/MaxAgeProvider { // com.apollographql.cache.normalized.api/MaxAgeProvider|null[0] abstract fun getMaxAge(com.apollographql.cache.normalized.api/MaxAgeContext): kotlin.time/Duration // com.apollographql.cache.normalized.api/MaxAgeProvider.getMaxAge|getMaxAge(com.apollographql.cache.normalized.api.MaxAgeContext){}[0] } + abstract interface com.apollographql.cache.normalized.api/MetadataGenerator { // com.apollographql.cache.normalized.api/MetadataGenerator|null[0] abstract fun metadataForObject(kotlin/Any?, com.apollographql.cache.normalized.api/MetadataGeneratorContext): kotlin.collections/Map // com.apollographql.cache.normalized.api/MetadataGenerator.metadataForObject|metadataForObject(kotlin.Any?;com.apollographql.cache.normalized.api.MetadataGeneratorContext){}[0] } + abstract interface com.apollographql.cache.normalized.api/NormalizedCache : com.apollographql.cache.normalized.api/ReadOnlyNormalizedCache { // com.apollographql.cache.normalized.api/NormalizedCache|null[0] abstract fun clearAll() // com.apollographql.cache.normalized.api/NormalizedCache.clearAll|clearAll(){}[0] abstract fun merge(com.apollographql.cache.normalized.api/Record, com.apollographql.cache.normalized.api/CacheHeaders, com.apollographql.cache.normalized.api/RecordMerger): kotlin.collections/Set // com.apollographql.cache.normalized.api/NormalizedCache.merge|merge(com.apollographql.cache.normalized.api.Record;com.apollographql.cache.normalized.api.CacheHeaders;com.apollographql.cache.normalized.api.RecordMerger){}[0] @@ -48,19 +60,26 @@ abstract interface com.apollographql.cache.normalized.api/NormalizedCache : com. abstract fun remove(com.apollographql.cache.normalized.api/CacheKey, kotlin/Boolean): kotlin/Boolean // com.apollographql.cache.normalized.api/NormalizedCache.remove|remove(com.apollographql.cache.normalized.api.CacheKey;kotlin.Boolean){}[0] abstract fun remove(kotlin.collections/Collection, kotlin/Boolean): kotlin/Int // com.apollographql.cache.normalized.api/NormalizedCache.remove|remove(kotlin.collections.Collection;kotlin.Boolean){}[0] abstract fun remove(kotlin/String): kotlin/Int // com.apollographql.cache.normalized.api/NormalizedCache.remove|remove(kotlin.String){}[0] + final object Companion { // com.apollographql.cache.normalized.api/NormalizedCache.Companion|null[0] final fun prettifyDump(kotlin.collections/Map, kotlin.collections/Map>): kotlin/String // com.apollographql.cache.normalized.api/NormalizedCache.Companion.prettifyDump|prettifyDump(kotlin.collections.Map,kotlin.collections.Map>){}[0] } } + abstract interface com.apollographql.cache.normalized.api/ReadOnlyNormalizedCache { // com.apollographql.cache.normalized.api/ReadOnlyNormalizedCache|null[0] abstract fun dump(): kotlin.collections/Map, kotlin.collections/Map> // com.apollographql.cache.normalized.api/ReadOnlyNormalizedCache.dump|dump(){}[0] abstract fun loadRecord(kotlin/String, com.apollographql.cache.normalized.api/CacheHeaders): com.apollographql.cache.normalized.api/Record? // com.apollographql.cache.normalized.api/ReadOnlyNormalizedCache.loadRecord|loadRecord(kotlin.String;com.apollographql.cache.normalized.api.CacheHeaders){}[0] abstract fun loadRecords(kotlin.collections/Collection, com.apollographql.cache.normalized.api/CacheHeaders): kotlin.collections/Collection // com.apollographql.cache.normalized.api/ReadOnlyNormalizedCache.loadRecords|loadRecords(kotlin.collections.Collection;com.apollographql.cache.normalized.api.CacheHeaders){}[0] } + abstract interface com.apollographql.cache.normalized.api/RecordMerger { // com.apollographql.cache.normalized.api/RecordMerger|null[0] abstract fun merge(com.apollographql.cache.normalized.api/Record, com.apollographql.cache.normalized.api/Record): kotlin/Pair> // com.apollographql.cache.normalized.api/RecordMerger.merge|merge(com.apollographql.cache.normalized.api.Record;com.apollographql.cache.normalized.api.Record){}[0] } + abstract interface com.apollographql.cache.normalized/ApolloStore { // com.apollographql.cache.normalized/ApolloStore|null[0] + abstract val changedKeys // com.apollographql.cache.normalized/ApolloStore.changedKeys|{}changedKeys[0] + abstract fun (): kotlinx.coroutines.flow/SharedFlow> // com.apollographql.cache.normalized/ApolloStore.changedKeys.|(){}[0] + abstract fun <#A1: com.apollographql.apollo.api/Fragment.Data> readFragment(com.apollographql.apollo.api/Fragment<#A1>, com.apollographql.cache.normalized.api/CacheKey, com.apollographql.apollo.api/CustomScalarAdapters = ..., com.apollographql.cache.normalized.api/CacheHeaders = ...): com.apollographql.cache.normalized/ApolloStore.ReadResult<#A1> // com.apollographql.cache.normalized/ApolloStore.readFragment|readFragment(com.apollographql.apollo.api.Fragment<0:0>;com.apollographql.cache.normalized.api.CacheKey;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheHeaders){0§}[0] abstract fun <#A1: com.apollographql.apollo.api/Fragment.Data> writeFragment(com.apollographql.apollo.api/Fragment<#A1>, com.apollographql.cache.normalized.api/CacheKey, #A1, com.apollographql.apollo.api/CustomScalarAdapters = ..., com.apollographql.cache.normalized.api/CacheHeaders = ...): kotlin.collections/Set // com.apollographql.cache.normalized/ApolloStore.writeFragment|writeFragment(com.apollographql.apollo.api.Fragment<0:0>;com.apollographql.cache.normalized.api.CacheKey;0:0;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheHeaders){0§}[0] abstract fun <#A1: com.apollographql.apollo.api/Fragment.Data> writeOptimisticUpdates(com.apollographql.apollo.api/Fragment<#A1>, com.apollographql.cache.normalized.api/CacheKey, #A1, com.benasher44.uuid/Uuid, com.apollographql.apollo.api/CustomScalarAdapters = ...): kotlin.collections/Set // com.apollographql.cache.normalized/ApolloStore.writeOptimisticUpdates|writeOptimisticUpdates(com.apollographql.apollo.api.Fragment<0:0>;com.apollographql.cache.normalized.api.CacheKey;0:0;com.benasher44.uuid.Uuid;com.apollographql.apollo.api.CustomScalarAdapters){0§}[0] @@ -75,87 +94,143 @@ abstract interface com.apollographql.cache.normalized/ApolloStore { // com.apoll abstract fun remove(com.apollographql.cache.normalized.api/CacheKey, kotlin/Boolean = ...): kotlin/Boolean // com.apollographql.cache.normalized/ApolloStore.remove|remove(com.apollographql.cache.normalized.api.CacheKey;kotlin.Boolean){}[0] abstract fun remove(kotlin.collections/List, kotlin/Boolean = ...): kotlin/Int // com.apollographql.cache.normalized/ApolloStore.remove|remove(kotlin.collections.List;kotlin.Boolean){}[0] abstract fun rollbackOptimisticUpdates(com.benasher44.uuid/Uuid): kotlin.collections/Set // com.apollographql.cache.normalized/ApolloStore.rollbackOptimisticUpdates|rollbackOptimisticUpdates(com.benasher44.uuid.Uuid){}[0] + abstract suspend fun <#A1: com.apollographql.apollo.api/Operation.Data> readOperationPartial(com.apollographql.apollo.api/Operation<#A1>, kotlin/String, com.apollographql.apollo.api/CustomScalarAdapters = ..., com.apollographql.cache.normalized.api/CacheHeaders = ...): com.apollographql.apollo.api/ApolloResponse<#A1> // com.apollographql.cache.normalized/ApolloStore.readOperationPartial|readOperationPartial(com.apollographql.apollo.api.Operation<0:0>;kotlin.String;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheHeaders){0§}[0] abstract suspend fun publish(kotlin.collections/Set) // com.apollographql.cache.normalized/ApolloStore.publish|publish(kotlin.collections.Set){}[0] - abstract val changedKeys // com.apollographql.cache.normalized/ApolloStore.changedKeys|{}changedKeys[0] - abstract fun (): kotlinx.coroutines.flow/SharedFlow> // com.apollographql.cache.normalized/ApolloStore.changedKeys.|(){}[0] + final class <#A1: com.apollographql.apollo.api/Executable.Data> ReadResult { // com.apollographql.cache.normalized/ApolloStore.ReadResult|null[0] constructor (#A1, com.apollographql.cache.normalized.api/CacheHeaders) // com.apollographql.cache.normalized/ApolloStore.ReadResult.|(1:0;com.apollographql.cache.normalized.api.CacheHeaders){}[0] + final val cacheHeaders // com.apollographql.cache.normalized/ApolloStore.ReadResult.cacheHeaders|{}cacheHeaders[0] final fun (): com.apollographql.cache.normalized.api/CacheHeaders // com.apollographql.cache.normalized/ApolloStore.ReadResult.cacheHeaders.|(){}[0] final val data // com.apollographql.cache.normalized/ApolloStore.ReadResult.data|{}data[0] final fun (): #A1 // com.apollographql.cache.normalized/ApolloStore.ReadResult.data.|(){}[0] } + final object Companion { // com.apollographql.cache.normalized/ApolloStore.Companion|null[0] final val ALL_KEYS // com.apollographql.cache.normalized/ApolloStore.Companion.ALL_KEYS|{}ALL_KEYS[0] final fun (): kotlin.collections/AbstractSet // com.apollographql.cache.normalized/ApolloStore.Companion.ALL_KEYS.|(){}[0] } } + +sealed interface com.apollographql.cache.normalized.api/MaxAge { // com.apollographql.cache.normalized.api/MaxAge|null[0] + final class Duration : com.apollographql.cache.normalized.api/MaxAge { // com.apollographql.cache.normalized.api/MaxAge.Duration|null[0] + constructor (kotlin.time/Duration) // com.apollographql.cache.normalized.api/MaxAge.Duration.|(kotlin.time.Duration){}[0] + + final val duration // com.apollographql.cache.normalized.api/MaxAge.Duration.duration|{}duration[0] + final fun (): kotlin.time/Duration // com.apollographql.cache.normalized.api/MaxAge.Duration.duration.|(){}[0] + } + + final object Inherit : com.apollographql.cache.normalized.api/MaxAge { // com.apollographql.cache.normalized.api/MaxAge.Inherit|null[0] + final fun equals(kotlin/Any?): kotlin/Boolean // com.apollographql.cache.normalized.api/MaxAge.Inherit.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // com.apollographql.cache.normalized.api/MaxAge.Inherit.hashCode|hashCode(){}[0] + final fun toString(): kotlin/String // com.apollographql.cache.normalized.api/MaxAge.Inherit.toString|toString(){}[0] + } +} + +abstract class com.apollographql.cache.normalized.api/CacheKeyResolver : com.apollographql.cache.normalized.api/CacheResolver { // com.apollographql.cache.normalized.api/CacheKeyResolver|null[0] + constructor () // com.apollographql.cache.normalized.api/CacheKeyResolver.|(){}[0] + + abstract fun cacheKeyForField(com.apollographql.cache.normalized.api/ResolverContext): com.apollographql.cache.normalized.api/CacheKey? // com.apollographql.cache.normalized.api/CacheKeyResolver.cacheKeyForField|cacheKeyForField(com.apollographql.cache.normalized.api.ResolverContext){}[0] + final fun resolveField(com.apollographql.cache.normalized.api/ResolverContext): kotlin/Any? // com.apollographql.cache.normalized.api/CacheKeyResolver.resolveField|resolveField(com.apollographql.cache.normalized.api.ResolverContext){}[0] + open fun listOfCacheKeysForField(com.apollographql.cache.normalized.api/ResolverContext): kotlin.collections/List? // com.apollographql.cache.normalized.api/CacheKeyResolver.listOfCacheKeysForField|listOfCacheKeysForField(com.apollographql.cache.normalized.api.ResolverContext){}[0] +} + +abstract class com.apollographql.cache.normalized.api/NormalizedCacheFactory { // com.apollographql.cache.normalized.api/NormalizedCacheFactory|null[0] + constructor () // com.apollographql.cache.normalized.api/NormalizedCacheFactory.|(){}[0] + + abstract fun create(): com.apollographql.cache.normalized.api/NormalizedCache // com.apollographql.cache.normalized.api/NormalizedCacheFactory.create|create(){}[0] +} + final class com.apollographql.cache.normalized.api/CacheControlCacheResolver : com.apollographql.cache.normalized.api/CacheResolver { // com.apollographql.cache.normalized.api/CacheControlCacheResolver|null[0] constructor (com.apollographql.cache.normalized.api/CacheResolver = ...) // com.apollographql.cache.normalized.api/CacheControlCacheResolver.|(com.apollographql.cache.normalized.api.CacheResolver){}[0] constructor (com.apollographql.cache.normalized.api/MaxAgeProvider, com.apollographql.cache.normalized.api/CacheResolver = ...) // com.apollographql.cache.normalized.api/CacheControlCacheResolver.|(com.apollographql.cache.normalized.api.MaxAgeProvider;com.apollographql.cache.normalized.api.CacheResolver){}[0] + final fun resolveField(com.apollographql.cache.normalized.api/ResolverContext): kotlin/Any? // com.apollographql.cache.normalized.api/CacheControlCacheResolver.resolveField|resolveField(com.apollographql.cache.normalized.api.ResolverContext){}[0] } + final class com.apollographql.cache.normalized.api/CacheHeaders { // com.apollographql.cache.normalized.api/CacheHeaders|null[0] + final fun hasHeader(kotlin/String): kotlin/Boolean // com.apollographql.cache.normalized.api/CacheHeaders.hasHeader|hasHeader(kotlin.String){}[0] + final fun headerValue(kotlin/String): kotlin/String? // com.apollographql.cache.normalized.api/CacheHeaders.headerValue|headerValue(kotlin.String){}[0] + final fun newBuilder(): com.apollographql.cache.normalized.api/CacheHeaders.Builder // com.apollographql.cache.normalized.api/CacheHeaders.newBuilder|newBuilder(){}[0] + final fun plus(com.apollographql.cache.normalized.api/CacheHeaders): com.apollographql.cache.normalized.api/CacheHeaders // com.apollographql.cache.normalized.api/CacheHeaders.plus|plus(com.apollographql.cache.normalized.api.CacheHeaders){}[0] + final class Builder { // com.apollographql.cache.normalized.api/CacheHeaders.Builder|null[0] constructor () // com.apollographql.cache.normalized.api/CacheHeaders.Builder.|(){}[0] + final fun addHeader(kotlin/String, kotlin/String): com.apollographql.cache.normalized.api/CacheHeaders.Builder // com.apollographql.cache.normalized.api/CacheHeaders.Builder.addHeader|addHeader(kotlin.String;kotlin.String){}[0] final fun addHeaders(kotlin.collections/Map): com.apollographql.cache.normalized.api/CacheHeaders.Builder // com.apollographql.cache.normalized.api/CacheHeaders.Builder.addHeaders|addHeaders(kotlin.collections.Map){}[0] final fun build(): com.apollographql.cache.normalized.api/CacheHeaders // com.apollographql.cache.normalized.api/CacheHeaders.Builder.build|build(){}[0] } - final fun hasHeader(kotlin/String): kotlin/Boolean // com.apollographql.cache.normalized.api/CacheHeaders.hasHeader|hasHeader(kotlin.String){}[0] - final fun headerValue(kotlin/String): kotlin/String? // com.apollographql.cache.normalized.api/CacheHeaders.headerValue|headerValue(kotlin.String){}[0] - final fun newBuilder(): com.apollographql.cache.normalized.api/CacheHeaders.Builder // com.apollographql.cache.normalized.api/CacheHeaders.newBuilder|newBuilder(){}[0] - final fun plus(com.apollographql.cache.normalized.api/CacheHeaders): com.apollographql.cache.normalized.api/CacheHeaders // com.apollographql.cache.normalized.api/CacheHeaders.plus|plus(com.apollographql.cache.normalized.api.CacheHeaders){}[0] + final object Companion { // com.apollographql.cache.normalized.api/CacheHeaders.Companion|null[0] - final fun builder(): com.apollographql.cache.normalized.api/CacheHeaders.Builder // com.apollographql.cache.normalized.api/CacheHeaders.Companion.builder|builder(){}[0] final val NONE // com.apollographql.cache.normalized.api/CacheHeaders.Companion.NONE|{}NONE[0] final fun (): com.apollographql.cache.normalized.api/CacheHeaders // com.apollographql.cache.normalized.api/CacheHeaders.Companion.NONE.|(){}[0] + + final fun builder(): com.apollographql.cache.normalized.api/CacheHeaders.Builder // com.apollographql.cache.normalized.api/CacheHeaders.Companion.builder|builder(){}[0] } } + final class com.apollographql.cache.normalized.api/CacheKey { // com.apollographql.cache.normalized.api/CacheKey|null[0] constructor (kotlin/String) // com.apollographql.cache.normalized.api/CacheKey.|(kotlin.String){}[0] constructor (kotlin/String, kotlin.collections/List) // com.apollographql.cache.normalized.api/CacheKey.|(kotlin.String;kotlin.collections.List){}[0] constructor (kotlin/String, kotlin/Array...) // com.apollographql.cache.normalized.api/CacheKey.|(kotlin.String;kotlin.Array...){}[0] + + final val key // com.apollographql.cache.normalized.api/CacheKey.key|{}key[0] + final fun (): kotlin/String // com.apollographql.cache.normalized.api/CacheKey.key.|(){}[0] + final fun equals(kotlin/Any?): kotlin/Boolean // com.apollographql.cache.normalized.api/CacheKey.equals|equals(kotlin.Any?){}[0] final fun hashCode(): kotlin/Int // com.apollographql.cache.normalized.api/CacheKey.hashCode|hashCode(){}[0] final fun serialize(): kotlin/String // com.apollographql.cache.normalized.api/CacheKey.serialize|serialize(){}[0] final fun toString(): kotlin/String // com.apollographql.cache.normalized.api/CacheKey.toString|toString(){}[0] + final object Companion { // com.apollographql.cache.normalized.api/CacheKey.Companion|null[0] final fun canDeserialize(kotlin/String): kotlin/Boolean // com.apollographql.cache.normalized.api/CacheKey.Companion.canDeserialize|canDeserialize(kotlin.String){}[0] final fun deserialize(kotlin/String): com.apollographql.cache.normalized.api/CacheKey // com.apollographql.cache.normalized.api/CacheKey.Companion.deserialize|deserialize(kotlin.String){}[0] final fun rootKey(): com.apollographql.cache.normalized.api/CacheKey // com.apollographql.cache.normalized.api/CacheKey.Companion.rootKey|rootKey(){}[0] } - final val key // com.apollographql.cache.normalized.api/CacheKey.key|{}key[0] - final fun (): kotlin/String // com.apollographql.cache.normalized.api/CacheKey.key.|(){}[0] } + final class com.apollographql.cache.normalized.api/CacheKeyGeneratorContext { // com.apollographql.cache.normalized.api/CacheKeyGeneratorContext|null[0] constructor (com.apollographql.apollo.api/CompiledField, com.apollographql.apollo.api/Executable.Variables) // com.apollographql.cache.normalized.api/CacheKeyGeneratorContext.|(com.apollographql.apollo.api.CompiledField;com.apollographql.apollo.api.Executable.Variables){}[0] + final val field // com.apollographql.cache.normalized.api/CacheKeyGeneratorContext.field|{}field[0] final fun (): com.apollographql.apollo.api/CompiledField // com.apollographql.cache.normalized.api/CacheKeyGeneratorContext.field.|(){}[0] final val variables // com.apollographql.cache.normalized.api/CacheKeyGeneratorContext.variables|{}variables[0] final fun (): com.apollographql.apollo.api/Executable.Variables // com.apollographql.cache.normalized.api/CacheKeyGeneratorContext.variables.|(){}[0] } + final class com.apollographql.cache.normalized.api/ConnectionEmbeddedFieldsProvider : com.apollographql.cache.normalized.api/EmbeddedFieldsProvider { // com.apollographql.cache.normalized.api/ConnectionEmbeddedFieldsProvider|null[0] constructor (kotlin.collections/Map>, kotlin.collections/Set) // com.apollographql.cache.normalized.api/ConnectionEmbeddedFieldsProvider.|(kotlin.collections.Map>;kotlin.collections.Set){}[0] + final fun getEmbeddedFields(com.apollographql.cache.normalized.api/EmbeddedFieldsContext): kotlin.collections/List // com.apollographql.cache.normalized.api/ConnectionEmbeddedFieldsProvider.getEmbeddedFields|getEmbeddedFields(com.apollographql.cache.normalized.api.EmbeddedFieldsContext){}[0] + final object Companion // com.apollographql.cache.normalized.api/ConnectionEmbeddedFieldsProvider.Companion|null[0] } + final class com.apollographql.cache.normalized.api/ConnectionFieldKeyGenerator : com.apollographql.cache.normalized.api/FieldKeyGenerator { // com.apollographql.cache.normalized.api/ConnectionFieldKeyGenerator|null[0] constructor (kotlin.collections/Map>) // com.apollographql.cache.normalized.api/ConnectionFieldKeyGenerator.|(kotlin.collections.Map>){}[0] + final fun getFieldKey(com.apollographql.cache.normalized.api/FieldKeyContext): kotlin/String // com.apollographql.cache.normalized.api/ConnectionFieldKeyGenerator.getFieldKey|getFieldKey(com.apollographql.cache.normalized.api.FieldKeyContext){}[0] + final object Companion // com.apollographql.cache.normalized.api/ConnectionFieldKeyGenerator.Companion|null[0] } + final class com.apollographql.cache.normalized.api/ConnectionMetadataGenerator : com.apollographql.cache.normalized.api/MetadataGenerator { // com.apollographql.cache.normalized.api/ConnectionMetadataGenerator|null[0] constructor (kotlin.collections/Set) // com.apollographql.cache.normalized.api/ConnectionMetadataGenerator.|(kotlin.collections.Set){}[0] + final fun metadataForObject(kotlin/Any?, com.apollographql.cache.normalized.api/MetadataGeneratorContext): kotlin.collections/Map // com.apollographql.cache.normalized.api/ConnectionMetadataGenerator.metadataForObject|metadataForObject(kotlin.Any?;com.apollographql.cache.normalized.api.MetadataGeneratorContext){}[0] } + final class com.apollographql.cache.normalized.api/EmbeddedFieldsContext { // com.apollographql.cache.normalized.api/EmbeddedFieldsContext|null[0] constructor (com.apollographql.apollo.api/CompiledNamedType) // com.apollographql.cache.normalized.api/EmbeddedFieldsContext.|(com.apollographql.apollo.api.CompiledNamedType){}[0] + final val parentType // com.apollographql.cache.normalized.api/EmbeddedFieldsContext.parentType|{}parentType[0] final fun (): com.apollographql.apollo.api/CompiledNamedType // com.apollographql.cache.normalized.api/EmbeddedFieldsContext.parentType.|(){}[0] } + final class com.apollographql.cache.normalized.api/FieldKeyContext { // com.apollographql.cache.normalized.api/FieldKeyContext|null[0] constructor (kotlin/String, com.apollographql.apollo.api/CompiledField, com.apollographql.apollo.api/Executable.Variables) // com.apollographql.cache.normalized.api/FieldKeyContext.|(kotlin.String;com.apollographql.apollo.api.CompiledField;com.apollographql.apollo.api.Executable.Variables){}[0] + final val field // com.apollographql.cache.normalized.api/FieldKeyContext.field|{}field[0] final fun (): com.apollographql.apollo.api/CompiledField // com.apollographql.cache.normalized.api/FieldKeyContext.field.|(){}[0] final val parentType // com.apollographql.cache.normalized.api/FieldKeyContext.parentType|{}parentType[0] @@ -163,43 +238,61 @@ final class com.apollographql.cache.normalized.api/FieldKeyContext { // com.apol final val variables // com.apollographql.cache.normalized.api/FieldKeyContext.variables|{}variables[0] final fun (): com.apollographql.apollo.api/Executable.Variables // com.apollographql.cache.normalized.api/FieldKeyContext.variables.|(){}[0] } + final class com.apollographql.cache.normalized.api/FieldRecordMerger : com.apollographql.cache.normalized.api/RecordMerger { // com.apollographql.cache.normalized.api/FieldRecordMerger|null[0] + constructor (com.apollographql.cache.normalized.api/FieldRecordMerger.FieldMerger) // com.apollographql.cache.normalized.api/FieldRecordMerger.|(com.apollographql.cache.normalized.api.FieldRecordMerger.FieldMerger){}[0] + + final fun merge(com.apollographql.cache.normalized.api/Record, com.apollographql.cache.normalized.api/Record): kotlin/Pair> // com.apollographql.cache.normalized.api/FieldRecordMerger.merge|merge(com.apollographql.cache.normalized.api.Record;com.apollographql.cache.normalized.api.Record){}[0] + abstract interface FieldMerger { // com.apollographql.cache.normalized.api/FieldRecordMerger.FieldMerger|null[0] abstract fun mergeFields(com.apollographql.cache.normalized.api/FieldRecordMerger.FieldInfo, com.apollographql.cache.normalized.api/FieldRecordMerger.FieldInfo): com.apollographql.cache.normalized.api/FieldRecordMerger.FieldInfo // com.apollographql.cache.normalized.api/FieldRecordMerger.FieldMerger.mergeFields|mergeFields(com.apollographql.cache.normalized.api.FieldRecordMerger.FieldInfo;com.apollographql.cache.normalized.api.FieldRecordMerger.FieldInfo){}[0] } - constructor (com.apollographql.cache.normalized.api/FieldRecordMerger.FieldMerger) // com.apollographql.cache.normalized.api/FieldRecordMerger.|(com.apollographql.cache.normalized.api.FieldRecordMerger.FieldMerger){}[0] + final class FieldInfo { // com.apollographql.cache.normalized.api/FieldRecordMerger.FieldInfo|null[0] constructor (kotlin/Any?, kotlin.collections/Map) // com.apollographql.cache.normalized.api/FieldRecordMerger.FieldInfo.|(kotlin.Any?;kotlin.collections.Map){}[0] + + final val metadata // com.apollographql.cache.normalized.api/FieldRecordMerger.FieldInfo.metadata|{}metadata[0] + final fun (): kotlin.collections/Map // com.apollographql.cache.normalized.api/FieldRecordMerger.FieldInfo.metadata.|(){}[0] + final val value // com.apollographql.cache.normalized.api/FieldRecordMerger.FieldInfo.value|{}value[0] + final fun (): kotlin/Any? // com.apollographql.cache.normalized.api/FieldRecordMerger.FieldInfo.value.|(){}[0] + final fun component1(): kotlin/Any? // com.apollographql.cache.normalized.api/FieldRecordMerger.FieldInfo.component1|component1(){}[0] final fun component2(): kotlin.collections/Map // com.apollographql.cache.normalized.api/FieldRecordMerger.FieldInfo.component2|component2(){}[0] final fun copy(kotlin/Any? = ..., kotlin.collections/Map = ...): com.apollographql.cache.normalized.api/FieldRecordMerger.FieldInfo // com.apollographql.cache.normalized.api/FieldRecordMerger.FieldInfo.copy|copy(kotlin.Any?;kotlin.collections.Map){}[0] final fun equals(kotlin/Any?): kotlin/Boolean // com.apollographql.cache.normalized.api/FieldRecordMerger.FieldInfo.equals|equals(kotlin.Any?){}[0] final fun hashCode(): kotlin/Int // com.apollographql.cache.normalized.api/FieldRecordMerger.FieldInfo.hashCode|hashCode(){}[0] final fun toString(): kotlin/String // com.apollographql.cache.normalized.api/FieldRecordMerger.FieldInfo.toString|toString(){}[0] - final val metadata // com.apollographql.cache.normalized.api/FieldRecordMerger.FieldInfo.metadata|{}metadata[0] - final fun (): kotlin.collections/Map // com.apollographql.cache.normalized.api/FieldRecordMerger.FieldInfo.metadata.|(){}[0] - final val value // com.apollographql.cache.normalized.api/FieldRecordMerger.FieldInfo.value|{}value[0] - final fun (): kotlin/Any? // com.apollographql.cache.normalized.api/FieldRecordMerger.FieldInfo.value.|(){}[0] } - final fun merge(com.apollographql.cache.normalized.api/Record, com.apollographql.cache.normalized.api/Record): kotlin/Pair> // com.apollographql.cache.normalized.api/FieldRecordMerger.merge|merge(com.apollographql.cache.normalized.api.Record;com.apollographql.cache.normalized.api.Record){}[0] } + final class com.apollographql.cache.normalized.api/GlobalMaxAgeProvider : com.apollographql.cache.normalized.api/MaxAgeProvider { // com.apollographql.cache.normalized.api/GlobalMaxAgeProvider|null[0] constructor (kotlin.time/Duration) // com.apollographql.cache.normalized.api/GlobalMaxAgeProvider.|(kotlin.time.Duration){}[0] + final fun getMaxAge(com.apollographql.cache.normalized.api/MaxAgeContext): kotlin.time/Duration // com.apollographql.cache.normalized.api/GlobalMaxAgeProvider.getMaxAge|getMaxAge(com.apollographql.cache.normalized.api.MaxAgeContext){}[0] } + final class com.apollographql.cache.normalized.api/IdCacheKeyGenerator : com.apollographql.cache.normalized.api/CacheKeyGenerator { // com.apollographql.cache.normalized.api/IdCacheKeyGenerator|null[0] constructor (kotlin/Array... = ...) // com.apollographql.cache.normalized.api/IdCacheKeyGenerator.|(kotlin.Array...){}[0] + final fun cacheKeyForObject(kotlin.collections/Map, com.apollographql.cache.normalized.api/CacheKeyGeneratorContext): com.apollographql.cache.normalized.api/CacheKey? // com.apollographql.cache.normalized.api/IdCacheKeyGenerator.cacheKeyForObject|cacheKeyForObject(kotlin.collections.Map;com.apollographql.cache.normalized.api.CacheKeyGeneratorContext){}[0] } + final class com.apollographql.cache.normalized.api/IdCacheKeyResolver : com.apollographql.cache.normalized.api/CacheKeyResolver { // com.apollographql.cache.normalized.api/IdCacheKeyResolver|null[0] constructor (kotlin.collections/List = ..., kotlin.collections/List = ...) // com.apollographql.cache.normalized.api/IdCacheKeyResolver.|(kotlin.collections.List;kotlin.collections.List){}[0] + final fun cacheKeyForField(com.apollographql.cache.normalized.api/ResolverContext): com.apollographql.cache.normalized.api/CacheKey? // com.apollographql.cache.normalized.api/IdCacheKeyResolver.cacheKeyForField|cacheKeyForField(com.apollographql.cache.normalized.api.ResolverContext){}[0] final fun listOfCacheKeysForField(com.apollographql.cache.normalized.api/ResolverContext): kotlin.collections/List? // com.apollographql.cache.normalized.api/IdCacheKeyResolver.listOfCacheKeysForField|listOfCacheKeysForField(com.apollographql.cache.normalized.api.ResolverContext){}[0] } + final class com.apollographql.cache.normalized.api/MaxAgeContext { // com.apollographql.cache.normalized.api/MaxAgeContext|null[0] constructor (kotlin.collections/List) // com.apollographql.cache.normalized.api/MaxAgeContext.|(kotlin.collections.List){}[0] + + final val fieldPath // com.apollographql.cache.normalized.api/MaxAgeContext.fieldPath|{}fieldPath[0] + final fun (): kotlin.collections/List // com.apollographql.cache.normalized.api/MaxAgeContext.fieldPath.|(){}[0] + final class Field { // com.apollographql.cache.normalized.api/MaxAgeContext.Field|null[0] constructor (kotlin/String, kotlin/String, kotlin/Boolean) // com.apollographql.cache.normalized.api/MaxAgeContext.Field.|(kotlin.String;kotlin.String;kotlin.Boolean){}[0] + final val isTypeComposite // com.apollographql.cache.normalized.api/MaxAgeContext.Field.isTypeComposite|{}isTypeComposite[0] final fun (): kotlin/Boolean // com.apollographql.cache.normalized.api/MaxAgeContext.Field.isTypeComposite.|(){}[0] final val name // com.apollographql.cache.normalized.api/MaxAgeContext.Field.name|{}name[0] @@ -207,28 +300,23 @@ final class com.apollographql.cache.normalized.api/MaxAgeContext { // com.apollo final val type // com.apollographql.cache.normalized.api/MaxAgeContext.Field.type|{}type[0] final fun (): kotlin/String // com.apollographql.cache.normalized.api/MaxAgeContext.Field.type.|(){}[0] } - final val fieldPath // com.apollographql.cache.normalized.api/MaxAgeContext.fieldPath|{}fieldPath[0] - final fun (): kotlin.collections/List // com.apollographql.cache.normalized.api/MaxAgeContext.fieldPath.|(){}[0] } + final class com.apollographql.cache.normalized.api/MetadataGeneratorContext { // com.apollographql.cache.normalized.api/MetadataGeneratorContext|null[0] constructor (com.apollographql.apollo.api/CompiledField, com.apollographql.apollo.api/Executable.Variables) // com.apollographql.cache.normalized.api/MetadataGeneratorContext.|(com.apollographql.apollo.api.CompiledField;com.apollographql.apollo.api.Executable.Variables){}[0] - final fun allArgumentValues(): kotlin.collections/Map // com.apollographql.cache.normalized.api/MetadataGeneratorContext.allArgumentValues|allArgumentValues(){}[0] - final fun argumentValue(kotlin/String): kotlin/Any? // com.apollographql.cache.normalized.api/MetadataGeneratorContext.argumentValue|argumentValue(kotlin.String){}[0] + final val field // com.apollographql.cache.normalized.api/MetadataGeneratorContext.field|{}field[0] final fun (): com.apollographql.apollo.api/CompiledField // com.apollographql.cache.normalized.api/MetadataGeneratorContext.field.|(){}[0] final val variables // com.apollographql.cache.normalized.api/MetadataGeneratorContext.variables|{}variables[0] final fun (): com.apollographql.apollo.api/Executable.Variables // com.apollographql.cache.normalized.api/MetadataGeneratorContext.variables.|(){}[0] + + final fun allArgumentValues(): kotlin.collections/Map // com.apollographql.cache.normalized.api/MetadataGeneratorContext.allArgumentValues|allArgumentValues(){}[0] + final fun argumentValue(kotlin/String): kotlin/Any? // com.apollographql.cache.normalized.api/MetadataGeneratorContext.argumentValue|argumentValue(kotlin.String){}[0] } + final class com.apollographql.cache.normalized.api/Record : kotlin.collections/Map { // com.apollographql.cache.normalized.api/Record|null[0] constructor (kotlin/String, kotlin.collections/Map, com.benasher44.uuid/Uuid? = ..., kotlin.collections/Map> = ...) // com.apollographql.cache.normalized.api/Record.|(kotlin.String;kotlin.collections.Map;com.benasher44.uuid.Uuid?;kotlin.collections.Map>){}[0] - final fun containsKey(kotlin/String): kotlin/Boolean // com.apollographql.cache.normalized.api/Record.containsKey|containsKey(kotlin.String){}[0] - final fun containsValue(kotlin/Any?): kotlin/Boolean // com.apollographql.cache.normalized.api/Record.containsValue|containsValue(kotlin.Any?){}[0] - final fun fieldKeys(): kotlin.collections/Set // com.apollographql.cache.normalized.api/Record.fieldKeys|fieldKeys(){}[0] - final fun get(kotlin/String): kotlin/Any? // com.apollographql.cache.normalized.api/Record.get|get(kotlin.String){}[0] - final fun isEmpty(): kotlin/Boolean // com.apollographql.cache.normalized.api/Record.isEmpty|isEmpty(){}[0] - final fun mergeWith(com.apollographql.cache.normalized.api/Record): kotlin/Pair> // com.apollographql.cache.normalized.api/Record.mergeWith|mergeWith(com.apollographql.cache.normalized.api.Record){}[0] - final fun referencedFields(): kotlin.collections/List // com.apollographql.cache.normalized.api/Record.referencedFields|referencedFields(){}[0] - final object Companion // com.apollographql.cache.normalized.api/Record.Companion|null[0] + final val entries // com.apollographql.cache.normalized.api/Record.entries|{}entries[0] final fun (): kotlin.collections/Set> // com.apollographql.cache.normalized.api/Record.entries.|(){}[0] final val fields // com.apollographql.cache.normalized.api/Record.fields|{}fields[0] @@ -247,11 +335,24 @@ final class com.apollographql.cache.normalized.api/Record : kotlin.collections/M final fun (): kotlin/Int // com.apollographql.cache.normalized.api/Record.sizeInBytes.|(){}[0] final val values // com.apollographql.cache.normalized.api/Record.values|{}values[0] final fun (): kotlin.collections/Collection // com.apollographql.cache.normalized.api/Record.values.|(){}[0] + + final fun containsKey(kotlin/String): kotlin/Boolean // com.apollographql.cache.normalized.api/Record.containsKey|containsKey(kotlin.String){}[0] + final fun containsValue(kotlin/Any?): kotlin/Boolean // com.apollographql.cache.normalized.api/Record.containsValue|containsValue(kotlin.Any?){}[0] + final fun fieldKeys(): kotlin.collections/Set // com.apollographql.cache.normalized.api/Record.fieldKeys|fieldKeys(){}[0] + final fun get(kotlin/String): kotlin/Any? // com.apollographql.cache.normalized.api/Record.get|get(kotlin.String){}[0] + final fun isEmpty(): kotlin/Boolean // com.apollographql.cache.normalized.api/Record.isEmpty|isEmpty(){}[0] + final fun mergeWith(com.apollographql.cache.normalized.api/Record): kotlin/Pair> // com.apollographql.cache.normalized.api/Record.mergeWith|mergeWith(com.apollographql.cache.normalized.api.Record){}[0] + final fun referencedFields(): kotlin.collections/List // com.apollographql.cache.normalized.api/Record.referencedFields|referencedFields(){}[0] + + final object Companion // com.apollographql.cache.normalized.api/Record.Companion|null[0] + // Targets: [js] final fun asJsReadonlyMapView(): kotlin.js.collections/JsReadonlyMap // com.apollographql.cache.normalized.api/Record.asJsReadonlyMapView|asJsReadonlyMapView(){}[0] } + final class com.apollographql.cache.normalized.api/ResolverContext { // com.apollographql.cache.normalized.api/ResolverContext|null[0] constructor (com.apollographql.apollo.api/CompiledField, com.apollographql.apollo.api/Executable.Variables, kotlin.collections/Map, kotlin/String, kotlin/String, com.apollographql.cache.normalized.api/CacheHeaders, com.apollographql.cache.normalized.api/FieldKeyGenerator, kotlin.collections/List) // com.apollographql.cache.normalized.api/ResolverContext.|(com.apollographql.apollo.api.CompiledField;com.apollographql.apollo.api.Executable.Variables;kotlin.collections.Map;kotlin.String;kotlin.String;com.apollographql.cache.normalized.api.CacheHeaders;com.apollographql.cache.normalized.api.FieldKeyGenerator;kotlin.collections.List){}[0] + final val cacheHeaders // com.apollographql.cache.normalized.api/ResolverContext.cacheHeaders|{}cacheHeaders[0] final fun (): com.apollographql.cache.normalized.api/CacheHeaders // com.apollographql.cache.normalized.api/ResolverContext.cacheHeaders.|(){}[0] final val field // com.apollographql.cache.normalized.api/ResolverContext.field|{}field[0] @@ -269,12 +370,19 @@ final class com.apollographql.cache.normalized.api/ResolverContext { // com.apol final val variables // com.apollographql.cache.normalized.api/ResolverContext.variables|{}variables[0] final fun (): com.apollographql.apollo.api/Executable.Variables // com.apollographql.cache.normalized.api/ResolverContext.variables.|(){}[0] } + final class com.apollographql.cache.normalized.api/SchemaCoordinatesMaxAgeProvider : com.apollographql.cache.normalized.api/MaxAgeProvider { // com.apollographql.cache.normalized.api/SchemaCoordinatesMaxAgeProvider|null[0] constructor (kotlin.collections/Map, kotlin.time/Duration) // com.apollographql.cache.normalized.api/SchemaCoordinatesMaxAgeProvider.|(kotlin.collections.Map;kotlin.time.Duration){}[0] + final fun getMaxAge(com.apollographql.cache.normalized.api/MaxAgeContext): kotlin.time/Duration // com.apollographql.cache.normalized.api/SchemaCoordinatesMaxAgeProvider.getMaxAge|getMaxAge(com.apollographql.cache.normalized.api.MaxAgeContext){}[0] } + final class com.apollographql.cache.normalized.memory/MemoryCache : com.apollographql.cache.normalized.api/NormalizedCache { // com.apollographql.cache.normalized.memory/MemoryCache|null[0] constructor (com.apollographql.cache.normalized.api/NormalizedCache? = ..., kotlin/Int = ..., kotlin/Long = ...) // com.apollographql.cache.normalized.memory/MemoryCache.|(com.apollographql.cache.normalized.api.NormalizedCache?;kotlin.Int;kotlin.Long){}[0] + + final val size // com.apollographql.cache.normalized.memory/MemoryCache.size|{}size[0] + final fun (): kotlin/Int // com.apollographql.cache.normalized.memory/MemoryCache.size.|(){}[0] + final fun clearAll() // com.apollographql.cache.normalized.memory/MemoryCache.clearAll|clearAll(){}[0] final fun dump(): kotlin.collections/Map, kotlin.collections/Map> // com.apollographql.cache.normalized.memory/MemoryCache.dump|dump(){}[0] final fun loadRecord(kotlin/String, com.apollographql.cache.normalized.api/CacheHeaders): com.apollographql.cache.normalized.api/Record? // com.apollographql.cache.normalized.memory/MemoryCache.loadRecord|loadRecord(kotlin.String;com.apollographql.cache.normalized.api.CacheHeaders){}[0] @@ -284,29 +392,16 @@ final class com.apollographql.cache.normalized.memory/MemoryCache : com.apollogr final fun remove(com.apollographql.cache.normalized.api/CacheKey, kotlin/Boolean): kotlin/Boolean // com.apollographql.cache.normalized.memory/MemoryCache.remove|remove(com.apollographql.cache.normalized.api.CacheKey;kotlin.Boolean){}[0] final fun remove(kotlin.collections/Collection, kotlin/Boolean): kotlin/Int // com.apollographql.cache.normalized.memory/MemoryCache.remove|remove(kotlin.collections.Collection;kotlin.Boolean){}[0] final fun remove(kotlin/String): kotlin/Int // com.apollographql.cache.normalized.memory/MemoryCache.remove|remove(kotlin.String){}[0] - final val size // com.apollographql.cache.normalized.memory/MemoryCache.size|{}size[0] - final fun (): kotlin/Int // com.apollographql.cache.normalized.memory/MemoryCache.size.|(){}[0] } + final class com.apollographql.cache.normalized.memory/MemoryCacheFactory : com.apollographql.cache.normalized.api/NormalizedCacheFactory { // com.apollographql.cache.normalized.memory/MemoryCacheFactory|null[0] constructor (kotlin/Int = ..., kotlin/Long = ...) // com.apollographql.cache.normalized.memory/MemoryCacheFactory.|(kotlin.Int;kotlin.Long){}[0] + final fun chain(com.apollographql.cache.normalized.api/NormalizedCacheFactory): com.apollographql.cache.normalized.memory/MemoryCacheFactory // com.apollographql.cache.normalized.memory/MemoryCacheFactory.chain|chain(com.apollographql.cache.normalized.api.NormalizedCacheFactory){}[0] final fun create(): com.apollographql.cache.normalized.memory/MemoryCache // com.apollographql.cache.normalized.memory/MemoryCacheFactory.create|create(){}[0] } + final class com.apollographql.cache.normalized/CacheInfo : com.apollographql.apollo.api/ExecutionContext.Element { // com.apollographql.cache.normalized/CacheInfo|null[0] - final class Builder { // com.apollographql.cache.normalized/CacheInfo.Builder|null[0] - constructor () // com.apollographql.cache.normalized/CacheInfo.Builder.|(){}[0] - final fun build(): com.apollographql.cache.normalized/CacheInfo // com.apollographql.cache.normalized/CacheInfo.Builder.build|build(){}[0] - final fun cacheEndMillis(kotlin/Long): com.apollographql.cache.normalized/CacheInfo.Builder // com.apollographql.cache.normalized/CacheInfo.Builder.cacheEndMillis|cacheEndMillis(kotlin.Long){}[0] - final fun cacheHit(kotlin/Boolean): com.apollographql.cache.normalized/CacheInfo.Builder // com.apollographql.cache.normalized/CacheInfo.Builder.cacheHit|cacheHit(kotlin.Boolean){}[0] - final fun cacheMissException(com.apollographql.apollo.exception/CacheMissException?): com.apollographql.cache.normalized/CacheInfo.Builder // com.apollographql.cache.normalized/CacheInfo.Builder.cacheMissException|cacheMissException(com.apollographql.apollo.exception.CacheMissException?){}[0] - final fun cacheStartMillis(kotlin/Long): com.apollographql.cache.normalized/CacheInfo.Builder // com.apollographql.cache.normalized/CacheInfo.Builder.cacheStartMillis|cacheStartMillis(kotlin.Long){}[0] - final fun networkEndMillis(kotlin/Long): com.apollographql.cache.normalized/CacheInfo.Builder // com.apollographql.cache.normalized/CacheInfo.Builder.networkEndMillis|networkEndMillis(kotlin.Long){}[0] - final fun networkException(com.apollographql.apollo.exception/ApolloException?): com.apollographql.cache.normalized/CacheInfo.Builder // com.apollographql.cache.normalized/CacheInfo.Builder.networkException|networkException(com.apollographql.apollo.exception.ApolloException?){}[0] - final fun networkStartMillis(kotlin/Long): com.apollographql.cache.normalized/CacheInfo.Builder // com.apollographql.cache.normalized/CacheInfo.Builder.networkStartMillis|networkStartMillis(kotlin.Long){}[0] - final fun stale(kotlin/Boolean): com.apollographql.cache.normalized/CacheInfo.Builder // com.apollographql.cache.normalized/CacheInfo.Builder.stale|stale(kotlin.Boolean){}[0] - } - final fun newBuilder(): com.apollographql.cache.normalized/CacheInfo.Builder // com.apollographql.cache.normalized/CacheInfo.newBuilder|newBuilder(){}[0] - final object Key : com.apollographql.apollo.api/ExecutionContext.Key // com.apollographql.cache.normalized/CacheInfo.Key|null[0] final val cacheEndMillis // com.apollographql.cache.normalized/CacheInfo.cacheEndMillis|{}cacheEndMillis[0] final fun (): kotlin/Long // com.apollographql.cache.normalized/CacheInfo.cacheEndMillis.|(){}[0] final val cacheMissException // com.apollographql.cache.normalized/CacheInfo.cacheMissException|{}cacheMissException[0] @@ -315,6 +410,8 @@ final class com.apollographql.cache.normalized/CacheInfo : com.apollographql.apo final fun (): kotlin/Long // com.apollographql.cache.normalized/CacheInfo.cacheStartMillis.|(){}[0] final val isCacheHit // com.apollographql.cache.normalized/CacheInfo.isCacheHit|{}isCacheHit[0] final fun (): kotlin/Boolean // com.apollographql.cache.normalized/CacheInfo.isCacheHit.|(){}[0] + final val isFromCache // com.apollographql.cache.normalized/CacheInfo.isFromCache|{}isFromCache[0] + final fun (): kotlin/Boolean // com.apollographql.cache.normalized/CacheInfo.isFromCache.|(){}[0] final val isStale // com.apollographql.cache.normalized/CacheInfo.isStale|{}isStale[0] final fun (): kotlin/Boolean // com.apollographql.cache.normalized/CacheInfo.isStale.|(){}[0] final val key // com.apollographql.cache.normalized/CacheInfo.key|{}key[0] @@ -325,13 +422,36 @@ final class com.apollographql.cache.normalized/CacheInfo : com.apollographql.apo final fun (): com.apollographql.apollo.exception/ApolloException? // com.apollographql.cache.normalized/CacheInfo.networkException.|(){}[0] final val networkStartMillis // com.apollographql.cache.normalized/CacheInfo.networkStartMillis|{}networkStartMillis[0] final fun (): kotlin/Long // com.apollographql.cache.normalized/CacheInfo.networkStartMillis.|(){}[0] + + final fun newBuilder(): com.apollographql.cache.normalized/CacheInfo.Builder // com.apollographql.cache.normalized/CacheInfo.newBuilder|newBuilder(){}[0] + + final class Builder { // com.apollographql.cache.normalized/CacheInfo.Builder|null[0] + constructor () // com.apollographql.cache.normalized/CacheInfo.Builder.|(){}[0] + + final fun build(): com.apollographql.cache.normalized/CacheInfo // com.apollographql.cache.normalized/CacheInfo.Builder.build|build(){}[0] + final fun cacheEndMillis(kotlin/Long): com.apollographql.cache.normalized/CacheInfo.Builder // com.apollographql.cache.normalized/CacheInfo.Builder.cacheEndMillis|cacheEndMillis(kotlin.Long){}[0] + final fun cacheHit(kotlin/Boolean): com.apollographql.cache.normalized/CacheInfo.Builder // com.apollographql.cache.normalized/CacheInfo.Builder.cacheHit|cacheHit(kotlin.Boolean){}[0] + final fun cacheMissException(com.apollographql.apollo.exception/CacheMissException?): com.apollographql.cache.normalized/CacheInfo.Builder // com.apollographql.cache.normalized/CacheInfo.Builder.cacheMissException|cacheMissException(com.apollographql.apollo.exception.CacheMissException?){}[0] + final fun cacheStartMillis(kotlin/Long): com.apollographql.cache.normalized/CacheInfo.Builder // com.apollographql.cache.normalized/CacheInfo.Builder.cacheStartMillis|cacheStartMillis(kotlin.Long){}[0] + final fun fromCache(kotlin/Boolean): com.apollographql.cache.normalized/CacheInfo.Builder // com.apollographql.cache.normalized/CacheInfo.Builder.fromCache|fromCache(kotlin.Boolean){}[0] + final fun networkEndMillis(kotlin/Long): com.apollographql.cache.normalized/CacheInfo.Builder // com.apollographql.cache.normalized/CacheInfo.Builder.networkEndMillis|networkEndMillis(kotlin.Long){}[0] + final fun networkException(com.apollographql.apollo.exception/ApolloException?): com.apollographql.cache.normalized/CacheInfo.Builder // com.apollographql.cache.normalized/CacheInfo.Builder.networkException|networkException(com.apollographql.apollo.exception.ApolloException?){}[0] + final fun networkStartMillis(kotlin/Long): com.apollographql.cache.normalized/CacheInfo.Builder // com.apollographql.cache.normalized/CacheInfo.Builder.networkStartMillis|networkStartMillis(kotlin.Long){}[0] + final fun stale(kotlin/Boolean): com.apollographql.cache.normalized/CacheInfo.Builder // com.apollographql.cache.normalized/CacheInfo.Builder.stale|stale(kotlin.Boolean){}[0] + } + + final object Key : com.apollographql.apollo.api/ExecutionContext.Key // com.apollographql.cache.normalized/CacheInfo.Key|null[0] } + final class com.apollographql.cache.normalized/CacheMissLoggingInterceptor : com.apollographql.apollo.interceptor/ApolloInterceptor { // com.apollographql.cache.normalized/CacheMissLoggingInterceptor|null[0] constructor (kotlin/Function1) // com.apollographql.cache.normalized/CacheMissLoggingInterceptor.|(kotlin.Function1){}[0] + final fun <#A1: com.apollographql.apollo.api/Operation.Data> intercept(com.apollographql.apollo.api/ApolloRequest<#A1>, com.apollographql.apollo.interceptor/ApolloInterceptorChain): kotlinx.coroutines.flow/Flow> // com.apollographql.cache.normalized/CacheMissLoggingInterceptor.intercept|intercept(com.apollographql.apollo.api.ApolloRequest<0:0>;com.apollographql.apollo.interceptor.ApolloInterceptorChain){0§}[0] } + final class com.apollographql.cache.normalized/GarbageCollectResult { // com.apollographql.cache.normalized/GarbageCollectResult|null[0] constructor (com.apollographql.cache.normalized/RemovedFieldsAndRecords, com.apollographql.cache.normalized/RemovedFieldsAndRecords, kotlin.collections/Set) // com.apollographql.cache.normalized/GarbageCollectResult.|(com.apollographql.cache.normalized.RemovedFieldsAndRecords;com.apollographql.cache.normalized.RemovedFieldsAndRecords;kotlin.collections.Set){}[0] + final val removedDanglingReferences // com.apollographql.cache.normalized/GarbageCollectResult.removedDanglingReferences|{}removedDanglingReferences[0] final fun (): com.apollographql.cache.normalized/RemovedFieldsAndRecords // com.apollographql.cache.normalized/GarbageCollectResult.removedDanglingReferences.|(){}[0] final val removedStaleFields // com.apollographql.cache.normalized/GarbageCollectResult.removedStaleFields|{}removedStaleFields[0] @@ -339,66 +459,16 @@ final class com.apollographql.cache.normalized/GarbageCollectResult { // com.apo final val removedUnreachableRecords // com.apollographql.cache.normalized/GarbageCollectResult.removedUnreachableRecords|{}removedUnreachableRecords[0] final fun (): kotlin.collections/Set // com.apollographql.cache.normalized/GarbageCollectResult.removedUnreachableRecords.|(){}[0] } + final class com.apollographql.cache.normalized/RemovedFieldsAndRecords { // com.apollographql.cache.normalized/RemovedFieldsAndRecords|null[0] constructor (kotlin.collections/Set, kotlin.collections/Set) // com.apollographql.cache.normalized/RemovedFieldsAndRecords.|(kotlin.collections.Set;kotlin.collections.Set){}[0] + final val removedFields // com.apollographql.cache.normalized/RemovedFieldsAndRecords.removedFields|{}removedFields[0] final fun (): kotlin.collections/Set // com.apollographql.cache.normalized/RemovedFieldsAndRecords.removedFields.|(){}[0] final val removedRecords // com.apollographql.cache.normalized/RemovedFieldsAndRecords.removedRecords|{}removedRecords[0] final fun (): kotlin.collections/Set // com.apollographql.cache.normalized/RemovedFieldsAndRecords.removedRecords.|(){}[0] } -final const val com.apollographql.cache.normalized/VERSION // com.apollographql.cache.normalized/VERSION|{}VERSION[0] - final fun (): kotlin/String // com.apollographql.cache.normalized/VERSION.|(){}[0] -final enum class com.apollographql.cache.normalized/FetchPolicy : kotlin/Enum { // com.apollographql.cache.normalized/FetchPolicy|null[0] - enum entry CacheAndNetwork // com.apollographql.cache.normalized/FetchPolicy.CacheAndNetwork|null[0] - enum entry CacheFirst // com.apollographql.cache.normalized/FetchPolicy.CacheFirst|null[0] - enum entry CacheOnly // com.apollographql.cache.normalized/FetchPolicy.CacheOnly|null[0] - enum entry NetworkFirst // com.apollographql.cache.normalized/FetchPolicy.NetworkFirst|null[0] - enum entry NetworkOnly // com.apollographql.cache.normalized/FetchPolicy.NetworkOnly|null[0] - final fun valueOf(kotlin/String): com.apollographql.cache.normalized/FetchPolicy // com.apollographql.cache.normalized/FetchPolicy.valueOf|valueOf#static(kotlin.String){}[0] - final fun values(): kotlin/Array // com.apollographql.cache.normalized/FetchPolicy.values|values#static(){}[0] - final val entries // com.apollographql.cache.normalized/FetchPolicy.entries|#static{}entries[0] - final fun (): kotlin.enums/EnumEntries // com.apollographql.cache.normalized/FetchPolicy.entries.|#static(){}[0] -} -final fun (com.apollographql.apollo/ApolloClient.Builder).com.apollographql.cache.normalized/logCacheMisses(kotlin/Function1 = ...): com.apollographql.apollo/ApolloClient.Builder // com.apollographql.cache.normalized/logCacheMisses|logCacheMisses@com.apollographql.apollo.ApolloClient.Builder(kotlin.Function1){}[0] -final fun (com.apollographql.apollo/ApolloClient.Builder).com.apollographql.cache.normalized/normalizedCache(com.apollographql.cache.normalized.api/NormalizedCacheFactory, com.apollographql.cache.normalized.api/CacheKeyGenerator = ..., com.apollographql.cache.normalized.api/MetadataGenerator = ..., com.apollographql.cache.normalized.api/CacheResolver = ..., com.apollographql.cache.normalized.api/RecordMerger = ..., com.apollographql.cache.normalized.api/FieldKeyGenerator = ..., com.apollographql.cache.normalized.api/EmbeddedFieldsProvider = ..., kotlin/Boolean = ...): com.apollographql.apollo/ApolloClient.Builder // com.apollographql.cache.normalized/normalizedCache|normalizedCache@com.apollographql.apollo.ApolloClient.Builder(com.apollographql.cache.normalized.api.NormalizedCacheFactory;com.apollographql.cache.normalized.api.CacheKeyGenerator;com.apollographql.cache.normalized.api.MetadataGenerator;com.apollographql.cache.normalized.api.CacheResolver;com.apollographql.cache.normalized.api.RecordMerger;com.apollographql.cache.normalized.api.FieldKeyGenerator;com.apollographql.cache.normalized.api.EmbeddedFieldsProvider;kotlin.Boolean){}[0] -final fun (com.apollographql.apollo/ApolloClient.Builder).com.apollographql.cache.normalized/store(com.apollographql.cache.normalized/ApolloStore, kotlin/Boolean = ...): com.apollographql.apollo/ApolloClient.Builder // com.apollographql.cache.normalized/store|store@com.apollographql.apollo.ApolloClient.Builder(com.apollographql.cache.normalized.ApolloStore;kotlin.Boolean){}[0] -final fun (com.apollographql.cache.normalized.api/NormalizedCache).com.apollographql.cache.normalized/allRecords(): kotlin.collections/Map // com.apollographql.cache.normalized/allRecords|allRecords@com.apollographql.cache.normalized.api.NormalizedCache(){}[0] -final fun (com.apollographql.cache.normalized.api/NormalizedCache).com.apollographql.cache.normalized/garbageCollect(com.apollographql.cache.normalized.api/MaxAgeProvider, kotlin.time/Duration = ...): com.apollographql.cache.normalized/GarbageCollectResult // com.apollographql.cache.normalized/garbageCollect|garbageCollect@com.apollographql.cache.normalized.api.NormalizedCache(com.apollographql.cache.normalized.api.MaxAgeProvider;kotlin.time.Duration){}[0] -final fun (com.apollographql.cache.normalized.api/NormalizedCache).com.apollographql.cache.normalized/removeDanglingReferences(): com.apollographql.cache.normalized/RemovedFieldsAndRecords // com.apollographql.cache.normalized/removeDanglingReferences|removeDanglingReferences@com.apollographql.cache.normalized.api.NormalizedCache(){}[0] -final fun (com.apollographql.cache.normalized.api/NormalizedCache).com.apollographql.cache.normalized/removeStaleFields(com.apollographql.cache.normalized.api/MaxAgeProvider, kotlin.time/Duration = ...): com.apollographql.cache.normalized/RemovedFieldsAndRecords // com.apollographql.cache.normalized/removeStaleFields|removeStaleFields@com.apollographql.cache.normalized.api.NormalizedCache(com.apollographql.cache.normalized.api.MaxAgeProvider;kotlin.time.Duration){}[0] -final fun (com.apollographql.cache.normalized.api/NormalizedCache).com.apollographql.cache.normalized/removeUnreachableRecords(): kotlin.collections/Set // com.apollographql.cache.normalized/removeUnreachableRecords|removeUnreachableRecords@com.apollographql.cache.normalized.api.NormalizedCache(){}[0] -final fun (com.apollographql.cache.normalized.api/Record).com.apollographql.cache.normalized.api/expirationDate(kotlin/String): kotlin/Long? // com.apollographql.cache.normalized.api/expirationDate|expirationDate@com.apollographql.cache.normalized.api.Record(kotlin.String){}[0] -final fun (com.apollographql.cache.normalized.api/Record).com.apollographql.cache.normalized.api/receivedDate(kotlin/String): kotlin/Long? // com.apollographql.cache.normalized.api/receivedDate|receivedDate@com.apollographql.cache.normalized.api.Record(kotlin.String){}[0] -final fun (com.apollographql.cache.normalized.api/Record).com.apollographql.cache.normalized.api/withDates(kotlin/String?, kotlin/String?): com.apollographql.cache.normalized.api/Record // com.apollographql.cache.normalized.api/withDates|withDates@com.apollographql.cache.normalized.api.Record(kotlin.String?;kotlin.String?){}[0] -final fun (com.apollographql.cache.normalized/ApolloStore).com.apollographql.cache.normalized/garbageCollect(com.apollographql.cache.normalized.api/MaxAgeProvider, kotlin.time/Duration = ...): com.apollographql.cache.normalized/GarbageCollectResult // com.apollographql.cache.normalized/garbageCollect|garbageCollect@com.apollographql.cache.normalized.ApolloStore(com.apollographql.cache.normalized.api.MaxAgeProvider;kotlin.time.Duration){}[0] -final fun (com.apollographql.cache.normalized/ApolloStore).com.apollographql.cache.normalized/removeDanglingReferences(): com.apollographql.cache.normalized/RemovedFieldsAndRecords // com.apollographql.cache.normalized/removeDanglingReferences|removeDanglingReferences@com.apollographql.cache.normalized.ApolloStore(){}[0] -final fun (com.apollographql.cache.normalized/ApolloStore).com.apollographql.cache.normalized/removeStaleFields(com.apollographql.cache.normalized.api/MaxAgeProvider, kotlin.time/Duration = ...): com.apollographql.cache.normalized/RemovedFieldsAndRecords // com.apollographql.cache.normalized/removeStaleFields|removeStaleFields@com.apollographql.cache.normalized.ApolloStore(com.apollographql.cache.normalized.api.MaxAgeProvider;kotlin.time.Duration){}[0] -final fun (com.apollographql.cache.normalized/ApolloStore).com.apollographql.cache.normalized/removeUnreachableRecords(): kotlin.collections/Set // com.apollographql.cache.normalized/removeUnreachableRecords|removeUnreachableRecords@com.apollographql.cache.normalized.ApolloStore(){}[0] -final fun (kotlin.collections/Collection?).com.apollographql.cache.normalized.api/dependentKeys(): kotlin.collections/Set // com.apollographql.cache.normalized.api/dependentKeys|dependentKeys@kotlin.collections.Collection?(){}[0] -final fun (kotlin.collections/Map).com.apollographql.cache.normalized/getReachableCacheKeys(): kotlin.collections/Set // com.apollographql.cache.normalized/getReachableCacheKeys|getReachableCacheKeys@kotlin.collections.Map(){}[0] -final fun <#A: com.apollographql.apollo.api/Executable.Data> (com.apollographql.apollo.api/Executable<#A>).com.apollographql.cache.normalized.api/normalize(#A, com.apollographql.apollo.api/CustomScalarAdapters, com.apollographql.cache.normalized.api/CacheKeyGenerator, com.apollographql.cache.normalized.api/MetadataGenerator = ..., com.apollographql.cache.normalized.api/FieldKeyGenerator = ..., com.apollographql.cache.normalized.api/EmbeddedFieldsProvider = ..., kotlin/String): kotlin.collections/Map // com.apollographql.cache.normalized.api/normalize|normalize@com.apollographql.apollo.api.Executable<0:0>(0:0;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheKeyGenerator;com.apollographql.cache.normalized.api.MetadataGenerator;com.apollographql.cache.normalized.api.FieldKeyGenerator;com.apollographql.cache.normalized.api.EmbeddedFieldsProvider;kotlin.String){0§}[0] -final fun <#A: com.apollographql.apollo.api/Executable.Data> (com.apollographql.apollo.api/Executable<#A>).com.apollographql.cache.normalized.api/readDataFromCache(com.apollographql.apollo.api/CustomScalarAdapters, com.apollographql.cache.normalized.api/ReadOnlyNormalizedCache, com.apollographql.cache.normalized.api/CacheResolver, com.apollographql.cache.normalized.api/CacheHeaders, com.apollographql.cache.normalized.api/FieldKeyGenerator = ...): #A // com.apollographql.cache.normalized.api/readDataFromCache|readDataFromCache@com.apollographql.apollo.api.Executable<0:0>(com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.ReadOnlyNormalizedCache;com.apollographql.cache.normalized.api.CacheResolver;com.apollographql.cache.normalized.api.CacheHeaders;com.apollographql.cache.normalized.api.FieldKeyGenerator){0§}[0] -final fun <#A: com.apollographql.apollo.api/Executable.Data> (com.apollographql.apollo.api/Executable<#A>).com.apollographql.cache.normalized.api/readDataFromCache(com.apollographql.cache.normalized.api/CacheKey, com.apollographql.apollo.api/CustomScalarAdapters, com.apollographql.cache.normalized.api/ReadOnlyNormalizedCache, com.apollographql.cache.normalized.api/CacheResolver, com.apollographql.cache.normalized.api/CacheHeaders, com.apollographql.cache.normalized.api/FieldKeyGenerator = ...): #A // com.apollographql.cache.normalized.api/readDataFromCache|readDataFromCache@com.apollographql.apollo.api.Executable<0:0>(com.apollographql.cache.normalized.api.CacheKey;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.ReadOnlyNormalizedCache;com.apollographql.cache.normalized.api.CacheResolver;com.apollographql.cache.normalized.api.CacheHeaders;com.apollographql.cache.normalized.api.FieldKeyGenerator){0§}[0] -final fun <#A: com.apollographql.apollo.api/Mutation.Data> (com.apollographql.apollo.api/ApolloRequest.Builder<#A>).com.apollographql.cache.normalized/optimisticUpdates(#A): com.apollographql.apollo.api/ApolloRequest.Builder<#A> // com.apollographql.cache.normalized/optimisticUpdates|optimisticUpdates@com.apollographql.apollo.api.ApolloRequest.Builder<0:0>(0:0){0§}[0] -final fun <#A: com.apollographql.apollo.api/Mutation.Data> (com.apollographql.apollo/ApolloCall<#A>).com.apollographql.cache.normalized/optimisticUpdates(#A): com.apollographql.apollo/ApolloCall<#A> // com.apollographql.cache.normalized/optimisticUpdates|optimisticUpdates@com.apollographql.apollo.ApolloCall<0:0>(0:0){0§}[0] -final fun <#A: com.apollographql.apollo.api/Operation.Data> (com.apollographql.apollo.api/ApolloResponse.Builder<#A>).com.apollographql.cache.normalized/cacheHeaders(com.apollographql.cache.normalized.api/CacheHeaders): com.apollographql.apollo.api/ApolloResponse.Builder<#A> // com.apollographql.cache.normalized/cacheHeaders|cacheHeaders@com.apollographql.apollo.api.ApolloResponse.Builder<0:0>(com.apollographql.cache.normalized.api.CacheHeaders){0§}[0] -final fun <#A: com.apollographql.apollo.api/Operation.Data> (com.apollographql.apollo.api/Operation<#A>).com.apollographql.cache.normalized.api/normalize(#A, com.apollographql.apollo.api/CustomScalarAdapters, com.apollographql.cache.normalized.api/CacheKeyGenerator, com.apollographql.cache.normalized.api/MetadataGenerator = ..., com.apollographql.cache.normalized.api/FieldKeyGenerator = ..., com.apollographql.cache.normalized.api/EmbeddedFieldsProvider = ...): kotlin.collections/Map // com.apollographql.cache.normalized.api/normalize|normalize@com.apollographql.apollo.api.Operation<0:0>(0:0;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheKeyGenerator;com.apollographql.cache.normalized.api.MetadataGenerator;com.apollographql.cache.normalized.api.FieldKeyGenerator;com.apollographql.cache.normalized.api.EmbeddedFieldsProvider){0§}[0] -final fun <#A: com.apollographql.apollo.api/Query.Data> (com.apollographql.apollo/ApolloCall<#A>).com.apollographql.cache.normalized/watch(#A?): kotlinx.coroutines.flow/Flow> // com.apollographql.cache.normalized/watch|watch@com.apollographql.apollo.ApolloCall<0:0>(0:0?){0§}[0] -final fun <#A: com.apollographql.apollo.api/Query.Data> (com.apollographql.apollo/ApolloCall<#A>).com.apollographql.cache.normalized/watch(): kotlinx.coroutines.flow/Flow> // com.apollographql.cache.normalized/watch|watch@com.apollographql.apollo.ApolloCall<0:0>(){0§}[0] -final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/addCacheHeader(kotlin/String, kotlin/String): #A // com.apollographql.cache.normalized/addCacheHeader|addCacheHeader@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.String;kotlin.String){0§}[0] -final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/cacheHeaders(com.apollographql.cache.normalized.api/CacheHeaders): #A // com.apollographql.cache.normalized/cacheHeaders|cacheHeaders@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(com.apollographql.cache.normalized.api.CacheHeaders){0§}[0] -final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/doNotStore(kotlin/Boolean): #A // com.apollographql.cache.normalized/doNotStore|doNotStore@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] -final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/fetchPolicy(com.apollographql.cache.normalized/FetchPolicy): #A // com.apollographql.cache.normalized/fetchPolicy|fetchPolicy@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(com.apollographql.cache.normalized.FetchPolicy){0§}[0] -final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/fetchPolicyInterceptor(com.apollographql.apollo.interceptor/ApolloInterceptor): #A // com.apollographql.cache.normalized/fetchPolicyInterceptor|fetchPolicyInterceptor@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(com.apollographql.apollo.interceptor.ApolloInterceptor){0§}[0] -final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/maxStale(kotlin.time/Duration): #A // com.apollographql.cache.normalized/maxStale|maxStale@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.time.Duration){0§}[0] -final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/memoryCacheOnly(kotlin/Boolean): #A // com.apollographql.cache.normalized/memoryCacheOnly|memoryCacheOnly@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] -final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/refetchPolicy(com.apollographql.cache.normalized/FetchPolicy): #A // com.apollographql.cache.normalized/refetchPolicy|refetchPolicy@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(com.apollographql.cache.normalized.FetchPolicy){0§}[0] -final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/refetchPolicyInterceptor(com.apollographql.apollo.interceptor/ApolloInterceptor): #A // com.apollographql.cache.normalized/refetchPolicyInterceptor|refetchPolicyInterceptor@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(com.apollographql.apollo.interceptor.ApolloInterceptor){0§}[0] -final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/storeExpirationDate(kotlin/Boolean): #A // com.apollographql.cache.normalized/storeExpirationDate|storeExpirationDate@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] -final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/storePartialResponses(kotlin/Boolean): #A // com.apollographql.cache.normalized/storePartialResponses|storePartialResponses@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] -final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/storeReceiveDate(kotlin/Boolean): #A // com.apollographql.cache.normalized/storeReceiveDate|storeReceiveDate@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] -final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/writeToCacheAsynchronously(kotlin/Boolean): #A // com.apollographql.cache.normalized/writeToCacheAsynchronously|writeToCacheAsynchronously@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] -final fun com.apollographql.cache.normalized/ApolloStore(com.apollographql.cache.normalized.api/NormalizedCacheFactory, com.apollographql.cache.normalized.api/CacheKeyGenerator = ..., com.apollographql.cache.normalized.api/MetadataGenerator = ..., com.apollographql.cache.normalized.api/CacheResolver = ..., com.apollographql.cache.normalized.api/RecordMerger = ..., com.apollographql.cache.normalized.api/FieldKeyGenerator = ..., com.apollographql.cache.normalized.api/EmbeddedFieldsProvider = ...): com.apollographql.cache.normalized/ApolloStore // com.apollographql.cache.normalized/ApolloStore|ApolloStore(com.apollographql.cache.normalized.api.NormalizedCacheFactory;com.apollographql.cache.normalized.api.CacheKeyGenerator;com.apollographql.cache.normalized.api.MetadataGenerator;com.apollographql.cache.normalized.api.CacheResolver;com.apollographql.cache.normalized.api.RecordMerger;com.apollographql.cache.normalized.api.FieldKeyGenerator;com.apollographql.cache.normalized.api.EmbeddedFieldsProvider){}[0] + final object com.apollographql.cache.normalized.api/ApolloCacheHeaders { // com.apollographql.cache.normalized.api/ApolloCacheHeaders|null[0] final const val DO_NOT_STORE // com.apollographql.cache.normalized.api/ApolloCacheHeaders.DO_NOT_STORE|{}DO_NOT_STORE[0] final fun (): kotlin/String // com.apollographql.cache.normalized.api/ApolloCacheHeaders.DO_NOT_STORE.|(){}[0] @@ -415,27 +485,38 @@ final object com.apollographql.cache.normalized.api/ApolloCacheHeaders { // com. final const val STALE // com.apollographql.cache.normalized.api/ApolloCacheHeaders.STALE|{}STALE[0] final fun (): kotlin/String // com.apollographql.cache.normalized.api/ApolloCacheHeaders.STALE.|(){}[0] } + final object com.apollographql.cache.normalized.api/DefaultCacheResolver : com.apollographql.cache.normalized.api/CacheResolver { // com.apollographql.cache.normalized.api/DefaultCacheResolver|null[0] final fun resolveField(com.apollographql.cache.normalized.api/ResolverContext): kotlin/Any? // com.apollographql.cache.normalized.api/DefaultCacheResolver.resolveField|resolveField(com.apollographql.cache.normalized.api.ResolverContext){}[0] } + final object com.apollographql.cache.normalized.api/DefaultEmbeddedFieldsProvider : com.apollographql.cache.normalized.api/EmbeddedFieldsProvider { // com.apollographql.cache.normalized.api/DefaultEmbeddedFieldsProvider|null[0] final fun getEmbeddedFields(com.apollographql.cache.normalized.api/EmbeddedFieldsContext): kotlin.collections/List // com.apollographql.cache.normalized.api/DefaultEmbeddedFieldsProvider.getEmbeddedFields|getEmbeddedFields(com.apollographql.cache.normalized.api.EmbeddedFieldsContext){}[0] } + final object com.apollographql.cache.normalized.api/DefaultFieldKeyGenerator : com.apollographql.cache.normalized.api/FieldKeyGenerator { // com.apollographql.cache.normalized.api/DefaultFieldKeyGenerator|null[0] final fun getFieldKey(com.apollographql.cache.normalized.api/FieldKeyContext): kotlin/String // com.apollographql.cache.normalized.api/DefaultFieldKeyGenerator.getFieldKey|getFieldKey(com.apollographql.cache.normalized.api.FieldKeyContext){}[0] } + final object com.apollographql.cache.normalized.api/DefaultRecordMerger : com.apollographql.cache.normalized.api/RecordMerger { // com.apollographql.cache.normalized.api/DefaultRecordMerger|null[0] final fun merge(com.apollographql.cache.normalized.api/Record, com.apollographql.cache.normalized.api/Record): kotlin/Pair> // com.apollographql.cache.normalized.api/DefaultRecordMerger.merge|merge(com.apollographql.cache.normalized.api.Record;com.apollographql.cache.normalized.api.Record){}[0] } + final object com.apollographql.cache.normalized.api/EmptyMetadataGenerator : com.apollographql.cache.normalized.api/MetadataGenerator { // com.apollographql.cache.normalized.api/EmptyMetadataGenerator|null[0] final fun metadataForObject(kotlin/Any?, com.apollographql.cache.normalized.api/MetadataGeneratorContext): kotlin.collections/Map // com.apollographql.cache.normalized.api/EmptyMetadataGenerator.metadataForObject|metadataForObject(kotlin.Any?;com.apollographql.cache.normalized.api.MetadataGeneratorContext){}[0] } + final object com.apollographql.cache.normalized.api/FieldPolicyCacheResolver : com.apollographql.cache.normalized.api/CacheResolver { // com.apollographql.cache.normalized.api/FieldPolicyCacheResolver|null[0] final fun resolveField(com.apollographql.cache.normalized.api/ResolverContext): kotlin/Any? // com.apollographql.cache.normalized.api/FieldPolicyCacheResolver.resolveField|resolveField(com.apollographql.cache.normalized.api.ResolverContext){}[0] } + final object com.apollographql.cache.normalized.api/TypePolicyCacheKeyGenerator : com.apollographql.cache.normalized.api/CacheKeyGenerator { // com.apollographql.cache.normalized.api/TypePolicyCacheKeyGenerator|null[0] final fun cacheKeyForObject(kotlin.collections/Map, com.apollographql.cache.normalized.api/CacheKeyGeneratorContext): com.apollographql.cache.normalized.api/CacheKey? // com.apollographql.cache.normalized.api/TypePolicyCacheKeyGenerator.cacheKeyForObject|cacheKeyForObject(kotlin.collections.Map;com.apollographql.cache.normalized.api.CacheKeyGeneratorContext){}[0] } + +final const val com.apollographql.cache.normalized/VERSION // com.apollographql.cache.normalized/VERSION|{}VERSION[0] + final fun (): kotlin/String // com.apollographql.cache.normalized/VERSION.|(){}[0] + final val com.apollographql.cache.normalized.api/ConnectionRecordMerger // com.apollographql.cache.normalized.api/ConnectionRecordMerger|{}ConnectionRecordMerger[0] final fun (): com.apollographql.cache.normalized.api/FieldRecordMerger // com.apollographql.cache.normalized.api/ConnectionRecordMerger.|(){}[0] final val com.apollographql.cache.normalized/CacheAndNetworkInterceptor // com.apollographql.cache.normalized/CacheAndNetworkInterceptor|{}CacheAndNetworkInterceptor[0] @@ -456,15 +537,45 @@ final val com.apollographql.cache.normalized/cacheInfo // com.apollographql.cach final fun <#A1: com.apollographql.apollo.api/Operation.Data> (com.apollographql.apollo.api/ApolloResponse<#A1>).(): com.apollographql.cache.normalized/CacheInfo? // com.apollographql.cache.normalized/cacheInfo.|@com.apollographql.apollo.api.ApolloResponse<0:0>(){0§}[0] final val com.apollographql.cache.normalized/isFromCache // com.apollographql.cache.normalized/isFromCache|@com.apollographql.apollo.api.ApolloResponse<0:0>{0§}isFromCache[0] final fun <#A1: com.apollographql.apollo.api/Operation.Data> (com.apollographql.apollo.api/ApolloResponse<#A1>).(): kotlin/Boolean // com.apollographql.cache.normalized/isFromCache.|@com.apollographql.apollo.api.ApolloResponse<0:0>(){0§}[0] -sealed interface com.apollographql.cache.normalized.api/MaxAge { // com.apollographql.cache.normalized.api/MaxAge|null[0] - final class Duration : com.apollographql.cache.normalized.api/MaxAge { // com.apollographql.cache.normalized.api/MaxAge.Duration|null[0] - constructor (kotlin.time/Duration) // com.apollographql.cache.normalized.api/MaxAge.Duration.|(kotlin.time.Duration){}[0] - final val duration // com.apollographql.cache.normalized.api/MaxAge.Duration.duration|{}duration[0] - final fun (): kotlin.time/Duration // com.apollographql.cache.normalized.api/MaxAge.Duration.duration.|(){}[0] - } - final object Inherit : com.apollographql.cache.normalized.api/MaxAge { // com.apollographql.cache.normalized.api/MaxAge.Inherit|null[0] - final fun equals(kotlin/Any?): kotlin/Boolean // com.apollographql.cache.normalized.api/MaxAge.Inherit.equals|equals(kotlin.Any?){}[0] - final fun hashCode(): kotlin/Int // com.apollographql.cache.normalized.api/MaxAge.Inherit.hashCode|hashCode(){}[0] - final fun toString(): kotlin/String // com.apollographql.cache.normalized.api/MaxAge.Inherit.toString|toString(){}[0] - } -} + +final fun (com.apollographql.apollo/ApolloClient.Builder).com.apollographql.cache.normalized/logCacheMisses(kotlin/Function1 = ...): com.apollographql.apollo/ApolloClient.Builder // com.apollographql.cache.normalized/logCacheMisses|logCacheMisses@com.apollographql.apollo.ApolloClient.Builder(kotlin.Function1){}[0] +final fun (com.apollographql.apollo/ApolloClient.Builder).com.apollographql.cache.normalized/normalizedCache(com.apollographql.cache.normalized.api/NormalizedCacheFactory, com.apollographql.cache.normalized.api/CacheKeyGenerator = ..., com.apollographql.cache.normalized.api/MetadataGenerator = ..., com.apollographql.cache.normalized.api/CacheResolver = ..., com.apollographql.cache.normalized.api/RecordMerger = ..., com.apollographql.cache.normalized.api/FieldKeyGenerator = ..., com.apollographql.cache.normalized.api/EmbeddedFieldsProvider = ..., kotlin/Boolean = ...): com.apollographql.apollo/ApolloClient.Builder // com.apollographql.cache.normalized/normalizedCache|normalizedCache@com.apollographql.apollo.ApolloClient.Builder(com.apollographql.cache.normalized.api.NormalizedCacheFactory;com.apollographql.cache.normalized.api.CacheKeyGenerator;com.apollographql.cache.normalized.api.MetadataGenerator;com.apollographql.cache.normalized.api.CacheResolver;com.apollographql.cache.normalized.api.RecordMerger;com.apollographql.cache.normalized.api.FieldKeyGenerator;com.apollographql.cache.normalized.api.EmbeddedFieldsProvider;kotlin.Boolean){}[0] +final fun (com.apollographql.apollo/ApolloClient.Builder).com.apollographql.cache.normalized/store(com.apollographql.cache.normalized/ApolloStore, kotlin/Boolean = ...): com.apollographql.apollo/ApolloClient.Builder // com.apollographql.cache.normalized/store|store@com.apollographql.apollo.ApolloClient.Builder(com.apollographql.cache.normalized.ApolloStore;kotlin.Boolean){}[0] +final fun (com.apollographql.cache.normalized.api/NormalizedCache).com.apollographql.cache.normalized/allRecords(): kotlin.collections/Map // com.apollographql.cache.normalized/allRecords|allRecords@com.apollographql.cache.normalized.api.NormalizedCache(){}[0] +final fun (com.apollographql.cache.normalized.api/NormalizedCache).com.apollographql.cache.normalized/garbageCollect(com.apollographql.cache.normalized.api/MaxAgeProvider, kotlin.time/Duration = ...): com.apollographql.cache.normalized/GarbageCollectResult // com.apollographql.cache.normalized/garbageCollect|garbageCollect@com.apollographql.cache.normalized.api.NormalizedCache(com.apollographql.cache.normalized.api.MaxAgeProvider;kotlin.time.Duration){}[0] +final fun (com.apollographql.cache.normalized.api/NormalizedCache).com.apollographql.cache.normalized/removeDanglingReferences(): com.apollographql.cache.normalized/RemovedFieldsAndRecords // com.apollographql.cache.normalized/removeDanglingReferences|removeDanglingReferences@com.apollographql.cache.normalized.api.NormalizedCache(){}[0] +final fun (com.apollographql.cache.normalized.api/NormalizedCache).com.apollographql.cache.normalized/removeStaleFields(com.apollographql.cache.normalized.api/MaxAgeProvider, kotlin.time/Duration = ...): com.apollographql.cache.normalized/RemovedFieldsAndRecords // com.apollographql.cache.normalized/removeStaleFields|removeStaleFields@com.apollographql.cache.normalized.api.NormalizedCache(com.apollographql.cache.normalized.api.MaxAgeProvider;kotlin.time.Duration){}[0] +final fun (com.apollographql.cache.normalized.api/NormalizedCache).com.apollographql.cache.normalized/removeUnreachableRecords(): kotlin.collections/Set // com.apollographql.cache.normalized/removeUnreachableRecords|removeUnreachableRecords@com.apollographql.cache.normalized.api.NormalizedCache(){}[0] +final fun (com.apollographql.cache.normalized.api/Record).com.apollographql.cache.normalized.api/expirationDate(kotlin/String): kotlin/Long? // com.apollographql.cache.normalized.api/expirationDate|expirationDate@com.apollographql.cache.normalized.api.Record(kotlin.String){}[0] +final fun (com.apollographql.cache.normalized.api/Record).com.apollographql.cache.normalized.api/receivedDate(kotlin/String): kotlin/Long? // com.apollographql.cache.normalized.api/receivedDate|receivedDate@com.apollographql.cache.normalized.api.Record(kotlin.String){}[0] +final fun (com.apollographql.cache.normalized.api/Record).com.apollographql.cache.normalized.api/withDates(kotlin/String?, kotlin/String?): com.apollographql.cache.normalized.api/Record // com.apollographql.cache.normalized.api/withDates|withDates@com.apollographql.cache.normalized.api.Record(kotlin.String?;kotlin.String?){}[0] +final fun (com.apollographql.cache.normalized/ApolloStore).com.apollographql.cache.normalized/garbageCollect(com.apollographql.cache.normalized.api/MaxAgeProvider, kotlin.time/Duration = ...): com.apollographql.cache.normalized/GarbageCollectResult // com.apollographql.cache.normalized/garbageCollect|garbageCollect@com.apollographql.cache.normalized.ApolloStore(com.apollographql.cache.normalized.api.MaxAgeProvider;kotlin.time.Duration){}[0] +final fun (com.apollographql.cache.normalized/ApolloStore).com.apollographql.cache.normalized/removeDanglingReferences(): com.apollographql.cache.normalized/RemovedFieldsAndRecords // com.apollographql.cache.normalized/removeDanglingReferences|removeDanglingReferences@com.apollographql.cache.normalized.ApolloStore(){}[0] +final fun (com.apollographql.cache.normalized/ApolloStore).com.apollographql.cache.normalized/removeStaleFields(com.apollographql.cache.normalized.api/MaxAgeProvider, kotlin.time/Duration = ...): com.apollographql.cache.normalized/RemovedFieldsAndRecords // com.apollographql.cache.normalized/removeStaleFields|removeStaleFields@com.apollographql.cache.normalized.ApolloStore(com.apollographql.cache.normalized.api.MaxAgeProvider;kotlin.time.Duration){}[0] +final fun (com.apollographql.cache.normalized/ApolloStore).com.apollographql.cache.normalized/removeUnreachableRecords(): kotlin.collections/Set // com.apollographql.cache.normalized/removeUnreachableRecords|removeUnreachableRecords@com.apollographql.cache.normalized.ApolloStore(){}[0] +final fun (kotlin.collections/Collection?).com.apollographql.cache.normalized.api/dependentKeys(): kotlin.collections/Set // com.apollographql.cache.normalized.api/dependentKeys|dependentKeys@kotlin.collections.Collection?(){}[0] +final fun (kotlin.collections/Map).com.apollographql.cache.normalized/getReachableCacheKeys(): kotlin.collections/Set // com.apollographql.cache.normalized/getReachableCacheKeys|getReachableCacheKeys@kotlin.collections.Map(){}[0] +final fun <#A: com.apollographql.apollo.api/Executable.Data> (com.apollographql.apollo.api/Executable<#A>).com.apollographql.cache.normalized.api/normalize(#A, com.apollographql.apollo.api/CustomScalarAdapters, com.apollographql.cache.normalized.api/CacheKeyGenerator, com.apollographql.cache.normalized.api/MetadataGenerator = ..., com.apollographql.cache.normalized.api/FieldKeyGenerator = ..., com.apollographql.cache.normalized.api/EmbeddedFieldsProvider = ..., kotlin/String): kotlin.collections/Map // com.apollographql.cache.normalized.api/normalize|normalize@com.apollographql.apollo.api.Executable<0:0>(0:0;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheKeyGenerator;com.apollographql.cache.normalized.api.MetadataGenerator;com.apollographql.cache.normalized.api.FieldKeyGenerator;com.apollographql.cache.normalized.api.EmbeddedFieldsProvider;kotlin.String){0§}[0] +final fun <#A: com.apollographql.apollo.api/Executable.Data> (com.apollographql.apollo.api/Executable<#A>).com.apollographql.cache.normalized.api/readDataFromCache(com.apollographql.apollo.api/CustomScalarAdapters, com.apollographql.cache.normalized.api/ReadOnlyNormalizedCache, com.apollographql.cache.normalized.api/CacheResolver, com.apollographql.cache.normalized.api/CacheHeaders, com.apollographql.cache.normalized.api/FieldKeyGenerator = ...): #A // com.apollographql.cache.normalized.api/readDataFromCache|readDataFromCache@com.apollographql.apollo.api.Executable<0:0>(com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.ReadOnlyNormalizedCache;com.apollographql.cache.normalized.api.CacheResolver;com.apollographql.cache.normalized.api.CacheHeaders;com.apollographql.cache.normalized.api.FieldKeyGenerator){0§}[0] +final fun <#A: com.apollographql.apollo.api/Executable.Data> (com.apollographql.apollo.api/Executable<#A>).com.apollographql.cache.normalized.api/readDataFromCache(com.apollographql.cache.normalized.api/CacheKey, com.apollographql.apollo.api/CustomScalarAdapters, com.apollographql.cache.normalized.api/ReadOnlyNormalizedCache, com.apollographql.cache.normalized.api/CacheResolver, com.apollographql.cache.normalized.api/CacheHeaders, com.apollographql.cache.normalized.api/FieldKeyGenerator = ...): #A // com.apollographql.cache.normalized.api/readDataFromCache|readDataFromCache@com.apollographql.apollo.api.Executable<0:0>(com.apollographql.cache.normalized.api.CacheKey;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.ReadOnlyNormalizedCache;com.apollographql.cache.normalized.api.CacheResolver;com.apollographql.cache.normalized.api.CacheHeaders;com.apollographql.cache.normalized.api.FieldKeyGenerator){0§}[0] +final fun <#A: com.apollographql.apollo.api/Mutation.Data> (com.apollographql.apollo.api/ApolloRequest.Builder<#A>).com.apollographql.cache.normalized/optimisticUpdates(#A): com.apollographql.apollo.api/ApolloRequest.Builder<#A> // com.apollographql.cache.normalized/optimisticUpdates|optimisticUpdates@com.apollographql.apollo.api.ApolloRequest.Builder<0:0>(0:0){0§}[0] +final fun <#A: com.apollographql.apollo.api/Mutation.Data> (com.apollographql.apollo/ApolloCall<#A>).com.apollographql.cache.normalized/optimisticUpdates(#A): com.apollographql.apollo/ApolloCall<#A> // com.apollographql.cache.normalized/optimisticUpdates|optimisticUpdates@com.apollographql.apollo.ApolloCall<0:0>(0:0){0§}[0] +final fun <#A: com.apollographql.apollo.api/Operation.Data> (com.apollographql.apollo.api/ApolloResponse.Builder<#A>).com.apollographql.cache.normalized/cacheHeaders(com.apollographql.cache.normalized.api/CacheHeaders): com.apollographql.apollo.api/ApolloResponse.Builder<#A> // com.apollographql.cache.normalized/cacheHeaders|cacheHeaders@com.apollographql.apollo.api.ApolloResponse.Builder<0:0>(com.apollographql.cache.normalized.api.CacheHeaders){0§}[0] +final fun <#A: com.apollographql.apollo.api/Operation.Data> (com.apollographql.apollo.api/Operation<#A>).com.apollographql.cache.normalized.api/normalize(#A, com.apollographql.apollo.api/CustomScalarAdapters, com.apollographql.cache.normalized.api/CacheKeyGenerator, com.apollographql.cache.normalized.api/MetadataGenerator = ..., com.apollographql.cache.normalized.api/FieldKeyGenerator = ..., com.apollographql.cache.normalized.api/EmbeddedFieldsProvider = ...): kotlin.collections/Map // com.apollographql.cache.normalized.api/normalize|normalize@com.apollographql.apollo.api.Operation<0:0>(0:0;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheKeyGenerator;com.apollographql.cache.normalized.api.MetadataGenerator;com.apollographql.cache.normalized.api.FieldKeyGenerator;com.apollographql.cache.normalized.api.EmbeddedFieldsProvider){0§}[0] +final fun <#A: com.apollographql.apollo.api/Query.Data> (com.apollographql.apollo/ApolloCall<#A>).com.apollographql.cache.normalized/watch(#A?): kotlinx.coroutines.flow/Flow> // com.apollographql.cache.normalized/watch|watch@com.apollographql.apollo.ApolloCall<0:0>(0:0?){0§}[0] +final fun <#A: com.apollographql.apollo.api/Query.Data> (com.apollographql.apollo/ApolloCall<#A>).com.apollographql.cache.normalized/watch(): kotlinx.coroutines.flow/Flow> // com.apollographql.cache.normalized/watch|watch@com.apollographql.apollo.ApolloCall<0:0>(){0§}[0] +final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/addCacheHeader(kotlin/String, kotlin/String): #A // com.apollographql.cache.normalized/addCacheHeader|addCacheHeader@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.String;kotlin.String){0§}[0] +final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/cacheHeaders(com.apollographql.cache.normalized.api/CacheHeaders): #A // com.apollographql.cache.normalized/cacheHeaders|cacheHeaders@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(com.apollographql.cache.normalized.api.CacheHeaders){0§}[0] +final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/doNotStore(kotlin/Boolean): #A // com.apollographql.cache.normalized/doNotStore|doNotStore@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] +final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/fetchPolicy(com.apollographql.cache.normalized/FetchPolicy): #A // com.apollographql.cache.normalized/fetchPolicy|fetchPolicy@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(com.apollographql.cache.normalized.FetchPolicy){0§}[0] +final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/fetchPolicyInterceptor(com.apollographql.apollo.interceptor/ApolloInterceptor): #A // com.apollographql.cache.normalized/fetchPolicyInterceptor|fetchPolicyInterceptor@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(com.apollographql.apollo.interceptor.ApolloInterceptor){0§}[0] +final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/maxStale(kotlin.time/Duration): #A // com.apollographql.cache.normalized/maxStale|maxStale@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.time.Duration){0§}[0] +final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/memoryCacheOnly(kotlin/Boolean): #A // com.apollographql.cache.normalized/memoryCacheOnly|memoryCacheOnly@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] +final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/refetchPolicy(com.apollographql.cache.normalized/FetchPolicy): #A // com.apollographql.cache.normalized/refetchPolicy|refetchPolicy@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(com.apollographql.cache.normalized.FetchPolicy){0§}[0] +final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/refetchPolicyInterceptor(com.apollographql.apollo.interceptor/ApolloInterceptor): #A // com.apollographql.cache.normalized/refetchPolicyInterceptor|refetchPolicyInterceptor@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(com.apollographql.apollo.interceptor.ApolloInterceptor){0§}[0] +final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/retrievePartialResponses(kotlin/Boolean): #A // com.apollographql.cache.normalized/retrievePartialResponses|retrievePartialResponses@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] +final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/storeExpirationDate(kotlin/Boolean): #A // com.apollographql.cache.normalized/storeExpirationDate|storeExpirationDate@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] +final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/storePartialResponses(kotlin/Boolean): #A // com.apollographql.cache.normalized/storePartialResponses|storePartialResponses@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] +final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/storeReceiveDate(kotlin/Boolean): #A // com.apollographql.cache.normalized/storeReceiveDate|storeReceiveDate@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] +final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/writeToCacheAsynchronously(kotlin/Boolean): #A // com.apollographql.cache.normalized/writeToCacheAsynchronously|writeToCacheAsynchronously@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] +final fun com.apollographql.cache.normalized/ApolloStore(com.apollographql.cache.normalized.api/NormalizedCacheFactory, com.apollographql.cache.normalized.api/CacheKeyGenerator = ..., com.apollographql.cache.normalized.api/MetadataGenerator = ..., com.apollographql.cache.normalized.api/CacheResolver = ..., com.apollographql.cache.normalized.api/RecordMerger = ..., com.apollographql.cache.normalized.api/FieldKeyGenerator = ..., com.apollographql.cache.normalized.api/EmbeddedFieldsProvider = ...): com.apollographql.cache.normalized/ApolloStore // com.apollographql.cache.normalized/ApolloStore|ApolloStore(com.apollographql.cache.normalized.api.NormalizedCacheFactory;com.apollographql.cache.normalized.api.CacheKeyGenerator;com.apollographql.cache.normalized.api.MetadataGenerator;com.apollographql.cache.normalized.api.CacheResolver;com.apollographql.cache.normalized.api.RecordMerger;com.apollographql.cache.normalized.api.FieldKeyGenerator;com.apollographql.cache.normalized.api.EmbeddedFieldsProvider){}[0] diff --git a/normalized-cache-sqlite-incubating/api/normalized-cache-sqlite-incubating.klib.api b/normalized-cache-sqlite-incubating/api/normalized-cache-sqlite-incubating.klib.api index 179691a8..25be1d66 100644 --- a/normalized-cache-sqlite-incubating/api/normalized-cache-sqlite-incubating.klib.api +++ b/normalized-cache-sqlite-incubating/api/normalized-cache-sqlite-incubating.klib.api @@ -9,23 +9,30 @@ abstract interface com.apollographql.cache.normalized.sql.internal.blob/BlobDatabase : app.cash.sqldelight/Transacter { // com.apollographql.cache.normalized.sql.internal.blob/BlobDatabase|null[0] abstract val blobQueries // com.apollographql.cache.normalized.sql.internal.blob/BlobDatabase.blobQueries|{}blobQueries[0] abstract fun (): com.apollographql.cache.normalized.sql.internal.blob/BlobQueries // com.apollographql.cache.normalized.sql.internal.blob/BlobDatabase.blobQueries.|(){}[0] + final object Companion { // com.apollographql.cache.normalized.sql.internal.blob/BlobDatabase.Companion|null[0] - final fun invoke(app.cash.sqldelight.db/SqlDriver): com.apollographql.cache.normalized.sql.internal.blob/BlobDatabase // com.apollographql.cache.normalized.sql.internal.blob/BlobDatabase.Companion.invoke|invoke(app.cash.sqldelight.db.SqlDriver){}[0] final val Schema // com.apollographql.cache.normalized.sql.internal.blob/BlobDatabase.Companion.Schema|{}Schema[0] final fun (): app.cash.sqldelight.db/SqlSchema> // com.apollographql.cache.normalized.sql.internal.blob/BlobDatabase.Companion.Schema.|(){}[0] + + final fun invoke(app.cash.sqldelight.db/SqlDriver): com.apollographql.cache.normalized.sql.internal.blob/BlobDatabase // com.apollographql.cache.normalized.sql.internal.blob/BlobDatabase.Companion.invoke|invoke(app.cash.sqldelight.db.SqlDriver){}[0] } } + abstract interface com.apollographql.cache.normalized.sql.internal.blob2/Blob2Database : app.cash.sqldelight/Transacter { // com.apollographql.cache.normalized.sql.internal.blob2/Blob2Database|null[0] abstract val blob2Queries // com.apollographql.cache.normalized.sql.internal.blob2/Blob2Database.blob2Queries|{}blob2Queries[0] abstract fun (): com.apollographql.cache.normalized.sql.internal.blob2/Blob2Queries // com.apollographql.cache.normalized.sql.internal.blob2/Blob2Database.blob2Queries.|(){}[0] + final object Companion { // com.apollographql.cache.normalized.sql.internal.blob2/Blob2Database.Companion|null[0] - final fun invoke(app.cash.sqldelight.db/SqlDriver): com.apollographql.cache.normalized.sql.internal.blob2/Blob2Database // com.apollographql.cache.normalized.sql.internal.blob2/Blob2Database.Companion.invoke|invoke(app.cash.sqldelight.db.SqlDriver){}[0] final val Schema // com.apollographql.cache.normalized.sql.internal.blob2/Blob2Database.Companion.Schema|{}Schema[0] final fun (): app.cash.sqldelight.db/SqlSchema> // com.apollographql.cache.normalized.sql.internal.blob2/Blob2Database.Companion.Schema.|(){}[0] + + final fun invoke(app.cash.sqldelight.db/SqlDriver): com.apollographql.cache.normalized.sql.internal.blob2/Blob2Database // com.apollographql.cache.normalized.sql.internal.blob2/Blob2Database.Companion.invoke|invoke(app.cash.sqldelight.db.SqlDriver){}[0] } } + final class com.apollographql.cache.normalized.sql.internal.blob/BlobQueries : app.cash.sqldelight/TransacterImpl { // com.apollographql.cache.normalized.sql.internal.blob/BlobQueries|null[0] constructor (app.cash.sqldelight.db/SqlDriver) // com.apollographql.cache.normalized.sql.internal.blob/BlobQueries.|(app.cash.sqldelight.db.SqlDriver){}[0] + final fun <#A1: kotlin/Any> recordForKey(kotlin/String, kotlin/Function2): app.cash.sqldelight/Query<#A1> // com.apollographql.cache.normalized.sql.internal.blob/BlobQueries.recordForKey|recordForKey(kotlin.String;kotlin.Function2){0§}[0] final fun <#A1: kotlin/Any> recordsForKeys(kotlin.collections/Collection, kotlin/Function2): app.cash.sqldelight/Query<#A1> // com.apollographql.cache.normalized.sql.internal.blob/BlobQueries.recordsForKeys|recordsForKeys(kotlin.collections.Collection;kotlin.Function2){0§}[0] final fun <#A1: kotlin/Any> selectRecords(kotlin/Function2): app.cash.sqldelight/Query<#A1> // com.apollographql.cache.normalized.sql.internal.blob/BlobQueries.selectRecords|selectRecords(kotlin.Function2){0§}[0] @@ -40,21 +47,26 @@ final class com.apollographql.cache.normalized.sql.internal.blob/BlobQueries : a final fun selectRecords(): app.cash.sqldelight/Query // com.apollographql.cache.normalized.sql.internal.blob/BlobQueries.selectRecords|selectRecords(){}[0] final fun update(kotlin/ByteArray, kotlin/String) // com.apollographql.cache.normalized.sql.internal.blob/BlobQueries.update|update(kotlin.ByteArray;kotlin.String){}[0] } + final class com.apollographql.cache.normalized.sql.internal.blob/Blobs { // com.apollographql.cache.normalized.sql.internal.blob/Blobs|null[0] constructor (kotlin/String, kotlin/ByteArray) // com.apollographql.cache.normalized.sql.internal.blob/Blobs.|(kotlin.String;kotlin.ByteArray){}[0] + + final val blob // com.apollographql.cache.normalized.sql.internal.blob/Blobs.blob|{}blob[0] + final fun (): kotlin/ByteArray // com.apollographql.cache.normalized.sql.internal.blob/Blobs.blob.|(){}[0] + final val key // com.apollographql.cache.normalized.sql.internal.blob/Blobs.key|{}key[0] + final fun (): kotlin/String // com.apollographql.cache.normalized.sql.internal.blob/Blobs.key.|(){}[0] + final fun component1(): kotlin/String // com.apollographql.cache.normalized.sql.internal.blob/Blobs.component1|component1(){}[0] final fun component2(): kotlin/ByteArray // com.apollographql.cache.normalized.sql.internal.blob/Blobs.component2|component2(){}[0] final fun copy(kotlin/String = ..., kotlin/ByteArray = ...): com.apollographql.cache.normalized.sql.internal.blob/Blobs // com.apollographql.cache.normalized.sql.internal.blob/Blobs.copy|copy(kotlin.String;kotlin.ByteArray){}[0] final fun equals(kotlin/Any?): kotlin/Boolean // com.apollographql.cache.normalized.sql.internal.blob/Blobs.equals|equals(kotlin.Any?){}[0] final fun hashCode(): kotlin/Int // com.apollographql.cache.normalized.sql.internal.blob/Blobs.hashCode|hashCode(){}[0] final fun toString(): kotlin/String // com.apollographql.cache.normalized.sql.internal.blob/Blobs.toString|toString(){}[0] - final val blob // com.apollographql.cache.normalized.sql.internal.blob/Blobs.blob|{}blob[0] - final fun (): kotlin/ByteArray // com.apollographql.cache.normalized.sql.internal.blob/Blobs.blob.|(){}[0] - final val key // com.apollographql.cache.normalized.sql.internal.blob/Blobs.key|{}key[0] - final fun (): kotlin/String // com.apollographql.cache.normalized.sql.internal.blob/Blobs.key.|(){}[0] } + final class com.apollographql.cache.normalized.sql.internal.blob2/Blob2Queries : app.cash.sqldelight/TransacterImpl { // com.apollographql.cache.normalized.sql.internal.blob2/Blob2Queries|null[0] constructor (app.cash.sqldelight.db/SqlDriver) // com.apollographql.cache.normalized.sql.internal.blob2/Blob2Queries.|(app.cash.sqldelight.db.SqlDriver){}[0] + final fun <#A1: kotlin/Any> recordForKey(kotlin/String, kotlin/Function2): app.cash.sqldelight/Query<#A1> // com.apollographql.cache.normalized.sql.internal.blob2/Blob2Queries.recordForKey|recordForKey(kotlin.String;kotlin.Function2){0§}[0] final fun <#A1: kotlin/Any> recordsForKeys(kotlin.collections/Collection, kotlin/Function2): app.cash.sqldelight/Query<#A1> // com.apollographql.cache.normalized.sql.internal.blob2/Blob2Queries.recordsForKeys|recordsForKeys(kotlin.collections.Collection;kotlin.Function2){0§}[0] final fun <#A1: kotlin/Any> selectRecords(kotlin/Function3): app.cash.sqldelight/Query<#A1> // com.apollographql.cache.normalized.sql.internal.blob2/Blob2Queries.selectRecords|selectRecords(kotlin.Function3){0§}[0] @@ -71,8 +83,17 @@ final class com.apollographql.cache.normalized.sql.internal.blob2/Blob2Queries : final fun trim(kotlin/Long) // com.apollographql.cache.normalized.sql.internal.blob2/Blob2Queries.trim|trim(kotlin.Long){}[0] final fun update(kotlin/ByteArray, kotlin/Long?, kotlin/String) // com.apollographql.cache.normalized.sql.internal.blob2/Blob2Queries.update|update(kotlin.ByteArray;kotlin.Long?;kotlin.String){}[0] } + final class com.apollographql.cache.normalized.sql.internal.blob2/Blobs { // com.apollographql.cache.normalized.sql.internal.blob2/Blobs|null[0] constructor (kotlin/String, kotlin/ByteArray, kotlin/Long?) // com.apollographql.cache.normalized.sql.internal.blob2/Blobs.|(kotlin.String;kotlin.ByteArray;kotlin.Long?){}[0] + + final val blob // com.apollographql.cache.normalized.sql.internal.blob2/Blobs.blob|{}blob[0] + final fun (): kotlin/ByteArray // com.apollographql.cache.normalized.sql.internal.blob2/Blobs.blob.|(){}[0] + final val date // com.apollographql.cache.normalized.sql.internal.blob2/Blobs.date|{}date[0] + final fun (): kotlin/Long? // com.apollographql.cache.normalized.sql.internal.blob2/Blobs.date.|(){}[0] + final val key // com.apollographql.cache.normalized.sql.internal.blob2/Blobs.key|{}key[0] + final fun (): kotlin/String // com.apollographql.cache.normalized.sql.internal.blob2/Blobs.key.|(){}[0] + final fun component1(): kotlin/String // com.apollographql.cache.normalized.sql.internal.blob2/Blobs.component1|component1(){}[0] final fun component2(): kotlin/ByteArray // com.apollographql.cache.normalized.sql.internal.blob2/Blobs.component2|component2(){}[0] final fun component3(): kotlin/Long? // com.apollographql.cache.normalized.sql.internal.blob2/Blobs.component3|component3(){}[0] @@ -80,39 +101,40 @@ final class com.apollographql.cache.normalized.sql.internal.blob2/Blobs { // com final fun equals(kotlin/Any?): kotlin/Boolean // com.apollographql.cache.normalized.sql.internal.blob2/Blobs.equals|equals(kotlin.Any?){}[0] final fun hashCode(): kotlin/Int // com.apollographql.cache.normalized.sql.internal.blob2/Blobs.hashCode|hashCode(){}[0] final fun toString(): kotlin/String // com.apollographql.cache.normalized.sql.internal.blob2/Blobs.toString|toString(){}[0] - final val blob // com.apollographql.cache.normalized.sql.internal.blob2/Blobs.blob|{}blob[0] - final fun (): kotlin/ByteArray // com.apollographql.cache.normalized.sql.internal.blob2/Blobs.blob.|(){}[0] - final val date // com.apollographql.cache.normalized.sql.internal.blob2/Blobs.date|{}date[0] - final fun (): kotlin/Long? // com.apollographql.cache.normalized.sql.internal.blob2/Blobs.date.|(){}[0] - final val key // com.apollographql.cache.normalized.sql.internal.blob2/Blobs.key|{}key[0] - final fun (): kotlin/String // com.apollographql.cache.normalized.sql.internal.blob2/Blobs.key.|(){}[0] } + final class com.apollographql.cache.normalized.sql.internal.blob2/RecordForKey { // com.apollographql.cache.normalized.sql.internal.blob2/RecordForKey|null[0] constructor (kotlin/String, kotlin/ByteArray) // com.apollographql.cache.normalized.sql.internal.blob2/RecordForKey.|(kotlin.String;kotlin.ByteArray){}[0] + + final val blob // com.apollographql.cache.normalized.sql.internal.blob2/RecordForKey.blob|{}blob[0] + final fun (): kotlin/ByteArray // com.apollographql.cache.normalized.sql.internal.blob2/RecordForKey.blob.|(){}[0] + final val key // com.apollographql.cache.normalized.sql.internal.blob2/RecordForKey.key|{}key[0] + final fun (): kotlin/String // com.apollographql.cache.normalized.sql.internal.blob2/RecordForKey.key.|(){}[0] + final fun component1(): kotlin/String // com.apollographql.cache.normalized.sql.internal.blob2/RecordForKey.component1|component1(){}[0] final fun component2(): kotlin/ByteArray // com.apollographql.cache.normalized.sql.internal.blob2/RecordForKey.component2|component2(){}[0] final fun copy(kotlin/String = ..., kotlin/ByteArray = ...): com.apollographql.cache.normalized.sql.internal.blob2/RecordForKey // com.apollographql.cache.normalized.sql.internal.blob2/RecordForKey.copy|copy(kotlin.String;kotlin.ByteArray){}[0] final fun equals(kotlin/Any?): kotlin/Boolean // com.apollographql.cache.normalized.sql.internal.blob2/RecordForKey.equals|equals(kotlin.Any?){}[0] final fun hashCode(): kotlin/Int // com.apollographql.cache.normalized.sql.internal.blob2/RecordForKey.hashCode|hashCode(){}[0] final fun toString(): kotlin/String // com.apollographql.cache.normalized.sql.internal.blob2/RecordForKey.toString|toString(){}[0] - final val blob // com.apollographql.cache.normalized.sql.internal.blob2/RecordForKey.blob|{}blob[0] - final fun (): kotlin/ByteArray // com.apollographql.cache.normalized.sql.internal.blob2/RecordForKey.blob.|(){}[0] - final val key // com.apollographql.cache.normalized.sql.internal.blob2/RecordForKey.key|{}key[0] - final fun (): kotlin/String // com.apollographql.cache.normalized.sql.internal.blob2/RecordForKey.key.|(){}[0] } + final class com.apollographql.cache.normalized.sql.internal.blob2/RecordsForKeys { // com.apollographql.cache.normalized.sql.internal.blob2/RecordsForKeys|null[0] constructor (kotlin/String, kotlin/ByteArray) // com.apollographql.cache.normalized.sql.internal.blob2/RecordsForKeys.|(kotlin.String;kotlin.ByteArray){}[0] + + final val blob // com.apollographql.cache.normalized.sql.internal.blob2/RecordsForKeys.blob|{}blob[0] + final fun (): kotlin/ByteArray // com.apollographql.cache.normalized.sql.internal.blob2/RecordsForKeys.blob.|(){}[0] + final val key // com.apollographql.cache.normalized.sql.internal.blob2/RecordsForKeys.key|{}key[0] + final fun (): kotlin/String // com.apollographql.cache.normalized.sql.internal.blob2/RecordsForKeys.key.|(){}[0] + final fun component1(): kotlin/String // com.apollographql.cache.normalized.sql.internal.blob2/RecordsForKeys.component1|component1(){}[0] final fun component2(): kotlin/ByteArray // com.apollographql.cache.normalized.sql.internal.blob2/RecordsForKeys.component2|component2(){}[0] final fun copy(kotlin/String = ..., kotlin/ByteArray = ...): com.apollographql.cache.normalized.sql.internal.blob2/RecordsForKeys // com.apollographql.cache.normalized.sql.internal.blob2/RecordsForKeys.copy|copy(kotlin.String;kotlin.ByteArray){}[0] final fun equals(kotlin/Any?): kotlin/Boolean // com.apollographql.cache.normalized.sql.internal.blob2/RecordsForKeys.equals|equals(kotlin.Any?){}[0] final fun hashCode(): kotlin/Int // com.apollographql.cache.normalized.sql.internal.blob2/RecordsForKeys.hashCode|hashCode(){}[0] final fun toString(): kotlin/String // com.apollographql.cache.normalized.sql.internal.blob2/RecordsForKeys.toString|toString(){}[0] - final val blob // com.apollographql.cache.normalized.sql.internal.blob2/RecordsForKeys.blob|{}blob[0] - final fun (): kotlin/ByteArray // com.apollographql.cache.normalized.sql.internal.blob2/RecordsForKeys.blob.|(){}[0] - final val key // com.apollographql.cache.normalized.sql.internal.blob2/RecordsForKeys.key|{}key[0] - final fun (): kotlin/String // com.apollographql.cache.normalized.sql.internal.blob2/RecordsForKeys.key.|(){}[0] } + final class com.apollographql.cache.normalized.sql/SqlNormalizedCache : com.apollographql.cache.normalized.api/NormalizedCache { // com.apollographql.cache.normalized.sql/SqlNormalizedCache|null[0] final fun clearAll() // com.apollographql.cache.normalized.sql/SqlNormalizedCache.clearAll|clearAll(){}[0] final fun dump(): kotlin.collections/Map, kotlin.collections/Map> // com.apollographql.cache.normalized.sql/SqlNormalizedCache.dump|dump(){}[0] @@ -124,8 +146,10 @@ final class com.apollographql.cache.normalized.sql/SqlNormalizedCache : com.apol final fun remove(kotlin.collections/Collection, kotlin/Boolean): kotlin/Int // com.apollographql.cache.normalized.sql/SqlNormalizedCache.remove|remove(kotlin.collections.Collection;kotlin.Boolean){}[0] final fun remove(kotlin/String): kotlin/Int // com.apollographql.cache.normalized.sql/SqlNormalizedCache.remove|remove(kotlin.String){}[0] } + final const val com.apollographql.cache.normalized.sql/VERSION // com.apollographql.cache.normalized.sql/VERSION|{}VERSION[0] final fun (): kotlin/String // com.apollographql.cache.normalized.sql/VERSION.|(){}[0] + final fun com.apollographql.cache.normalized.sql/SqlNormalizedCacheFactory(app.cash.sqldelight.db/SqlDriver): com.apollographql.cache.normalized.api/NormalizedCacheFactory // com.apollographql.cache.normalized.sql/SqlNormalizedCacheFactory|SqlNormalizedCacheFactory(app.cash.sqldelight.db.SqlDriver){}[0] final fun com.apollographql.cache.normalized.sql/SqlNormalizedCacheFactory(kotlin/String? = ...): com.apollographql.cache.normalized.api/NormalizedCacheFactory // com.apollographql.cache.normalized.sql/SqlNormalizedCacheFactory|SqlNormalizedCacheFactory(kotlin.String?){}[0] final fun com.apollographql.cache.normalized.sql/SqlNormalizedCacheFactory(kotlin/String?, kotlin/String?): com.apollographql.cache.normalized.api/NormalizedCacheFactory // com.apollographql.cache.normalized.sql/SqlNormalizedCacheFactory|SqlNormalizedCacheFactory(kotlin.String?;kotlin.String?){}[0] From 6b3bfd2e5430e409002a0bd6cc7bccc9ebb296d4 Mon Sep 17 00:00:00 2001 From: BoD Date: Thu, 30 Jan 2025 09:40:16 +0100 Subject: [PATCH 03/11] Generate a Schema via the compiler plugin --- ...ormalized-cache-apollo-compiler-plugin.api | 2 +- .../ApolloCacheCompilerPlugin.kt | 17 ++++- .../apollocompilerplugin/internal/Codegen.kt | 62 ++++++++++++++++--- .../api/normalized-cache-incubating.api | 6 +- .../api/normalized-cache-incubating.klib.api | 4 +- .../cache/normalized/ApolloStore.kt | 4 +- .../cache/normalized/ClientCacheExtensions.kt | 26 ++++++++ .../internal/ApolloCacheInterceptor.kt | 3 +- .../normalized/internal/DefaultApolloStore.kt | 3 +- tests/partial-results/build.gradle.kts | 5 ++ .../kotlin/test/CachePartialResultTest.kt | 54 ++-------------- 11 files changed, 120 insertions(+), 66 deletions(-) diff --git a/normalized-cache-apollo-compiler-plugin/api/normalized-cache-apollo-compiler-plugin.api b/normalized-cache-apollo-compiler-plugin/api/normalized-cache-apollo-compiler-plugin.api index 439fa85e..65a0c900 100644 --- a/normalized-cache-apollo-compiler-plugin/api/normalized-cache-apollo-compiler-plugin.api +++ b/normalized-cache-apollo-compiler-plugin/api/normalized-cache-apollo-compiler-plugin.api @@ -1,5 +1,5 @@ public final class com/apollographql/cache/apollocompilerplugin/ApolloCacheCompilerPlugin : com/apollographql/apollo/compiler/ApolloCompilerPlugin { - public fun (Ljava/lang/String;Lcom/apollographql/apollo/compiler/ApolloCompilerPluginLogger;)V + public fun (Lcom/apollographql/apollo/compiler/ApolloCompilerPluginLogger;Ljava/lang/String;Z)V public fun foreignSchemas ()Ljava/util/List; public fun schemaListener ()Lcom/apollographql/apollo/compiler/SchemaListener; } diff --git a/normalized-cache-apollo-compiler-plugin/src/main/kotlin/com/apollographql/cache/apollocompilerplugin/ApolloCacheCompilerPlugin.kt b/normalized-cache-apollo-compiler-plugin/src/main/kotlin/com/apollographql/cache/apollocompilerplugin/ApolloCacheCompilerPlugin.kt index 5d1f0667..5d1f556e 100644 --- a/normalized-cache-apollo-compiler-plugin/src/main/kotlin/com/apollographql/cache/apollocompilerplugin/ApolloCacheCompilerPlugin.kt +++ b/normalized-cache-apollo-compiler-plugin/src/main/kotlin/com/apollographql/cache/apollocompilerplugin/ApolloCacheCompilerPlugin.kt @@ -18,16 +18,22 @@ import java.io.File class ApolloCacheCompilerPluginProvider : ApolloCompilerPluginProvider { override fun create(environment: ApolloCompilerPluginEnvironment): ApolloCompilerPlugin { return ApolloCacheCompilerPlugin( + logger = environment.logger, packageName = environment.arguments["packageName"] as? String ?: throw IllegalArgumentException("packageName argument is required and must be a String"), - logger = environment.logger, + generateSchema = when (val generateSchema = environment.arguments["generateSchema"]) { + null -> false + is Boolean -> generateSchema + else -> throw IllegalArgumentException("generateSchema argument must be a Boolean") + } ) } } class ApolloCacheCompilerPlugin( - private val packageName: String, private val logger: ApolloCompilerPluginLogger, + private val packageName: String, + private val generateSchema: Boolean, ) : ApolloCompilerPlugin { override fun foreignSchemas(): List { return listOf( @@ -40,7 +46,12 @@ class ApolloCacheCompilerPlugin( return object : SchemaListener { override fun onSchema(schema: Schema, outputDirectory: File) { val maxAges = schema.getMaxAges(logger) - Codegen("$packageName.cache", outputDirectory, maxAges).generate() + Codegen( + packageName = "$packageName.cache", + outputDirectory = outputDirectory, + maxAges = maxAges, + schema = schema.takeIf { generateSchema }, + ).generate() } } } diff --git a/normalized-cache-apollo-compiler-plugin/src/main/kotlin/com/apollographql/cache/apollocompilerplugin/internal/Codegen.kt b/normalized-cache-apollo-compiler-plugin/src/main/kotlin/com/apollographql/cache/apollocompilerplugin/internal/Codegen.kt index a2610784..de52d7ef 100644 --- a/normalized-cache-apollo-compiler-plugin/src/main/kotlin/com/apollographql/cache/apollocompilerplugin/internal/Codegen.kt +++ b/normalized-cache-apollo-compiler-plugin/src/main/kotlin/com/apollographql/cache/apollocompilerplugin/internal/Codegen.kt @@ -1,9 +1,16 @@ package com.apollographql.cache.apollocompilerplugin.internal +import com.apollographql.apollo.annotations.ApolloExperimental +import com.apollographql.apollo.ast.GQLDocument +import com.apollographql.apollo.ast.GQLNamed +import com.apollographql.apollo.ast.Schema +import com.apollographql.apollo.ast.builtinDefinitions +import com.apollographql.apollo.ast.toSDL import com.apollographql.cache.apollocompilerplugin.VERSION import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.FileSpec +import com.squareup.kotlinpoet.KModifier import com.squareup.kotlinpoet.MAP import com.squareup.kotlinpoet.MemberName import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy @@ -21,13 +28,25 @@ private object Symbols { val Seconds = MemberName(Duration.Companion::class.asTypeName(), "seconds", isExtension = true) } +private val FILE_COMMENT = """ + + AUTO-GENERATED FILE. DO NOT MODIFY. + + This class was automatically generated by Apollo GraphQL Cache version '$VERSION'. + +""".trimIndent() + internal class Codegen( private val packageName: String, private val outputDirectory: File, private val maxAges: Map, + private val schema: Schema?, ) { fun generate() { generateCache() + if (schema != null) { + generateSchema(schema.toGQLDocumentWithoutBuiltinDefinitions()) + } } private fun generateCache() { @@ -57,17 +76,44 @@ internal class Codegen( ) .build() ) - .addFileComment( - """ - - AUTO-GENERATED FILE. DO NOT MODIFY. - - This class was automatically generated by Apollo GraphQL Cache version '$VERSION'. - - """.trimIndent() + .addFileComment(FILE_COMMENT) + .build() + + file.writeTo(outputDirectory) + } + + private fun generateSchema(schema: GQLDocument) { + val file = FileSpec.builder(packageName, "Schema") + .addType( + TypeSpec.objectBuilder("Schema") + .addProperty( + PropertySpec.builder("schema", String::class) + .addModifiers(KModifier.CONST) + .initializer("%S", @OptIn(ApolloExperimental::class) schema.toSDL()) + .build() + ) + .build() ) + .addFileComment(FILE_COMMENT) .build() file.writeTo(outputDirectory) } } + +private fun Schema.toGQLDocumentWithoutBuiltinDefinitions(): GQLDocument { + val excludedNames = builtinDefinitions().map { + (it as GQLNamed).name + }.toSet() + val gqlDocument = toGQLDocument() + return gqlDocument.copy( + definitions = gqlDocument.definitions.filter { + if (it !is GQLNamed) { + // GQLSchemaDefinition is not a GQLNamed + return@filter true + } + !excludedNames.contains(it.name) + } + ) + +} diff --git a/normalized-cache-incubating/api/normalized-cache-incubating.api b/normalized-cache-incubating/api/normalized-cache-incubating.api index 1dccbf37..32983621 100644 --- a/normalized-cache-incubating/api/normalized-cache-incubating.api +++ b/normalized-cache-incubating/api/normalized-cache-incubating.api @@ -9,7 +9,7 @@ public abstract interface class com/apollographql/cache/normalized/ApolloStore { public abstract fun publish (Ljava/util/Set;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun readFragment (Lcom/apollographql/apollo/api/Fragment;Lcom/apollographql/cache/normalized/api/CacheKey;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;)Lcom/apollographql/cache/normalized/ApolloStore$ReadResult; public abstract fun readOperation (Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;)Lcom/apollographql/cache/normalized/ApolloStore$ReadResult; - public abstract fun readOperationPartial (Lcom/apollographql/apollo/api/Operation;Ljava/lang/String;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun readOperationPartial (Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/ast/GQLDocument;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun remove (Lcom/apollographql/cache/normalized/api/CacheKey;Z)Z public abstract fun remove (Ljava/util/List;Z)I public abstract fun rollbackOptimisticUpdates (Ljava/util/UUID;)Ljava/util/Set; @@ -26,7 +26,7 @@ public final class com/apollographql/cache/normalized/ApolloStore$Companion { public final class com/apollographql/cache/normalized/ApolloStore$DefaultImpls { public static synthetic fun readFragment$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/apollo/api/Fragment;Lcom/apollographql/cache/normalized/api/CacheKey;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;ILjava/lang/Object;)Lcom/apollographql/cache/normalized/ApolloStore$ReadResult; public static synthetic fun readOperation$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;ILjava/lang/Object;)Lcom/apollographql/cache/normalized/ApolloStore$ReadResult; - public static synthetic fun readOperationPartial$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/apollo/api/Operation;Ljava/lang/String;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; + public static synthetic fun readOperationPartial$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/ast/GQLDocument;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; public static synthetic fun remove$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/cache/normalized/api/CacheKey;ZILjava/lang/Object;)Z public static synthetic fun remove$default (Lcom/apollographql/cache/normalized/ApolloStore;Ljava/util/List;ZILjava/lang/Object;)I public static synthetic fun writeFragment$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/apollo/api/Fragment;Lcom/apollographql/cache/normalized/api/CacheKey;Lcom/apollographql/apollo/api/Fragment$Data;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;ILjava/lang/Object;)Ljava/util/Set; @@ -156,6 +156,8 @@ public final class com/apollographql/cache/normalized/NormalizedCache { public static final fun refetchPolicy (Lcom/apollographql/apollo/api/MutableExecutionOptions;Lcom/apollographql/cache/normalized/FetchPolicy;)Ljava/lang/Object; public static final fun refetchPolicyInterceptor (Lcom/apollographql/apollo/api/MutableExecutionOptions;Lcom/apollographql/apollo/interceptor/ApolloInterceptor;)Ljava/lang/Object; public static final fun retrievePartialResponses (Lcom/apollographql/apollo/api/MutableExecutionOptions;Z)Ljava/lang/Object; + public static final fun schema (Lcom/apollographql/apollo/api/MutableExecutionOptions;Lcom/apollographql/apollo/ast/GQLDocument;)Ljava/lang/Object; + public static final fun schema (Lcom/apollographql/apollo/api/MutableExecutionOptions;Ljava/lang/String;)Ljava/lang/Object; public static final fun store (Lcom/apollographql/apollo/ApolloClient$Builder;Lcom/apollographql/cache/normalized/ApolloStore;Z)Lcom/apollographql/apollo/ApolloClient$Builder; public static synthetic fun store$default (Lcom/apollographql/apollo/ApolloClient$Builder;Lcom/apollographql/cache/normalized/ApolloStore;ZILjava/lang/Object;)Lcom/apollographql/apollo/ApolloClient$Builder; public static final fun storeExpirationDate (Lcom/apollographql/apollo/api/MutableExecutionOptions;Z)Ljava/lang/Object; diff --git a/normalized-cache-incubating/api/normalized-cache-incubating.klib.api b/normalized-cache-incubating/api/normalized-cache-incubating.klib.api index cfbb211e..a50578c1 100644 --- a/normalized-cache-incubating/api/normalized-cache-incubating.klib.api +++ b/normalized-cache-incubating/api/normalized-cache-incubating.klib.api @@ -94,7 +94,7 @@ abstract interface com.apollographql.cache.normalized/ApolloStore { // com.apoll abstract fun remove(com.apollographql.cache.normalized.api/CacheKey, kotlin/Boolean = ...): kotlin/Boolean // com.apollographql.cache.normalized/ApolloStore.remove|remove(com.apollographql.cache.normalized.api.CacheKey;kotlin.Boolean){}[0] abstract fun remove(kotlin.collections/List, kotlin/Boolean = ...): kotlin/Int // com.apollographql.cache.normalized/ApolloStore.remove|remove(kotlin.collections.List;kotlin.Boolean){}[0] abstract fun rollbackOptimisticUpdates(com.benasher44.uuid/Uuid): kotlin.collections/Set // com.apollographql.cache.normalized/ApolloStore.rollbackOptimisticUpdates|rollbackOptimisticUpdates(com.benasher44.uuid.Uuid){}[0] - abstract suspend fun <#A1: com.apollographql.apollo.api/Operation.Data> readOperationPartial(com.apollographql.apollo.api/Operation<#A1>, kotlin/String, com.apollographql.apollo.api/CustomScalarAdapters = ..., com.apollographql.cache.normalized.api/CacheHeaders = ...): com.apollographql.apollo.api/ApolloResponse<#A1> // com.apollographql.cache.normalized/ApolloStore.readOperationPartial|readOperationPartial(com.apollographql.apollo.api.Operation<0:0>;kotlin.String;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheHeaders){0§}[0] + abstract suspend fun <#A1: com.apollographql.apollo.api/Operation.Data> readOperationPartial(com.apollographql.apollo.api/Operation<#A1>, com.apollographql.apollo.ast/GQLDocument, com.apollographql.apollo.api/CustomScalarAdapters = ..., com.apollographql.cache.normalized.api/CacheHeaders = ...): com.apollographql.apollo.api/ApolloResponse<#A1> // com.apollographql.cache.normalized/ApolloStore.readOperationPartial|readOperationPartial(com.apollographql.apollo.api.Operation<0:0>;com.apollographql.apollo.ast.GQLDocument;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheHeaders){0§}[0] abstract suspend fun publish(kotlin.collections/Set) // com.apollographql.cache.normalized/ApolloStore.publish|publish(kotlin.collections.Set){}[0] final class <#A1: com.apollographql.apollo.api/Executable.Data> ReadResult { // com.apollographql.cache.normalized/ApolloStore.ReadResult|null[0] @@ -574,6 +574,8 @@ final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOption final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/refetchPolicy(com.apollographql.cache.normalized/FetchPolicy): #A // com.apollographql.cache.normalized/refetchPolicy|refetchPolicy@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(com.apollographql.cache.normalized.FetchPolicy){0§}[0] final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/refetchPolicyInterceptor(com.apollographql.apollo.interceptor/ApolloInterceptor): #A // com.apollographql.cache.normalized/refetchPolicyInterceptor|refetchPolicyInterceptor@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(com.apollographql.apollo.interceptor.ApolloInterceptor){0§}[0] final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/retrievePartialResponses(kotlin/Boolean): #A // com.apollographql.cache.normalized/retrievePartialResponses|retrievePartialResponses@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] +final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/schema(com.apollographql.apollo.ast/GQLDocument): #A // com.apollographql.cache.normalized/schema|schema@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(com.apollographql.apollo.ast.GQLDocument){0§}[0] +final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/schema(kotlin/String): #A // com.apollographql.cache.normalized/schema|schema@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.String){0§}[0] final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/storeExpirationDate(kotlin/Boolean): #A // com.apollographql.cache.normalized/storeExpirationDate|storeExpirationDate@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/storePartialResponses(kotlin/Boolean): #A // com.apollographql.cache.normalized/storePartialResponses|storePartialResponses@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/storeReceiveDate(kotlin/Boolean): #A // com.apollographql.cache.normalized/storeReceiveDate|storeReceiveDate@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ApolloStore.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ApolloStore.kt index cf0d6539..d498dbb8 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ApolloStore.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ApolloStore.kt @@ -6,6 +6,7 @@ import com.apollographql.apollo.api.Executable import com.apollographql.apollo.api.Fragment import com.apollographql.apollo.api.Operation import com.apollographql.apollo.api.json.JsonNumber +import com.apollographql.apollo.ast.GQLDocument import com.apollographql.apollo.interceptor.ApolloInterceptor import com.apollographql.cache.normalized.api.CacheHeaders import com.apollographql.cache.normalized.api.CacheKey @@ -80,12 +81,13 @@ interface ApolloStore { * This is a synchronous operation that might block if the underlying cache is doing IO. * * @param operation the operation to read + * @param schema the schema to use for reading the operation * * @throws [com.apollographql.apollo.exception.ApolloException] on cache read errors */ suspend fun readOperationPartial( operation: Operation, - schema: String, + schema: GQLDocument, customScalarAdapters: CustomScalarAdapters = CustomScalarAdapters.Empty, cacheHeaders: CacheHeaders = CacheHeaders.NONE, ): ApolloResponse diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ClientCacheExtensions.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ClientCacheExtensions.kt index dd061a83..c7edc7f6 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ClientCacheExtensions.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ClientCacheExtensions.kt @@ -14,6 +14,8 @@ import com.apollographql.apollo.api.Mutation import com.apollographql.apollo.api.Operation import com.apollographql.apollo.api.Query import com.apollographql.apollo.api.http.get +import com.apollographql.apollo.ast.GQLDocument +import com.apollographql.apollo.ast.toGQLDocument import com.apollographql.apollo.exception.ApolloException import com.apollographql.apollo.exception.CacheMissException import com.apollographql.apollo.interceptor.ApolloInterceptor @@ -282,6 +284,19 @@ fun MutableExecutionOptions.retrievePartialResponses(retrievePartialRespo RetrievePartialResponsesContext(retrievePartialResponses) ) +/** + * @param schema The schema to use when reading the cache with partial results. + */ +fun MutableExecutionOptions.schema(schema: GQLDocument) = addExecutionContext( + SchemaContext(schema) +) + +/** + * @param schema The schema to use when reading the cache with partial results. + */ +fun MutableExecutionOptions.schema(schema: String) = schema(schema.toGQLDocument()) + + /** * @param storeExpirationDate Whether to store the expiration date in the cache. * @@ -418,6 +433,9 @@ internal val ApolloRequest.watchContext: WatchContext? internal val ApolloRequest.retrievePartialResponses get() = executionContext[RetrievePartialResponsesContext]?.value ?: false +internal val ApolloRequest.schema: GQLDocument? + get() = executionContext[SchemaContext]?.value + class CacheInfo private constructor( val cacheStartMillis: Long, @@ -644,6 +662,14 @@ internal class RetrievePartialResponsesContext(val value: Boolean) : ExecutionCo companion object Key : ExecutionContext.Key } +internal class SchemaContext(val value: GQLDocument) : ExecutionContext.Element { + override val key: ExecutionContext.Key<*> + get() = Key + + companion object Key : ExecutionContext.Key +} + + internal fun ApolloRequest.Builder.fetchFromCache(fetchFromCache: Boolean) = apply { addExecutionContext(FetchFromCacheContext(fetchFromCache)) } diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/ApolloCacheInterceptor.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/ApolloCacheInterceptor.kt index d6234407..539dfa49 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/ApolloCacheInterceptor.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/ApolloCacheInterceptor.kt @@ -27,6 +27,7 @@ import com.apollographql.cache.normalized.fetchFromCache import com.apollographql.cache.normalized.memoryCacheOnly import com.apollographql.cache.normalized.optimisticData import com.apollographql.cache.normalized.retrievePartialResponses +import com.apollographql.cache.normalized.schema import com.apollographql.cache.normalized.storePartialResponses import com.apollographql.cache.normalized.storeReceiveDate import com.apollographql.cache.normalized.writeToCacheAsynchronously @@ -225,7 +226,7 @@ internal class ApolloCacheInterceptor( val startMillis = currentTimeMillis() val response = store.readOperationPartial( operation = request.operation, - schema = cacheHeaders.headerValue("schema")!!, // TODO + schema = request.schema ?: error("schema is required for partial responses"), customScalarAdapters = customScalarAdapters, cacheHeaders = cacheHeaders, ) diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt index a93b41e2..3706edc2 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt @@ -8,6 +8,7 @@ import com.apollographql.apollo.api.Fragment import com.apollographql.apollo.api.Operation import com.apollographql.apollo.api.json.jsonReader import com.apollographql.apollo.api.variables +import com.apollographql.apollo.ast.GQLDocument import com.apollographql.apollo.execution.ExecutableSchema import com.apollographql.apollo.execution.GraphQLRequest import com.apollographql.apollo.execution.GraphQLResponse @@ -139,7 +140,7 @@ internal class DefaultApolloStore( override suspend fun readOperationPartial( operation: Operation, - schema: String, + schema: GQLDocument, customScalarAdapters: CustomScalarAdapters, cacheHeaders: CacheHeaders, ): ApolloResponse { diff --git a/tests/partial-results/build.gradle.kts b/tests/partial-results/build.gradle.kts index 70b43a0f..fd9524a5 100644 --- a/tests/partial-results/build.gradle.kts +++ b/tests/partial-results/build.gradle.kts @@ -38,5 +38,10 @@ kotlin { apollo { service("service") { packageName.set("test") + + plugin("com.apollographql.cache:normalized-cache-apollo-compiler-plugin") { + argument("packageName", packageName.get()) + argument("generateSchema", true) + } } } diff --git a/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt b/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt index 8c3a7082..9bcdaf30 100644 --- a/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt +++ b/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt @@ -6,22 +6,21 @@ import com.apollographql.apollo.api.Error.Location import com.apollographql.apollo.testing.internal.runTest import com.apollographql.cache.normalized.ApolloStore import com.apollographql.cache.normalized.FetchPolicy -import com.apollographql.cache.normalized.api.CacheHeaders import com.apollographql.cache.normalized.api.CacheKey import com.apollographql.cache.normalized.api.IdCacheKeyGenerator import com.apollographql.cache.normalized.api.IdCacheKeyResolver -import com.apollographql.cache.normalized.api.NormalizedCache import com.apollographql.cache.normalized.apolloStore -import com.apollographql.cache.normalized.cacheHeaders import com.apollographql.cache.normalized.fetchPolicy import com.apollographql.cache.normalized.memory.MemoryCacheFactory import com.apollographql.cache.normalized.normalizedCache import com.apollographql.cache.normalized.retrievePartialResponses +import com.apollographql.cache.normalized.schema import com.apollographql.cache.normalized.store import com.apollographql.cache.normalized.storePartialResponses import com.apollographql.mockserver.MockServer import com.apollographql.mockserver.enqueueString import okio.use +import test.cache.Schema import kotlin.test.Test import kotlin.test.assertContentEquals import kotlin.test.assertEquals @@ -59,11 +58,8 @@ class CachePartialResultTest { ApolloClient.Builder() .serverUrl(mockServer.url()) .normalizedCache(MemoryCacheFactory()) - .cacheHeaders(CacheHeaders.builder() - .addHeader("schema", SCHEMA) - .build() - ) .retrievePartialResponses(true) + .schema(Schema.schema) .build() .use { apolloClient -> val networkResult = apolloClient.query(MeWithoutNickNameWithEmailQuery()) @@ -160,10 +156,6 @@ class CachePartialResultTest { ) ApolloClient.Builder() .serverUrl(mockServer.url()) - .cacheHeaders(CacheHeaders.builder() - .addHeader("schema", SCHEMA) - .build() - ) .store( ApolloStore( normalizedCacheFactory = MemoryCacheFactory(), @@ -172,6 +164,7 @@ class CachePartialResultTest { ) ) .retrievePartialResponses(true) + .schema(Schema.schema) .build() .use { apolloClient -> val networkResult = apolloClient.query(UsersQuery(listOf("1", "2", "3"))) @@ -262,11 +255,8 @@ class CachePartialResultTest { ApolloClient.Builder() .serverUrl(mockServer.url()) .normalizedCache(MemoryCacheFactory()) - .cacheHeaders(CacheHeaders.builder() - .addHeader("schema", SCHEMA) - .build() - ) .retrievePartialResponses(true) + .schema(Schema.schema) .build() .use { apolloClient -> // Prime the cache @@ -437,11 +427,8 @@ class CachePartialResultTest { cacheResolver = IdCacheKeyResolver() ) ) - .cacheHeaders(CacheHeaders.builder() - .addHeader("schema", SCHEMA) - .build() - ) .retrievePartialResponses(true) + .schema(Schema.schema) .build() .use { apolloClient -> val networkResult = apolloClient.query(DefaultProjectQuery()) @@ -463,8 +450,6 @@ class CachePartialResultTest { networkResult.data ) - println(NormalizedCache.prettifyDump(apolloClient.apolloStore.dump())) - val cacheResult = apolloClient.query(DefaultProjectQuery()) .fetchPolicy(FetchPolicy.CacheOnly) .execute() @@ -476,33 +461,6 @@ class CachePartialResultTest { } } -private const val SCHEMA = """ -type Query { - me: User! - users(ids: [ID!]!): [User]! - project(id: ID! = "42"): Project -} - -type User { - id: ID! - firstName: String! - lastName: String! - nickName: String - email: String! - bestFriend: User - projects: [Project!]! - mainProject: Project! -} - -type Project { - id: ID! - name: String! - description: String - lead: User - users: [User!]! -} -""" - /** * Helps using assertEquals. */ From a6d1d39105f61fe8b00aa30a36a8d9915715bc4c Mon Sep 17 00:00:00 2001 From: BoD Date: Thu, 30 Jan 2025 14:35:42 +0100 Subject: [PATCH 04/11] Simplify ApolloStore --- .../api/normalized-cache-incubating.api | 8 +- .../api/normalized-cache-incubating.klib.api | 5 +- normalized-cache-incubating/build.gradle.kts | 1 + .../cache/normalized/ApolloStore.kt | 33 +++----- .../cache/normalized/ClientCacheExtensions.kt | 16 ++-- .../api/OperationCacheExtensions.kt | 12 +-- .../internal/ApolloCacheInterceptor.kt | 77 ++--------------- .../normalized/internal/CacheBatchReader.kt | 8 +- .../normalized/internal/DefaultApolloStore.kt | 83 ++++++++++++++----- .../kotlin/com/example/NormalizationTest.kt | 2 +- .../kotlin/circular/CircularCacheReadTest.kt | 2 +- .../declarativecache/DeclarativeCacheTest.kt | 12 +-- .../kotlin/test/CachePartialResultTest.kt | 10 +-- 13 files changed, 116 insertions(+), 153 deletions(-) diff --git a/normalized-cache-incubating/api/normalized-cache-incubating.api b/normalized-cache-incubating/api/normalized-cache-incubating.api index 32983621..1c78480d 100644 --- a/normalized-cache-incubating/api/normalized-cache-incubating.api +++ b/normalized-cache-incubating/api/normalized-cache-incubating.api @@ -8,8 +8,7 @@ public abstract interface class com/apollographql/cache/normalized/ApolloStore { public abstract fun normalize (Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/api/Operation$Data;Lcom/apollographql/apollo/api/CustomScalarAdapters;)Ljava/util/Map; public abstract fun publish (Ljava/util/Set;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun readFragment (Lcom/apollographql/apollo/api/Fragment;Lcom/apollographql/cache/normalized/api/CacheKey;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;)Lcom/apollographql/cache/normalized/ApolloStore$ReadResult; - public abstract fun readOperation (Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;)Lcom/apollographql/cache/normalized/ApolloStore$ReadResult; - public abstract fun readOperationPartial (Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/ast/GQLDocument;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun readOperation (Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;ZLcom/apollographql/apollo/ast/GQLDocument;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun remove (Lcom/apollographql/cache/normalized/api/CacheKey;Z)Z public abstract fun remove (Ljava/util/List;Z)I public abstract fun rollbackOptimisticUpdates (Ljava/util/UUID;)Ljava/util/Set; @@ -25,8 +24,7 @@ public final class com/apollographql/cache/normalized/ApolloStore$Companion { public final class com/apollographql/cache/normalized/ApolloStore$DefaultImpls { public static synthetic fun readFragment$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/apollo/api/Fragment;Lcom/apollographql/cache/normalized/api/CacheKey;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;ILjava/lang/Object;)Lcom/apollographql/cache/normalized/ApolloStore$ReadResult; - public static synthetic fun readOperation$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;ILjava/lang/Object;)Lcom/apollographql/cache/normalized/ApolloStore$ReadResult; - public static synthetic fun readOperationPartial$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/ast/GQLDocument;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; + public static synthetic fun readOperation$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;ZLcom/apollographql/apollo/ast/GQLDocument;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; public static synthetic fun remove$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/cache/normalized/api/CacheKey;ZILjava/lang/Object;)Z public static synthetic fun remove$default (Lcom/apollographql/cache/normalized/ApolloStore;Ljava/util/List;ZILjava/lang/Object;)I public static synthetic fun writeFragment$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/apollo/api/Fragment;Lcom/apollographql/cache/normalized/api/CacheKey;Lcom/apollographql/apollo/api/Fragment$Data;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;ILjava/lang/Object;)Ljava/util/Set; @@ -155,7 +153,7 @@ public final class com/apollographql/cache/normalized/NormalizedCache { public static final fun optimisticUpdates (Lcom/apollographql/apollo/api/ApolloRequest$Builder;Lcom/apollographql/apollo/api/Mutation$Data;)Lcom/apollographql/apollo/api/ApolloRequest$Builder; public static final fun refetchPolicy (Lcom/apollographql/apollo/api/MutableExecutionOptions;Lcom/apollographql/cache/normalized/FetchPolicy;)Ljava/lang/Object; public static final fun refetchPolicyInterceptor (Lcom/apollographql/apollo/api/MutableExecutionOptions;Lcom/apollographql/apollo/interceptor/ApolloInterceptor;)Ljava/lang/Object; - public static final fun retrievePartialResponses (Lcom/apollographql/apollo/api/MutableExecutionOptions;Z)Ljava/lang/Object; + public static final fun returnPartialResponses (Lcom/apollographql/apollo/api/MutableExecutionOptions;Z)Ljava/lang/Object; public static final fun schema (Lcom/apollographql/apollo/api/MutableExecutionOptions;Lcom/apollographql/apollo/ast/GQLDocument;)Ljava/lang/Object; public static final fun schema (Lcom/apollographql/apollo/api/MutableExecutionOptions;Ljava/lang/String;)Ljava/lang/Object; public static final fun store (Lcom/apollographql/apollo/ApolloClient$Builder;Lcom/apollographql/cache/normalized/ApolloStore;Z)Lcom/apollographql/apollo/ApolloClient$Builder; diff --git a/normalized-cache-incubating/api/normalized-cache-incubating.klib.api b/normalized-cache-incubating/api/normalized-cache-incubating.klib.api index a50578c1..0ad5e0b8 100644 --- a/normalized-cache-incubating/api/normalized-cache-incubating.klib.api +++ b/normalized-cache-incubating/api/normalized-cache-incubating.klib.api @@ -84,7 +84,6 @@ abstract interface com.apollographql.cache.normalized/ApolloStore { // com.apoll abstract fun <#A1: com.apollographql.apollo.api/Fragment.Data> writeFragment(com.apollographql.apollo.api/Fragment<#A1>, com.apollographql.cache.normalized.api/CacheKey, #A1, com.apollographql.apollo.api/CustomScalarAdapters = ..., com.apollographql.cache.normalized.api/CacheHeaders = ...): kotlin.collections/Set // com.apollographql.cache.normalized/ApolloStore.writeFragment|writeFragment(com.apollographql.apollo.api.Fragment<0:0>;com.apollographql.cache.normalized.api.CacheKey;0:0;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheHeaders){0§}[0] abstract fun <#A1: com.apollographql.apollo.api/Fragment.Data> writeOptimisticUpdates(com.apollographql.apollo.api/Fragment<#A1>, com.apollographql.cache.normalized.api/CacheKey, #A1, com.benasher44.uuid/Uuid, com.apollographql.apollo.api/CustomScalarAdapters = ...): kotlin.collections/Set // com.apollographql.cache.normalized/ApolloStore.writeOptimisticUpdates|writeOptimisticUpdates(com.apollographql.apollo.api.Fragment<0:0>;com.apollographql.cache.normalized.api.CacheKey;0:0;com.benasher44.uuid.Uuid;com.apollographql.apollo.api.CustomScalarAdapters){0§}[0] abstract fun <#A1: com.apollographql.apollo.api/Operation.Data> normalize(com.apollographql.apollo.api/Operation<#A1>, #A1, com.apollographql.apollo.api/CustomScalarAdapters): kotlin.collections/Map // com.apollographql.cache.normalized/ApolloStore.normalize|normalize(com.apollographql.apollo.api.Operation<0:0>;0:0;com.apollographql.apollo.api.CustomScalarAdapters){0§}[0] - abstract fun <#A1: com.apollographql.apollo.api/Operation.Data> readOperation(com.apollographql.apollo.api/Operation<#A1>, com.apollographql.apollo.api/CustomScalarAdapters = ..., com.apollographql.cache.normalized.api/CacheHeaders = ...): com.apollographql.cache.normalized/ApolloStore.ReadResult<#A1> // com.apollographql.cache.normalized/ApolloStore.readOperation|readOperation(com.apollographql.apollo.api.Operation<0:0>;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheHeaders){0§}[0] abstract fun <#A1: com.apollographql.apollo.api/Operation.Data> writeOperation(com.apollographql.apollo.api/Operation<#A1>, #A1, com.apollographql.apollo.api/CustomScalarAdapters = ..., com.apollographql.cache.normalized.api/CacheHeaders = ...): kotlin.collections/Set // com.apollographql.cache.normalized/ApolloStore.writeOperation|writeOperation(com.apollographql.apollo.api.Operation<0:0>;0:0;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheHeaders){0§}[0] abstract fun <#A1: com.apollographql.apollo.api/Operation.Data> writeOptimisticUpdates(com.apollographql.apollo.api/Operation<#A1>, #A1, com.benasher44.uuid/Uuid, com.apollographql.apollo.api/CustomScalarAdapters = ...): kotlin.collections/Set // com.apollographql.cache.normalized/ApolloStore.writeOptimisticUpdates|writeOptimisticUpdates(com.apollographql.apollo.api.Operation<0:0>;0:0;com.benasher44.uuid.Uuid;com.apollographql.apollo.api.CustomScalarAdapters){0§}[0] abstract fun <#A1: kotlin/Any?> accessCache(kotlin/Function1): #A1 // com.apollographql.cache.normalized/ApolloStore.accessCache|accessCache(kotlin.Function1){0§}[0] @@ -94,7 +93,7 @@ abstract interface com.apollographql.cache.normalized/ApolloStore { // com.apoll abstract fun remove(com.apollographql.cache.normalized.api/CacheKey, kotlin/Boolean = ...): kotlin/Boolean // com.apollographql.cache.normalized/ApolloStore.remove|remove(com.apollographql.cache.normalized.api.CacheKey;kotlin.Boolean){}[0] abstract fun remove(kotlin.collections/List, kotlin/Boolean = ...): kotlin/Int // com.apollographql.cache.normalized/ApolloStore.remove|remove(kotlin.collections.List;kotlin.Boolean){}[0] abstract fun rollbackOptimisticUpdates(com.benasher44.uuid/Uuid): kotlin.collections/Set // com.apollographql.cache.normalized/ApolloStore.rollbackOptimisticUpdates|rollbackOptimisticUpdates(com.benasher44.uuid.Uuid){}[0] - abstract suspend fun <#A1: com.apollographql.apollo.api/Operation.Data> readOperationPartial(com.apollographql.apollo.api/Operation<#A1>, com.apollographql.apollo.ast/GQLDocument, com.apollographql.apollo.api/CustomScalarAdapters = ..., com.apollographql.cache.normalized.api/CacheHeaders = ...): com.apollographql.apollo.api/ApolloResponse<#A1> // com.apollographql.cache.normalized/ApolloStore.readOperationPartial|readOperationPartial(com.apollographql.apollo.api.Operation<0:0>;com.apollographql.apollo.ast.GQLDocument;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheHeaders){0§}[0] + abstract suspend fun <#A1: com.apollographql.apollo.api/Operation.Data> readOperation(com.apollographql.apollo.api/Operation<#A1>, com.apollographql.apollo.api/CustomScalarAdapters = ..., com.apollographql.cache.normalized.api/CacheHeaders = ..., kotlin/Boolean = ..., com.apollographql.apollo.ast/GQLDocument? = ...): com.apollographql.apollo.api/ApolloResponse<#A1> // com.apollographql.cache.normalized/ApolloStore.readOperation|readOperation(com.apollographql.apollo.api.Operation<0:0>;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheHeaders;kotlin.Boolean;com.apollographql.apollo.ast.GQLDocument?){0§}[0] abstract suspend fun publish(kotlin.collections/Set) // com.apollographql.cache.normalized/ApolloStore.publish|publish(kotlin.collections.Set){}[0] final class <#A1: com.apollographql.apollo.api/Executable.Data> ReadResult { // com.apollographql.cache.normalized/ApolloStore.ReadResult|null[0] @@ -573,7 +572,7 @@ final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOption final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/memoryCacheOnly(kotlin/Boolean): #A // com.apollographql.cache.normalized/memoryCacheOnly|memoryCacheOnly@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/refetchPolicy(com.apollographql.cache.normalized/FetchPolicy): #A // com.apollographql.cache.normalized/refetchPolicy|refetchPolicy@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(com.apollographql.cache.normalized.FetchPolicy){0§}[0] final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/refetchPolicyInterceptor(com.apollographql.apollo.interceptor/ApolloInterceptor): #A // com.apollographql.cache.normalized/refetchPolicyInterceptor|refetchPolicyInterceptor@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(com.apollographql.apollo.interceptor.ApolloInterceptor){0§}[0] -final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/retrievePartialResponses(kotlin/Boolean): #A // com.apollographql.cache.normalized/retrievePartialResponses|retrievePartialResponses@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] +final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/returnPartialResponses(kotlin/Boolean): #A // com.apollographql.cache.normalized/returnPartialResponses|returnPartialResponses@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/schema(com.apollographql.apollo.ast/GQLDocument): #A // com.apollographql.cache.normalized/schema|schema@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(com.apollographql.apollo.ast.GQLDocument){0§}[0] final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/schema(kotlin/String): #A // com.apollographql.cache.normalized/schema|schema@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.String){0§}[0] final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/storeExpirationDate(kotlin/Boolean): #A // com.apollographql.cache.normalized/storeExpirationDate|storeExpirationDate@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] diff --git a/normalized-cache-incubating/build.gradle.kts b/normalized-cache-incubating/build.gradle.kts index 03e1c8ed..4b7bb87b 100644 --- a/normalized-cache-incubating/build.gradle.kts +++ b/normalized-cache-incubating/build.gradle.kts @@ -23,6 +23,7 @@ kotlin { api(libs.uuid) implementation(libs.atomicfu.library) implementation(libs.apollo.execution) + api(libs.apollo.ast) } } diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ApolloStore.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ApolloStore.kt index d498dbb8..d3879aba 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ApolloStore.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ApolloStore.kt @@ -58,38 +58,25 @@ interface ApolloStore { /** * Reads an operation from the store. * - * This is a synchronous operation that might block if the underlying cache is doing IO. - * - * @param operation the operation to read + * When [returnPartialResponses] is `false`, in case of missing data the returned [ApolloResponse.data] is `null` and + * [ApolloResponse.exception] is a [com.apollographql.apollo.exception.CacheMissException]. * - * @throws [com.apollographql.apollo.exception.CacheMissException] on cache miss - * @throws [com.apollographql.apollo.exception.ApolloException] on other cache read errors - * - * @return the operation data with optional headers from the [NormalizedCache] - */ - fun readOperation( - operation: Operation, - customScalarAdapters: CustomScalarAdapters = CustomScalarAdapters.Empty, - cacheHeaders: CacheHeaders = CacheHeaders.NONE, - ): ReadResult - - /** - * Reads an operation from the store, returning only the present data. - * Missing fields are returned as `null` if their type is nullable, bubbling up to their parent otherwise. - * When a field is missing, a corresponding [com.apollographql.apollo.api.Error] is present in [ApolloResponse.errors]. + * When [returnPartialResponses] is `true`, the returned [ApolloResponse.data] has `null` values for any missing fields if their + * type is nullable, bubbling up to their parent otherwise. Missing fields have a corresponding [com.apollographql.apollo.api.Error] + * in [ApolloResponse.errors]. A [schema] must be provided to read partial responses. * * This is a synchronous operation that might block if the underlying cache is doing IO. * * @param operation the operation to read - * @param schema the schema to use for reading the operation - * - * @throws [com.apollographql.apollo.exception.ApolloException] on cache read errors + * @param returnPartialResponses whether to return partial responses + * @param schema the schema to use for reading the operation - required when [returnPartialResponses] is `true` */ - suspend fun readOperationPartial( + suspend fun readOperation( operation: Operation, - schema: GQLDocument, customScalarAdapters: CustomScalarAdapters = CustomScalarAdapters.Empty, cacheHeaders: CacheHeaders = CacheHeaders.NONE, + returnPartialResponses: Boolean = false, + schema: GQLDocument? = null, ): ApolloResponse /** diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ClientCacheExtensions.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ClientCacheExtensions.kt index c7edc7f6..e2571224 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ClientCacheExtensions.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ClientCacheExtensions.kt @@ -275,13 +275,13 @@ fun MutableExecutionOptions.storeReceiveDate(storeReceiveDate: Boolean) = ) /** - * @param retrievePartialResponses Whether to return partial data from the cache (`true`), or no data with a [CacheMissException] whenever a field + * @param returnPartialResponses Whether to return partial data from the cache (`true`), or no data with a [CacheMissException] whenever a field * is missing (`false`). * * Default: false */ -fun MutableExecutionOptions.retrievePartialResponses(retrievePartialResponses: Boolean) = addExecutionContext( - RetrievePartialResponsesContext(retrievePartialResponses) +fun MutableExecutionOptions.returnPartialResponses(returnPartialResponses: Boolean) = addExecutionContext( + ReturnPartialResponsesContext(returnPartialResponses) ) /** @@ -430,8 +430,8 @@ internal val ExecutionOptions.cacheHeaders: CacheHeaders internal val ApolloRequest.watchContext: WatchContext? get() = executionContext[WatchContext] -internal val ApolloRequest.retrievePartialResponses - get() = executionContext[RetrievePartialResponsesContext]?.value ?: false +internal val ApolloRequest.returnPartialResponses + get() = executionContext[ReturnPartialResponsesContext]?.value ?: false internal val ApolloRequest.schema: GQLDocument? get() = executionContext[SchemaContext]?.value @@ -456,7 +456,7 @@ class CacheInfo private constructor( /** * The exception that occurred while reading the cache. * Always `null` if [isFromCache] is false, or when partial responses are enabled. - * @see MutableExecutionOptions.retrievePartialResponses + * @see MutableExecutionOptions.returnPartialResponses */ val cacheMissException: CacheMissException?, @@ -655,11 +655,11 @@ internal class FetchFromCacheContext(val value: Boolean) : ExecutionContext.Elem companion object Key : ExecutionContext.Key } -internal class RetrievePartialResponsesContext(val value: Boolean) : ExecutionContext.Element { +internal class ReturnPartialResponsesContext(val value: Boolean) : ExecutionContext.Element { override val key: ExecutionContext.Key<*> get() = Key - companion object Key : ExecutionContext.Key + companion object Key : ExecutionContext.Key } internal class SchemaContext(val value: GQLDocument) : ExecutionContext.Element { diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/api/OperationCacheExtensions.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/api/OperationCacheExtensions.kt index 839bee7c..47e1ad28 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/api/OperationCacheExtensions.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/api/OperationCacheExtensions.kt @@ -53,7 +53,7 @@ fun Executable.readDataFromCache( cacheHeaders = cacheHeaders, variables = variables, fieldKeyGenerator = fieldKeyGenerator, - retrievePartialResponses = false, + returnPartialResponses = false, ).toData(adapter(), customScalarAdapters, variables) } @@ -74,7 +74,7 @@ fun Executable.readDataFromCache( cacheHeaders = cacheHeaders, variables = variables, fieldKeyGenerator = fieldKeyGenerator, - retrievePartialResponses = false, + returnPartialResponses = false, ).toData(adapter(), customScalarAdapters, variables) } @@ -85,7 +85,7 @@ internal fun Executable.readDataFromCacheInternal( cacheHeaders: CacheHeaders, variables: Executable.Variables, fieldKeyGenerator: FieldKeyGenerator, - retrievePartialResponses: Boolean, + returnPartialResponses: Boolean, ): CacheBatchReaderData = readInternal( cacheKey = cacheKey, cache = cache, @@ -93,7 +93,7 @@ internal fun Executable.readDataFromCacheInternal( cacheHeaders = cacheHeaders, variables = variables, fieldKeyGenerator = fieldKeyGenerator, - retrievePartialResponses = retrievePartialResponses, + returnPartialResponses = returnPartialResponses, ) @@ -104,7 +104,7 @@ private fun Executable.readInternal( cacheHeaders: CacheHeaders, variables: Executable.Variables, fieldKeyGenerator: FieldKeyGenerator, - retrievePartialResponses: Boolean, + returnPartialResponses: Boolean, ): CacheBatchReaderData { return CacheBatchReader( cache = cache, @@ -115,7 +115,7 @@ private fun Executable.readInternal( rootSelections = rootField().selections, rootField = rootField(), fieldKeyGenerator = fieldKeyGenerator, - retrievePartialResponses = retrievePartialResponses, + returnPartialResponses = returnPartialResponses, ).collectData() } diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/ApolloCacheInterceptor.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/ApolloCacheInterceptor.kt index 539dfa49..97dbc74b 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/ApolloCacheInterceptor.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/ApolloCacheInterceptor.kt @@ -9,7 +9,6 @@ import com.apollographql.apollo.api.Operation import com.apollographql.apollo.api.Query import com.apollographql.apollo.api.Subscription import com.apollographql.apollo.exception.ApolloException -import com.apollographql.apollo.exception.CacheMissException import com.apollographql.apollo.exception.DefaultApolloException import com.apollographql.apollo.exception.apolloExceptionHandler import com.apollographql.apollo.interceptor.ApolloInterceptor @@ -26,7 +25,7 @@ import com.apollographql.cache.normalized.doNotStore import com.apollographql.cache.normalized.fetchFromCache import com.apollographql.cache.normalized.memoryCacheOnly import com.apollographql.cache.normalized.optimisticData -import com.apollographql.cache.normalized.retrievePartialResponses +import com.apollographql.cache.normalized.returnPartialResponses import com.apollographql.cache.normalized.schema import com.apollographql.cache.normalized.storePartialResponses import com.apollographql.cache.normalized.storeReceiveDate @@ -211,92 +210,28 @@ internal class ApolloCacheInterceptor( if (request.memoryCacheOnly) { cacheHeaders += CacheHeaders.Builder().addHeader(ApolloCacheHeaders.MEMORY_CACHE_ONLY, "true").build() } - return if (request.retrievePartialResponses) { - readFromCachePartial(request, customScalarAdapters, cacheHeaders) - } else { - readFromCacheThrowCacheMiss(request, customScalarAdapters, cacheHeaders) - } - } - - private suspend fun readFromCachePartial( - request: ApolloRequest, - customScalarAdapters: CustomScalarAdapters, - cacheHeaders: CacheHeaders, - ): ApolloResponse { val startMillis = currentTimeMillis() - val response = store.readOperationPartial( + val returnPartialResponses = request.returnPartialResponses + val response = store.readOperation( operation = request.operation, - schema = request.schema ?: error("schema is required for partial responses"), customScalarAdapters = customScalarAdapters, cacheHeaders = cacheHeaders, + returnPartialResponses = returnPartialResponses, + schema = if (returnPartialResponses) request.schema ?: error("schema is required for partial responses") else null, ) return response.newBuilder() .requestUuid(request.requestUuid) - .cacheInfo( - response.cacheInfo!!.newBuilder() - .cacheStartMillis(startMillis) - .cacheEndMillis(currentTimeMillis()) - .build() - ) - .isLast(true) - .build() - } - - private fun readFromCacheThrowCacheMiss( - request: ApolloRequest, - customScalarAdapters: CustomScalarAdapters, - cacheHeaders: CacheHeaders, - ): ApolloResponse { - val operation = request.operation - val startMillis = currentTimeMillis() - val readResult = try { - store.readOperation( - operation = operation, - customScalarAdapters = customScalarAdapters, - cacheHeaders = cacheHeaders, - ) - } catch (e: CacheMissException) { - return ApolloResponse.Builder( - requestUuid = request.requestUuid, - operation = operation, - ) - .exception(e) - .addExecutionContext(request.executionContext) - .cacheInfo( - CacheInfo.Builder() - .cacheStartMillis(startMillis) - .cacheEndMillis(currentTimeMillis()) - .fromCache(true) - .cacheHit(false) - .cacheMissException(e) - .stale(e.stale) - .build() - ) - .isLast(true) - .build() - } - - return ApolloResponse.Builder( - requestUuid = request.requestUuid, - operation = operation, - ) - .data(readResult.data) .addExecutionContext(request.executionContext) - .cacheHeaders(readResult.cacheHeaders) .cacheInfo( - CacheInfo.Builder() + response.cacheInfo!!.newBuilder() .cacheStartMillis(startMillis) .cacheEndMillis(currentTimeMillis()) - .fromCache(true) - .cacheHit(true) - .stale(readResult.cacheHeaders.headerValue(ApolloCacheHeaders.STALE) == "true") .build() ) .isLast(true) .build() } - private fun readFromNetwork( request: ApolloRequest, chain: ApolloInterceptorChain, diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/CacheBatchReader.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/CacheBatchReader.kt index 180d56b6..43d3fad7 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/CacheBatchReader.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/CacheBatchReader.kt @@ -32,7 +32,7 @@ internal class CacheBatchReader( private val rootSelections: List, private val rootField: CompiledField, private val fieldKeyGenerator: FieldKeyGenerator, - private val retrievePartialResponses: Boolean, + private val returnPartialResponses: Boolean, ) { /** * @param key: the key of the record we need to fetch @@ -116,7 +116,7 @@ internal class CacheBatchReader( // This happens the very first time we read the cache record = Record(pendingReference.key, emptyMap()) } else { - if (retrievePartialResponses) { + if (returnPartialResponses) { data[pendingReference.path] = cacheMissError(key = pendingReference.key, fieldName = null, stale = false, path = pendingReference.path) return@forEach @@ -148,7 +148,7 @@ internal class CacheBatchReader( ) ).unwrap() } catch (e: CacheMissException) { - if (retrievePartialResponses) { + if (returnPartialResponses) { cacheMissError(e, pendingReference.path + it.responseName) } else { throw e @@ -232,7 +232,7 @@ internal class CacheBatchReader( ) ).unwrap() } catch (e: CacheMissException) { - if (retrievePartialResponses) { + if (returnPartialResponses) { cacheMissError(e, path + it.responseName) } else { throw e diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt index 3706edc2..7d478f28 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt @@ -9,6 +9,7 @@ import com.apollographql.apollo.api.Operation import com.apollographql.apollo.api.json.jsonReader import com.apollographql.apollo.api.variables import com.apollographql.apollo.ast.GQLDocument +import com.apollographql.apollo.exception.CacheMissException import com.apollographql.apollo.execution.ExecutableSchema import com.apollographql.apollo.execution.GraphQLRequest import com.apollographql.apollo.execution.GraphQLResponse @@ -29,6 +30,7 @@ import com.apollographql.cache.normalized.api.Record import com.apollographql.cache.normalized.api.RecordMerger import com.apollographql.cache.normalized.api.normalize import com.apollographql.cache.normalized.api.readDataFromCacheInternal +import com.apollographql.cache.normalized.cacheHeaders import com.apollographql.cache.normalized.cacheInfo import com.benasher44.uuid.Uuid import com.benasher44.uuid.uuid4 @@ -117,28 +119,68 @@ internal class DefaultApolloStore( ) } - override fun readOperation( + override suspend fun readOperation( operation: Operation, customScalarAdapters: CustomScalarAdapters, cacheHeaders: CacheHeaders, - ): ReadResult { - val variables = operation.variables(customScalarAdapters, true) - val batchReaderData = operation.readDataFromCacheInternal( - cache = cache, - cacheResolver = cacheResolver, - cacheHeaders = cacheHeaders, - cacheKey = CacheKey.rootKey(), - variables = variables, - fieldKeyGenerator = fieldKeyGenerator, - retrievePartialResponses = false, - ) - return ReadResult( - data = batchReaderData.toData(operation.adapter(), customScalarAdapters, variables), - cacheHeaders = batchReaderData.cacheHeaders, - ) + returnPartialResponses: Boolean, + schema: GQLDocument?, + ): ApolloResponse { + return if (returnPartialResponses) { + readOperationPartial(operation, schema!!, customScalarAdapters, cacheHeaders) + } else { + readOperationThrowCacheMiss(operation, customScalarAdapters, cacheHeaders) + } } - override suspend fun readOperationPartial( + private fun readOperationThrowCacheMiss( + operation: Operation, + customScalarAdapters: CustomScalarAdapters, + cacheHeaders: CacheHeaders, + ): ApolloResponse { + return try { + val variables = operation.variables(customScalarAdapters, true) + val batchReaderData = operation.readDataFromCacheInternal( + cache = cache, + cacheResolver = cacheResolver, + cacheHeaders = cacheHeaders, + cacheKey = CacheKey.rootKey(), + variables = variables, + fieldKeyGenerator = fieldKeyGenerator, + returnPartialResponses = false, + ) + val readResult = ReadResult( + data = batchReaderData.toData(operation.adapter(), customScalarAdapters, variables), + cacheHeaders = batchReaderData.cacheHeaders, + ) + ApolloResponse.Builder(operation, uuid4()) + .data(readResult.data) + .cacheHeaders(readResult.cacheHeaders) + .cacheInfo( + CacheInfo.Builder() + .fromCache(true) + .cacheHit(true) + .stale(readResult.cacheHeaders.headerValue(ApolloCacheHeaders.STALE) == "true") + .build() + ) + .build() + } catch (e: CacheMissException) { + ApolloResponse.Builder(operation, uuid4()) + .data(null) + .exception(e) + .cacheInfo( + CacheInfo.Builder() + .fromCache(true) + .cacheHit(false) + .cacheMissException(e) + .stale(e.stale) + .build() + ) + .build() + } + } + + private suspend fun readOperationPartial( operation: Operation, schema: GQLDocument, customScalarAdapters: CustomScalarAdapters, @@ -152,7 +194,7 @@ internal class DefaultApolloStore( cacheKey = CacheKey.rootKey(), variables = variables, fieldKeyGenerator = fieldKeyGenerator, - retrievePartialResponses = true, + returnPartialResponses = true, ) val dataAsMapWithCacheMisses: Map = batchReaderData.toMap() val graphQLRequest = GraphQLRequest.Builder() @@ -175,11 +217,12 @@ internal class DefaultApolloStore( return ApolloResponse.Builder(operation, uuid4()) .data(data) .errors(graphQLResponse.errors) + .cacheHeaders(batchReaderData.cacheHeaders) .cacheInfo( CacheInfo.Builder() .fromCache(true) - .stale(batchReaderData.cacheHeaders.headerValue(ApolloCacheHeaders.STALE) == "true") .cacheHit(graphQLResponse.errors.isNullOrEmpty()) + .stale(batchReaderData.cacheHeaders.headerValue(ApolloCacheHeaders.STALE) == "true") .build() ) .build() @@ -227,7 +270,7 @@ internal class DefaultApolloStore( cacheKey = cacheKey, variables = variables, fieldKeyGenerator = fieldKeyGenerator, - retrievePartialResponses = false, + returnPartialResponses = false, ) return ReadResult( data = batchReaderData.toData(fragment.adapter(), customScalarAdapters, variables), diff --git a/tests/normalization-tests/src/commonTest/kotlin/com/example/NormalizationTest.kt b/tests/normalization-tests/src/commonTest/kotlin/com/example/NormalizationTest.kt index e9a4b9ce..f3023331 100644 --- a/tests/normalization-tests/src/commonTest/kotlin/com/example/NormalizationTest.kt +++ b/tests/normalization-tests/src/commonTest/kotlin/com/example/NormalizationTest.kt @@ -111,7 +111,7 @@ class NormalizationTest { ), ) - val data = apolloStore.readOperation(Issue2818Query()).data + val data = apolloStore.readOperation(Issue2818Query()).data!! assertEquals("section-name", data.home.sectionA?.name) assertEquals("section-id", data.home.sectionFragment.sectionA?.id) assertEquals("https://...", data.home.sectionFragment.sectionA?.imageUrl) diff --git a/tests/normalized-cache/src/commonTest/kotlin/circular/CircularCacheReadTest.kt b/tests/normalized-cache/src/commonTest/kotlin/circular/CircularCacheReadTest.kt index 909c9695..dce29384 100644 --- a/tests/normalized-cache/src/commonTest/kotlin/circular/CircularCacheReadTest.kt +++ b/tests/normalized-cache/src/commonTest/kotlin/circular/CircularCacheReadTest.kt @@ -30,7 +30,7 @@ class CircularCacheReadTest { ) store.writeOperation(operation, data) - val result = store.readOperation(operation, customScalarAdapters = CustomScalarAdapters.Empty).data + val result = store.readOperation(operation, customScalarAdapters = CustomScalarAdapters.Empty).data!! assertEquals("42", result.user.friend.id) } } diff --git a/tests/normalized-cache/src/commonTest/kotlin/declarativecache/DeclarativeCacheTest.kt b/tests/normalized-cache/src/commonTest/kotlin/declarativecache/DeclarativeCacheTest.kt index 5aa5a47a..8278084c 100644 --- a/tests/normalized-cache/src/commonTest/kotlin/declarativecache/DeclarativeCacheTest.kt +++ b/tests/normalized-cache/src/commonTest/kotlin/declarativecache/DeclarativeCacheTest.kt @@ -36,7 +36,7 @@ class DeclarativeCacheTest { store.writeOperation(otherOperation, otherData) // Get the "promo" book again, the title must be updated - val data = store.readOperation(promoOperation, CustomScalarAdapters.Empty).data + val data = store.readOperation(promoOperation, CustomScalarAdapters.Empty).data!! assertEquals("Other", data.promoBook?.title) } @@ -56,7 +56,7 @@ class DeclarativeCacheTest { store.writeOperation(otherOperation, otherData) // Get the "promo" library again, the address must be updated - val data = store.readOperation(promoOperation, CustomScalarAdapters.Empty).data + val data = store.readOperation(promoOperation, CustomScalarAdapters.Empty).data!! assertEquals("OtherAddress", data.promoLibrary?.address) } @@ -70,7 +70,7 @@ class DeclarativeCacheTest { store.writeOperation(bookQuery1, bookData1) val bookQuery2 = GetBookQuery("42") - val bookData2 = store.readOperation(bookQuery2, CustomScalarAdapters.Empty).data + val bookData2 = store.readOperation(bookQuery2, CustomScalarAdapters.Empty).data!! assertEquals("Promo", bookData2.book?.title) @@ -86,7 +86,7 @@ class DeclarativeCacheTest { store.writeOperation(authorQuery1, authorData1) val authorQuery2 = GetAuthorQuery("Pierre", "Bordage") - val authorData2 = store.readOperation(authorQuery2, CustomScalarAdapters.Empty).data + val authorData2 = store.readOperation(authorQuery2, CustomScalarAdapters.Empty).data!! assertEquals("Pierre", authorData2.author?.firstName) assertEquals("Bordage", authorData2.author?.lastName) @@ -117,13 +117,13 @@ class DeclarativeCacheTest { store.writeOperation(promoOperation, GetPromoBookQuery.Data(GetPromoBookQuery.PromoBook("Title4", "4", "Book"))) var operation = GetBooksQuery(listOf("4", "1")) - var data = store.readOperation(operation, CustomScalarAdapters.Empty).data + var data = store.readOperation(operation, CustomScalarAdapters.Empty).data!! assertEquals("Title4", data.books.get(0).title) assertEquals("Title1", data.books.get(1).title) operation = GetBooksQuery(listOf("3")) - data = store.readOperation(operation, CustomScalarAdapters.Empty).data + data = store.readOperation(operation, CustomScalarAdapters.Empty).data!! assertEquals("Title3", data.books.get(0).title) } diff --git a/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt b/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt index 9bcdaf30..2cc32483 100644 --- a/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt +++ b/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt @@ -13,7 +13,7 @@ import com.apollographql.cache.normalized.apolloStore import com.apollographql.cache.normalized.fetchPolicy import com.apollographql.cache.normalized.memory.MemoryCacheFactory import com.apollographql.cache.normalized.normalizedCache -import com.apollographql.cache.normalized.retrievePartialResponses +import com.apollographql.cache.normalized.returnPartialResponses import com.apollographql.cache.normalized.schema import com.apollographql.cache.normalized.store import com.apollographql.cache.normalized.storePartialResponses @@ -58,7 +58,7 @@ class CachePartialResultTest { ApolloClient.Builder() .serverUrl(mockServer.url()) .normalizedCache(MemoryCacheFactory()) - .retrievePartialResponses(true) + .returnPartialResponses(true) .schema(Schema.schema) .build() .use { apolloClient -> @@ -163,7 +163,7 @@ class CachePartialResultTest { cacheResolver = IdCacheKeyResolver() ) ) - .retrievePartialResponses(true) + .returnPartialResponses(true) .schema(Schema.schema) .build() .use { apolloClient -> @@ -255,7 +255,7 @@ class CachePartialResultTest { ApolloClient.Builder() .serverUrl(mockServer.url()) .normalizedCache(MemoryCacheFactory()) - .retrievePartialResponses(true) + .returnPartialResponses(true) .schema(Schema.schema) .build() .use { apolloClient -> @@ -427,7 +427,7 @@ class CachePartialResultTest { cacheResolver = IdCacheKeyResolver() ) ) - .retrievePartialResponses(true) + .returnPartialResponses(true) .schema(Schema.schema) .build() .use { apolloClient -> From 881d90e1c935a5fbd6af9097e6d936a7e266cc07 Mon Sep 17 00:00:00 2001 From: BoD Date: Thu, 30 Jan 2025 16:27:05 +0100 Subject: [PATCH 05/11] Make custom scalars work --- .../normalized/internal/DefaultApolloStore.kt | 18 ++++++ tests/partial-results/build.gradle.kts | 2 + .../src/commonMain/graphql/operation.graphql | 8 +++ .../src/commonMain/graphql/schema.graphqls | 4 ++ .../src/commonMain/kotlin/test/Category.kt | 35 +++++++++++ .../kotlin/test/CachePartialResultTest.kt | 58 +++++++++++++++++++ 6 files changed, 125 insertions(+) create mode 100644 tests/partial-results/src/commonMain/kotlin/test/Category.kt diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt index 7d478f28..206622a7 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt @@ -9,10 +9,13 @@ import com.apollographql.apollo.api.Operation import com.apollographql.apollo.api.json.jsonReader import com.apollographql.apollo.api.variables import com.apollographql.apollo.ast.GQLDocument +import com.apollographql.apollo.ast.GQLValue import com.apollographql.apollo.exception.CacheMissException +import com.apollographql.apollo.execution.Coercing import com.apollographql.apollo.execution.ExecutableSchema import com.apollographql.apollo.execution.GraphQLRequest import com.apollographql.apollo.execution.GraphQLResponse +import com.apollographql.apollo.execution.JsonValue import com.apollographql.cache.normalized.ApolloStore import com.apollographql.cache.normalized.ApolloStore.ReadResult import com.apollographql.cache.normalized.CacheInfo @@ -206,6 +209,7 @@ internal class DefaultApolloStore( .resolver { resolveInfo -> dataAsMapWithCacheMisses.valueAtPath(resolveInfo.path) } + .addCoercing("Category", PassThroughCoercing) .build() .execute(graphQLRequest, ExecutionContext.Empty) @@ -255,6 +259,20 @@ internal class DefaultApolloStore( return value } + private object PassThroughCoercing : Coercing { + override fun deserialize(value: JsonValue): Any? { + return value + } + + override fun parseLiteral(value: GQLValue): Any { + return value + } + + override fun serialize(internalValue: Any?): JsonValue { + return internalValue + } + } + override fun readFragment( fragment: Fragment, cacheKey: CacheKey, diff --git a/tests/partial-results/build.gradle.kts b/tests/partial-results/build.gradle.kts index fd9524a5..2af20c9b 100644 --- a/tests/partial-results/build.gradle.kts +++ b/tests/partial-results/build.gradle.kts @@ -43,5 +43,7 @@ apollo { argument("packageName", packageName.get()) argument("generateSchema", true) } + + mapScalar("Category", "test.Category", "test.CategoryAdapter") } } diff --git a/tests/partial-results/src/commonMain/graphql/operation.graphql b/tests/partial-results/src/commonMain/graphql/operation.graphql index 667cdab7..68fc9226 100644 --- a/tests/partial-results/src/commonMain/graphql/operation.graphql +++ b/tests/partial-results/src/commonMain/graphql/operation.graphql @@ -73,3 +73,11 @@ query DefaultProjectQuery($id: ID! = "42") { description } } + +query UserByCategoryQuery($category: Category!) { + user(category: $category) { + firstName + lastName + category + } +} diff --git a/tests/partial-results/src/commonMain/graphql/schema.graphqls b/tests/partial-results/src/commonMain/graphql/schema.graphqls index 609e7d42..760fb396 100644 --- a/tests/partial-results/src/commonMain/graphql/schema.graphqls +++ b/tests/partial-results/src/commonMain/graphql/schema.graphqls @@ -2,6 +2,7 @@ type Query { me: User! users(ids: [ID!]!): [User]! project(id: ID! = "1"): Project + user(category: Category!): User! } type User { @@ -13,6 +14,7 @@ type User { bestFriend: User projects: [Project!]! mainProject: Project! + category: Category! } type Project { @@ -22,3 +24,5 @@ type Project { lead: User users: [User!]! } + +scalar Category diff --git a/tests/partial-results/src/commonMain/kotlin/test/Category.kt b/tests/partial-results/src/commonMain/kotlin/test/Category.kt new file mode 100644 index 00000000..f1d88161 --- /dev/null +++ b/tests/partial-results/src/commonMain/kotlin/test/Category.kt @@ -0,0 +1,35 @@ +package test + +import com.apollographql.apollo.api.Adapter +import com.apollographql.apollo.api.CustomScalarAdapters +import com.apollographql.apollo.api.json.JsonReader +import com.apollographql.apollo.api.json.JsonWriter + +data class Category( + val code: Int, + val name: String, +) + +val CategoryAdapter = object : Adapter { + override fun fromJson(reader: JsonReader, customScalarAdapters: CustomScalarAdapters): Category { + reader.beginObject() + var code: Int? = null + var name: String? = null + while (true) { + when (reader.selectName(listOf("code", "name"))) { + 0 -> code = reader.nextInt() + 1 -> name = reader.nextString() + else -> break + } + } + reader.endObject() + return Category(code = code!!, name = name!!) + } + + override fun toJson(writer: JsonWriter, customScalarAdapters: CustomScalarAdapters, value: Category) { + writer.beginObject() + writer.name("code").value(value.code) + writer.name("name").value(value.name) + writer.endObject() + } +} diff --git a/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt b/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt index 2cc32483..36c0d5af 100644 --- a/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt +++ b/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt @@ -459,6 +459,64 @@ class CachePartialResultTest { ) } } + + @Test + fun customScalar() = runTest(before = { setUp() }, after = { tearDown() }) { + mockServer.enqueueString( + // language=JSON + """ + { + "data": { + "user": { + "__typename": "User", + "id": "1", + "firstName": "John", + "lastName": "Smith", + "category": { + "code": 1, + "name": "First" + } + } + } + } + """ + ) + ApolloClient.Builder() + .serverUrl(mockServer.url()) + .normalizedCache(MemoryCacheFactory()) + .returnPartialResponses(true) + .schema(Schema.schema) + .build() + .use { apolloClient -> + val networkResult = apolloClient.query(UserByCategoryQuery(Category(2, "Second"))) + .fetchPolicy(FetchPolicy.NetworkOnly) + .execute() + assertEquals( + UserByCategoryQuery.Data( + UserByCategoryQuery.User( + + firstName = "John", + lastName = "Smith", + category = Category( + code = 1, + name = "First" + ), + id = "1", + __typename = "User", + ) + ), + networkResult.data + ) + + val cacheResult = apolloClient.query(UserByCategoryQuery(Category(2, "Second"))) + .fetchPolicy(FetchPolicy.CacheOnly) + .execute() + assertEquals( + networkResult.data, + cacheResult.data + ) + } + } } /** From 62ced3c2998aacbc570f616143f2c9f3738a8014 Mon Sep 17 00:00:00 2001 From: BoD Date: Tue, 4 Feb 2025 14:39:29 +0100 Subject: [PATCH 06/11] Rely on CompiledFields instead of apollo-execution for null bubbling --- gradle/libs.versions.toml | 1 - ...ormalized-cache-apollo-compiler-plugin.api | 2 +- .../ApolloCacheCompilerPlugin.kt | 17 +-- .../apollocompilerplugin/internal/Codegen.kt | 62 +------- .../api/normalized-cache-incubating.api | 6 +- .../api/normalized-cache-incubating.klib.api | 4 +- normalized-cache-incubating/build.gradle.kts | 2 - .../cache/normalized/ApolloStore.kt | 7 +- .../cache/normalized/ClientCacheExtensions.kt | 27 ---- .../internal/ApolloCacheInterceptor.kt | 4 +- .../normalized/internal/DefaultApolloStore.kt | 144 +++++++++++------- .../src/commonMain/graphql/operation.graphql | 19 +++ .../kotlin/test/CachePartialResultTest.kt | 80 +++++++++- 13 files changed, 195 insertions(+), 180 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9174ca9f..c63c76df 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,7 +19,6 @@ apollo-compiler = { group = "com.apollographql.apollo", name = "apollo-compiler" apollo-cache = { group = "com.apollographql.apollo", name = "apollo-normalized-cache", version.ref = "apollo" } apollo-cache-sqlite = { group = "com.apollographql.apollo", name = "apollo-normalized-cache-sqlite", version.ref = "apollo" } apollo-plugin = { group = "com.apollographql.apollo", name = "apollo-gradle-plugin", version.ref = "apollo" } -apollo-execution = { group = "com.apollographql.apollo", name = "apollo-execution", version.ref = "apollo" } atomicfu-library = { group = "org.jetbrains.kotlinx", name = "atomicfu", version.ref = "atomicfu" } atomicfu-plugin = { group = "org.jetbrains.kotlinx", name = "atomicfu-gradle-plugin", version.ref = "atomicfu" } kotlin-test = { group = "org.jetbrains.kotlin", name = "kotlin-test" } # the Kotlin plugin resolves the version diff --git a/normalized-cache-apollo-compiler-plugin/api/normalized-cache-apollo-compiler-plugin.api b/normalized-cache-apollo-compiler-plugin/api/normalized-cache-apollo-compiler-plugin.api index 65a0c900..439fa85e 100644 --- a/normalized-cache-apollo-compiler-plugin/api/normalized-cache-apollo-compiler-plugin.api +++ b/normalized-cache-apollo-compiler-plugin/api/normalized-cache-apollo-compiler-plugin.api @@ -1,5 +1,5 @@ public final class com/apollographql/cache/apollocompilerplugin/ApolloCacheCompilerPlugin : com/apollographql/apollo/compiler/ApolloCompilerPlugin { - public fun (Lcom/apollographql/apollo/compiler/ApolloCompilerPluginLogger;Ljava/lang/String;Z)V + public fun (Ljava/lang/String;Lcom/apollographql/apollo/compiler/ApolloCompilerPluginLogger;)V public fun foreignSchemas ()Ljava/util/List; public fun schemaListener ()Lcom/apollographql/apollo/compiler/SchemaListener; } diff --git a/normalized-cache-apollo-compiler-plugin/src/main/kotlin/com/apollographql/cache/apollocompilerplugin/ApolloCacheCompilerPlugin.kt b/normalized-cache-apollo-compiler-plugin/src/main/kotlin/com/apollographql/cache/apollocompilerplugin/ApolloCacheCompilerPlugin.kt index 5d1f556e..5d1f0667 100644 --- a/normalized-cache-apollo-compiler-plugin/src/main/kotlin/com/apollographql/cache/apollocompilerplugin/ApolloCacheCompilerPlugin.kt +++ b/normalized-cache-apollo-compiler-plugin/src/main/kotlin/com/apollographql/cache/apollocompilerplugin/ApolloCacheCompilerPlugin.kt @@ -18,22 +18,16 @@ import java.io.File class ApolloCacheCompilerPluginProvider : ApolloCompilerPluginProvider { override fun create(environment: ApolloCompilerPluginEnvironment): ApolloCompilerPlugin { return ApolloCacheCompilerPlugin( - logger = environment.logger, packageName = environment.arguments["packageName"] as? String ?: throw IllegalArgumentException("packageName argument is required and must be a String"), - generateSchema = when (val generateSchema = environment.arguments["generateSchema"]) { - null -> false - is Boolean -> generateSchema - else -> throw IllegalArgumentException("generateSchema argument must be a Boolean") - } + logger = environment.logger, ) } } class ApolloCacheCompilerPlugin( - private val logger: ApolloCompilerPluginLogger, private val packageName: String, - private val generateSchema: Boolean, + private val logger: ApolloCompilerPluginLogger, ) : ApolloCompilerPlugin { override fun foreignSchemas(): List { return listOf( @@ -46,12 +40,7 @@ class ApolloCacheCompilerPlugin( return object : SchemaListener { override fun onSchema(schema: Schema, outputDirectory: File) { val maxAges = schema.getMaxAges(logger) - Codegen( - packageName = "$packageName.cache", - outputDirectory = outputDirectory, - maxAges = maxAges, - schema = schema.takeIf { generateSchema }, - ).generate() + Codegen("$packageName.cache", outputDirectory, maxAges).generate() } } } diff --git a/normalized-cache-apollo-compiler-plugin/src/main/kotlin/com/apollographql/cache/apollocompilerplugin/internal/Codegen.kt b/normalized-cache-apollo-compiler-plugin/src/main/kotlin/com/apollographql/cache/apollocompilerplugin/internal/Codegen.kt index de52d7ef..a2610784 100644 --- a/normalized-cache-apollo-compiler-plugin/src/main/kotlin/com/apollographql/cache/apollocompilerplugin/internal/Codegen.kt +++ b/normalized-cache-apollo-compiler-plugin/src/main/kotlin/com/apollographql/cache/apollocompilerplugin/internal/Codegen.kt @@ -1,16 +1,9 @@ package com.apollographql.cache.apollocompilerplugin.internal -import com.apollographql.apollo.annotations.ApolloExperimental -import com.apollographql.apollo.ast.GQLDocument -import com.apollographql.apollo.ast.GQLNamed -import com.apollographql.apollo.ast.Schema -import com.apollographql.apollo.ast.builtinDefinitions -import com.apollographql.apollo.ast.toSDL import com.apollographql.cache.apollocompilerplugin.VERSION import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.FileSpec -import com.squareup.kotlinpoet.KModifier import com.squareup.kotlinpoet.MAP import com.squareup.kotlinpoet.MemberName import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy @@ -28,25 +21,13 @@ private object Symbols { val Seconds = MemberName(Duration.Companion::class.asTypeName(), "seconds", isExtension = true) } -private val FILE_COMMENT = """ - - AUTO-GENERATED FILE. DO NOT MODIFY. - - This class was automatically generated by Apollo GraphQL Cache version '$VERSION'. - -""".trimIndent() - internal class Codegen( private val packageName: String, private val outputDirectory: File, private val maxAges: Map, - private val schema: Schema?, ) { fun generate() { generateCache() - if (schema != null) { - generateSchema(schema.toGQLDocumentWithoutBuiltinDefinitions()) - } } private fun generateCache() { @@ -76,44 +57,17 @@ internal class Codegen( ) .build() ) - .addFileComment(FILE_COMMENT) - .build() - - file.writeTo(outputDirectory) - } - - private fun generateSchema(schema: GQLDocument) { - val file = FileSpec.builder(packageName, "Schema") - .addType( - TypeSpec.objectBuilder("Schema") - .addProperty( - PropertySpec.builder("schema", String::class) - .addModifiers(KModifier.CONST) - .initializer("%S", @OptIn(ApolloExperimental::class) schema.toSDL()) - .build() - ) - .build() + .addFileComment( + """ + + AUTO-GENERATED FILE. DO NOT MODIFY. + + This class was automatically generated by Apollo GraphQL Cache version '$VERSION'. + + """.trimIndent() ) - .addFileComment(FILE_COMMENT) .build() file.writeTo(outputDirectory) } } - -private fun Schema.toGQLDocumentWithoutBuiltinDefinitions(): GQLDocument { - val excludedNames = builtinDefinitions().map { - (it as GQLNamed).name - }.toSet() - val gqlDocument = toGQLDocument() - return gqlDocument.copy( - definitions = gqlDocument.definitions.filter { - if (it !is GQLNamed) { - // GQLSchemaDefinition is not a GQLNamed - return@filter true - } - !excludedNames.contains(it.name) - } - ) - -} diff --git a/normalized-cache-incubating/api/normalized-cache-incubating.api b/normalized-cache-incubating/api/normalized-cache-incubating.api index 1c78480d..59a64475 100644 --- a/normalized-cache-incubating/api/normalized-cache-incubating.api +++ b/normalized-cache-incubating/api/normalized-cache-incubating.api @@ -8,7 +8,7 @@ public abstract interface class com/apollographql/cache/normalized/ApolloStore { public abstract fun normalize (Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/api/Operation$Data;Lcom/apollographql/apollo/api/CustomScalarAdapters;)Ljava/util/Map; public abstract fun publish (Ljava/util/Set;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun readFragment (Lcom/apollographql/apollo/api/Fragment;Lcom/apollographql/cache/normalized/api/CacheKey;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;)Lcom/apollographql/cache/normalized/ApolloStore$ReadResult; - public abstract fun readOperation (Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;ZLcom/apollographql/apollo/ast/GQLDocument;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun readOperation (Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;Z)Lcom/apollographql/apollo/api/ApolloResponse; public abstract fun remove (Lcom/apollographql/cache/normalized/api/CacheKey;Z)Z public abstract fun remove (Ljava/util/List;Z)I public abstract fun rollbackOptimisticUpdates (Ljava/util/UUID;)Ljava/util/Set; @@ -24,7 +24,7 @@ public final class com/apollographql/cache/normalized/ApolloStore$Companion { public final class com/apollographql/cache/normalized/ApolloStore$DefaultImpls { public static synthetic fun readFragment$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/apollo/api/Fragment;Lcom/apollographql/cache/normalized/api/CacheKey;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;ILjava/lang/Object;)Lcom/apollographql/cache/normalized/ApolloStore$ReadResult; - public static synthetic fun readOperation$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;ZLcom/apollographql/apollo/ast/GQLDocument;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; + public static synthetic fun readOperation$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;ZILjava/lang/Object;)Lcom/apollographql/apollo/api/ApolloResponse; public static synthetic fun remove$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/cache/normalized/api/CacheKey;ZILjava/lang/Object;)Z public static synthetic fun remove$default (Lcom/apollographql/cache/normalized/ApolloStore;Ljava/util/List;ZILjava/lang/Object;)I public static synthetic fun writeFragment$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/apollo/api/Fragment;Lcom/apollographql/cache/normalized/api/CacheKey;Lcom/apollographql/apollo/api/Fragment$Data;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;ILjava/lang/Object;)Ljava/util/Set; @@ -154,8 +154,6 @@ public final class com/apollographql/cache/normalized/NormalizedCache { public static final fun refetchPolicy (Lcom/apollographql/apollo/api/MutableExecutionOptions;Lcom/apollographql/cache/normalized/FetchPolicy;)Ljava/lang/Object; public static final fun refetchPolicyInterceptor (Lcom/apollographql/apollo/api/MutableExecutionOptions;Lcom/apollographql/apollo/interceptor/ApolloInterceptor;)Ljava/lang/Object; public static final fun returnPartialResponses (Lcom/apollographql/apollo/api/MutableExecutionOptions;Z)Ljava/lang/Object; - public static final fun schema (Lcom/apollographql/apollo/api/MutableExecutionOptions;Lcom/apollographql/apollo/ast/GQLDocument;)Ljava/lang/Object; - public static final fun schema (Lcom/apollographql/apollo/api/MutableExecutionOptions;Ljava/lang/String;)Ljava/lang/Object; public static final fun store (Lcom/apollographql/apollo/ApolloClient$Builder;Lcom/apollographql/cache/normalized/ApolloStore;Z)Lcom/apollographql/apollo/ApolloClient$Builder; public static synthetic fun store$default (Lcom/apollographql/apollo/ApolloClient$Builder;Lcom/apollographql/cache/normalized/ApolloStore;ZILjava/lang/Object;)Lcom/apollographql/apollo/ApolloClient$Builder; public static final fun storeExpirationDate (Lcom/apollographql/apollo/api/MutableExecutionOptions;Z)Ljava/lang/Object; diff --git a/normalized-cache-incubating/api/normalized-cache-incubating.klib.api b/normalized-cache-incubating/api/normalized-cache-incubating.klib.api index 0ad5e0b8..a2ef1fd5 100644 --- a/normalized-cache-incubating/api/normalized-cache-incubating.klib.api +++ b/normalized-cache-incubating/api/normalized-cache-incubating.klib.api @@ -84,6 +84,7 @@ abstract interface com.apollographql.cache.normalized/ApolloStore { // com.apoll abstract fun <#A1: com.apollographql.apollo.api/Fragment.Data> writeFragment(com.apollographql.apollo.api/Fragment<#A1>, com.apollographql.cache.normalized.api/CacheKey, #A1, com.apollographql.apollo.api/CustomScalarAdapters = ..., com.apollographql.cache.normalized.api/CacheHeaders = ...): kotlin.collections/Set // com.apollographql.cache.normalized/ApolloStore.writeFragment|writeFragment(com.apollographql.apollo.api.Fragment<0:0>;com.apollographql.cache.normalized.api.CacheKey;0:0;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheHeaders){0§}[0] abstract fun <#A1: com.apollographql.apollo.api/Fragment.Data> writeOptimisticUpdates(com.apollographql.apollo.api/Fragment<#A1>, com.apollographql.cache.normalized.api/CacheKey, #A1, com.benasher44.uuid/Uuid, com.apollographql.apollo.api/CustomScalarAdapters = ...): kotlin.collections/Set // com.apollographql.cache.normalized/ApolloStore.writeOptimisticUpdates|writeOptimisticUpdates(com.apollographql.apollo.api.Fragment<0:0>;com.apollographql.cache.normalized.api.CacheKey;0:0;com.benasher44.uuid.Uuid;com.apollographql.apollo.api.CustomScalarAdapters){0§}[0] abstract fun <#A1: com.apollographql.apollo.api/Operation.Data> normalize(com.apollographql.apollo.api/Operation<#A1>, #A1, com.apollographql.apollo.api/CustomScalarAdapters): kotlin.collections/Map // com.apollographql.cache.normalized/ApolloStore.normalize|normalize(com.apollographql.apollo.api.Operation<0:0>;0:0;com.apollographql.apollo.api.CustomScalarAdapters){0§}[0] + abstract fun <#A1: com.apollographql.apollo.api/Operation.Data> readOperation(com.apollographql.apollo.api/Operation<#A1>, com.apollographql.apollo.api/CustomScalarAdapters = ..., com.apollographql.cache.normalized.api/CacheHeaders = ..., kotlin/Boolean = ...): com.apollographql.apollo.api/ApolloResponse<#A1> // com.apollographql.cache.normalized/ApolloStore.readOperation|readOperation(com.apollographql.apollo.api.Operation<0:0>;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheHeaders;kotlin.Boolean){0§}[0] abstract fun <#A1: com.apollographql.apollo.api/Operation.Data> writeOperation(com.apollographql.apollo.api/Operation<#A1>, #A1, com.apollographql.apollo.api/CustomScalarAdapters = ..., com.apollographql.cache.normalized.api/CacheHeaders = ...): kotlin.collections/Set // com.apollographql.cache.normalized/ApolloStore.writeOperation|writeOperation(com.apollographql.apollo.api.Operation<0:0>;0:0;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheHeaders){0§}[0] abstract fun <#A1: com.apollographql.apollo.api/Operation.Data> writeOptimisticUpdates(com.apollographql.apollo.api/Operation<#A1>, #A1, com.benasher44.uuid/Uuid, com.apollographql.apollo.api/CustomScalarAdapters = ...): kotlin.collections/Set // com.apollographql.cache.normalized/ApolloStore.writeOptimisticUpdates|writeOptimisticUpdates(com.apollographql.apollo.api.Operation<0:0>;0:0;com.benasher44.uuid.Uuid;com.apollographql.apollo.api.CustomScalarAdapters){0§}[0] abstract fun <#A1: kotlin/Any?> accessCache(kotlin/Function1): #A1 // com.apollographql.cache.normalized/ApolloStore.accessCache|accessCache(kotlin.Function1){0§}[0] @@ -93,7 +94,6 @@ abstract interface com.apollographql.cache.normalized/ApolloStore { // com.apoll abstract fun remove(com.apollographql.cache.normalized.api/CacheKey, kotlin/Boolean = ...): kotlin/Boolean // com.apollographql.cache.normalized/ApolloStore.remove|remove(com.apollographql.cache.normalized.api.CacheKey;kotlin.Boolean){}[0] abstract fun remove(kotlin.collections/List, kotlin/Boolean = ...): kotlin/Int // com.apollographql.cache.normalized/ApolloStore.remove|remove(kotlin.collections.List;kotlin.Boolean){}[0] abstract fun rollbackOptimisticUpdates(com.benasher44.uuid/Uuid): kotlin.collections/Set // com.apollographql.cache.normalized/ApolloStore.rollbackOptimisticUpdates|rollbackOptimisticUpdates(com.benasher44.uuid.Uuid){}[0] - abstract suspend fun <#A1: com.apollographql.apollo.api/Operation.Data> readOperation(com.apollographql.apollo.api/Operation<#A1>, com.apollographql.apollo.api/CustomScalarAdapters = ..., com.apollographql.cache.normalized.api/CacheHeaders = ..., kotlin/Boolean = ..., com.apollographql.apollo.ast/GQLDocument? = ...): com.apollographql.apollo.api/ApolloResponse<#A1> // com.apollographql.cache.normalized/ApolloStore.readOperation|readOperation(com.apollographql.apollo.api.Operation<0:0>;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheHeaders;kotlin.Boolean;com.apollographql.apollo.ast.GQLDocument?){0§}[0] abstract suspend fun publish(kotlin.collections/Set) // com.apollographql.cache.normalized/ApolloStore.publish|publish(kotlin.collections.Set){}[0] final class <#A1: com.apollographql.apollo.api/Executable.Data> ReadResult { // com.apollographql.cache.normalized/ApolloStore.ReadResult|null[0] @@ -573,8 +573,6 @@ final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOption final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/refetchPolicy(com.apollographql.cache.normalized/FetchPolicy): #A // com.apollographql.cache.normalized/refetchPolicy|refetchPolicy@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(com.apollographql.cache.normalized.FetchPolicy){0§}[0] final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/refetchPolicyInterceptor(com.apollographql.apollo.interceptor/ApolloInterceptor): #A // com.apollographql.cache.normalized/refetchPolicyInterceptor|refetchPolicyInterceptor@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(com.apollographql.apollo.interceptor.ApolloInterceptor){0§}[0] final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/returnPartialResponses(kotlin/Boolean): #A // com.apollographql.cache.normalized/returnPartialResponses|returnPartialResponses@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] -final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/schema(com.apollographql.apollo.ast/GQLDocument): #A // com.apollographql.cache.normalized/schema|schema@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(com.apollographql.apollo.ast.GQLDocument){0§}[0] -final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/schema(kotlin/String): #A // com.apollographql.cache.normalized/schema|schema@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.String){0§}[0] final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/storeExpirationDate(kotlin/Boolean): #A // com.apollographql.cache.normalized/storeExpirationDate|storeExpirationDate@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/storePartialResponses(kotlin/Boolean): #A // com.apollographql.cache.normalized/storePartialResponses|storePartialResponses@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/storeReceiveDate(kotlin/Boolean): #A // com.apollographql.cache.normalized/storeReceiveDate|storeReceiveDate@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] diff --git a/normalized-cache-incubating/build.gradle.kts b/normalized-cache-incubating/build.gradle.kts index 4b7bb87b..8327047c 100644 --- a/normalized-cache-incubating/build.gradle.kts +++ b/normalized-cache-incubating/build.gradle.kts @@ -22,8 +22,6 @@ kotlin { implementation(libs.okio) api(libs.uuid) implementation(libs.atomicfu.library) - implementation(libs.apollo.execution) - api(libs.apollo.ast) } } diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ApolloStore.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ApolloStore.kt index d3879aba..a98bb346 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ApolloStore.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ApolloStore.kt @@ -6,7 +6,6 @@ import com.apollographql.apollo.api.Executable import com.apollographql.apollo.api.Fragment import com.apollographql.apollo.api.Operation import com.apollographql.apollo.api.json.JsonNumber -import com.apollographql.apollo.ast.GQLDocument import com.apollographql.apollo.interceptor.ApolloInterceptor import com.apollographql.cache.normalized.api.CacheHeaders import com.apollographql.cache.normalized.api.CacheKey @@ -63,20 +62,18 @@ interface ApolloStore { * * When [returnPartialResponses] is `true`, the returned [ApolloResponse.data] has `null` values for any missing fields if their * type is nullable, bubbling up to their parent otherwise. Missing fields have a corresponding [com.apollographql.apollo.api.Error] - * in [ApolloResponse.errors]. A [schema] must be provided to read partial responses. + * in [ApolloResponse.errors]. * * This is a synchronous operation that might block if the underlying cache is doing IO. * * @param operation the operation to read * @param returnPartialResponses whether to return partial responses - * @param schema the schema to use for reading the operation - required when [returnPartialResponses] is `true` */ - suspend fun readOperation( + fun readOperation( operation: Operation, customScalarAdapters: CustomScalarAdapters = CustomScalarAdapters.Empty, cacheHeaders: CacheHeaders = CacheHeaders.NONE, returnPartialResponses: Boolean = false, - schema: GQLDocument? = null, ): ApolloResponse /** diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ClientCacheExtensions.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ClientCacheExtensions.kt index e2571224..799395f9 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ClientCacheExtensions.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ClientCacheExtensions.kt @@ -14,8 +14,6 @@ import com.apollographql.apollo.api.Mutation import com.apollographql.apollo.api.Operation import com.apollographql.apollo.api.Query import com.apollographql.apollo.api.http.get -import com.apollographql.apollo.ast.GQLDocument -import com.apollographql.apollo.ast.toGQLDocument import com.apollographql.apollo.exception.ApolloException import com.apollographql.apollo.exception.CacheMissException import com.apollographql.apollo.interceptor.ApolloInterceptor @@ -284,19 +282,6 @@ fun MutableExecutionOptions.returnPartialResponses(returnPartialResponses ReturnPartialResponsesContext(returnPartialResponses) ) -/** - * @param schema The schema to use when reading the cache with partial results. - */ -fun MutableExecutionOptions.schema(schema: GQLDocument) = addExecutionContext( - SchemaContext(schema) -) - -/** - * @param schema The schema to use when reading the cache with partial results. - */ -fun MutableExecutionOptions.schema(schema: String) = schema(schema.toGQLDocument()) - - /** * @param storeExpirationDate Whether to store the expiration date in the cache. * @@ -433,10 +418,6 @@ internal val ApolloRequest.watchContext: WatchContext? internal val ApolloRequest.returnPartialResponses get() = executionContext[ReturnPartialResponsesContext]?.value ?: false -internal val ApolloRequest.schema: GQLDocument? - get() = executionContext[SchemaContext]?.value - - class CacheInfo private constructor( val cacheStartMillis: Long, val cacheEndMillis: Long, @@ -662,14 +643,6 @@ internal class ReturnPartialResponsesContext(val value: Boolean) : ExecutionCont companion object Key : ExecutionContext.Key } -internal class SchemaContext(val value: GQLDocument) : ExecutionContext.Element { - override val key: ExecutionContext.Key<*> - get() = Key - - companion object Key : ExecutionContext.Key -} - - internal fun ApolloRequest.Builder.fetchFromCache(fetchFromCache: Boolean) = apply { addExecutionContext(FetchFromCacheContext(fetchFromCache)) } diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/ApolloCacheInterceptor.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/ApolloCacheInterceptor.kt index 97dbc74b..f0dd654b 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/ApolloCacheInterceptor.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/ApolloCacheInterceptor.kt @@ -26,7 +26,6 @@ import com.apollographql.cache.normalized.fetchFromCache import com.apollographql.cache.normalized.memoryCacheOnly import com.apollographql.cache.normalized.optimisticData import com.apollographql.cache.normalized.returnPartialResponses -import com.apollographql.cache.normalized.schema import com.apollographql.cache.normalized.storePartialResponses import com.apollographql.cache.normalized.storeReceiveDate import com.apollographql.cache.normalized.writeToCacheAsynchronously @@ -202,7 +201,7 @@ internal class ApolloCacheInterceptor( } } - private suspend fun readFromCache( + private fun readFromCache( request: ApolloRequest, customScalarAdapters: CustomScalarAdapters, ): ApolloResponse { @@ -217,7 +216,6 @@ internal class ApolloCacheInterceptor( customScalarAdapters = customScalarAdapters, cacheHeaders = cacheHeaders, returnPartialResponses = returnPartialResponses, - schema = if (returnPartialResponses) request.schema ?: error("schema is required for partial responses") else null, ) return response.newBuilder() .requestUuid(request.requestUuid) diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt index 206622a7..1a89ec60 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt @@ -1,21 +1,18 @@ package com.apollographql.cache.normalized.internal import com.apollographql.apollo.api.ApolloResponse +import com.apollographql.apollo.api.CompiledField +import com.apollographql.apollo.api.CompiledFragment +import com.apollographql.apollo.api.CompiledListType +import com.apollographql.apollo.api.CompiledNotNullType +import com.apollographql.apollo.api.CompiledSelection import com.apollographql.apollo.api.CustomScalarAdapters import com.apollographql.apollo.api.Error -import com.apollographql.apollo.api.ExecutionContext import com.apollographql.apollo.api.Fragment import com.apollographql.apollo.api.Operation import com.apollographql.apollo.api.json.jsonReader import com.apollographql.apollo.api.variables -import com.apollographql.apollo.ast.GQLDocument -import com.apollographql.apollo.ast.GQLValue import com.apollographql.apollo.exception.CacheMissException -import com.apollographql.apollo.execution.Coercing -import com.apollographql.apollo.execution.ExecutableSchema -import com.apollographql.apollo.execution.GraphQLRequest -import com.apollographql.apollo.execution.GraphQLResponse -import com.apollographql.apollo.execution.JsonValue import com.apollographql.cache.normalized.ApolloStore import com.apollographql.cache.normalized.ApolloStore.ReadResult import com.apollographql.cache.normalized.CacheInfo @@ -122,15 +119,14 @@ internal class DefaultApolloStore( ) } - override suspend fun readOperation( + override fun readOperation( operation: Operation, customScalarAdapters: CustomScalarAdapters, cacheHeaders: CacheHeaders, returnPartialResponses: Boolean, - schema: GQLDocument?, ): ApolloResponse { return if (returnPartialResponses) { - readOperationPartial(operation, schema!!, customScalarAdapters, cacheHeaders) + readOperationPartial(operation, customScalarAdapters, cacheHeaders) } else { readOperationThrowCacheMiss(operation, customScalarAdapters, cacheHeaders) } @@ -183,9 +179,8 @@ internal class DefaultApolloStore( } } - private suspend fun readOperationPartial( + private fun readOperationPartial( operation: Operation, - schema: GQLDocument, customScalarAdapters: CustomScalarAdapters, cacheHeaders: CacheHeaders, ): ApolloResponse { @@ -199,78 +194,109 @@ internal class DefaultApolloStore( fieldKeyGenerator = fieldKeyGenerator, returnPartialResponses = true, ) - val dataAsMapWithCacheMisses: Map = batchReaderData.toMap() - val graphQLRequest = GraphQLRequest.Builder() - .document(operation.document()) - .variables(variables.valueMap) - .build() - val graphQLResponse: GraphQLResponse = ExecutableSchema.Builder() - .schema(schema) - .resolver { resolveInfo -> - dataAsMapWithCacheMisses.valueAtPath(resolveInfo.path) - } - .addCoercing("Category", PassThroughCoercing) - .build() - .execute(graphQLRequest, ExecutionContext.Empty) + val dataWithErrors: Map = batchReaderData.toMap() + val errors = mutableListOf() @Suppress("UNCHECKED_CAST") - val dataAsMapWithNullFields = graphQLResponse.data as Map? + val dataWithNullBubbling: Map? = nullBubble(dataWithErrors, operation.rootField(), errors) as Map? val falseVariablesCustomScalarAdapter = customScalarAdapters.newBuilder().falseVariables(variables.valueMap.filter { it.value == false }.keys).build() - val data = dataAsMapWithNullFields?.let { operation.adapter().fromJson(it.jsonReader(), falseVariablesCustomScalarAdapter) } + val data = dataWithNullBubbling?.let { operation.adapter().fromJson(it.jsonReader(), falseVariablesCustomScalarAdapter) } return ApolloResponse.Builder(operation, uuid4()) .data(data) - .errors(graphQLResponse.errors) + .errors(errors.takeIf { it.isNotEmpty() }) .cacheHeaders(batchReaderData.cacheHeaders) .cacheInfo( CacheInfo.Builder() .fromCache(true) - .cacheHit(graphQLResponse.errors.isNullOrEmpty()) + .cacheHit(errors.isEmpty()) .stale(batchReaderData.cacheHeaders.headerValue(ApolloCacheHeaders.STALE) == "true") .build() ) .build() } - private fun Map.valueAtPath(path: List): Any? { - var value: Any? = this - for (key in path) { - value = when (value) { - is List<*> -> { - value[key as Int] - } - - is Map<*, *> -> { - @Suppress("UNCHECKED_CAST") - value as Map - value[key] + /** + * If a position contains an Error, replace it by a null if the field's type is nullable, bubble up if not. + */ + private fun nullBubble(dataWithErrors: Any?, field: CompiledField, errors: MutableList): Any? { + return when (dataWithErrors) { + is Map<*, *> -> { + @Suppress("UNCHECKED_CAST") + dataWithErrors as Map + dataWithErrors.mapValues { (key, value) -> + val selection = field.fieldSelections()[key] + ?: // Scalar + return@mapValues value + when (value) { + is Error -> { + errors.add(value) + if (selection.type is CompiledNotNullType) { + return null + } + null + } + + else -> { + nullBubble(value, selection, errors).also { + if (it == null && selection.type is CompiledNotNullType) { + return null + } + } + } + } } + } - is Error -> { - // Short circuit if we encounter a cache miss error - return value + is List<*> -> { + dataWithErrors.mapIndexed { index, value -> + val listType = if (field.type is CompiledNotNullType) { + (field.type as CompiledNotNullType).ofType as? CompiledListType + } else { + field.type as? CompiledListType + } + if (listType == null) { + // Scalar + return@mapIndexed value + } + val elementType = listType.ofType + when (value) { + is Error -> { + errors.add(value) + if (elementType is CompiledNotNullType) { + return null + } + null + } + + else -> { + nullBubble(value, field, errors).also { + if (it == null && elementType is CompiledNotNullType) { + return null + } + } + } + } } + } - else -> { - error("Unknown value type: $value") - } + else -> { + dataWithErrors } } - return value } - private object PassThroughCoercing : Coercing { - override fun deserialize(value: JsonValue): Any? { - return value - } - - override fun parseLiteral(value: GQLValue): Any { - return value - } + private fun CompiledSelection.fieldSelections(): Map { + fun CompiledSelection.fieldSelections(): List { + return when (this) { + is CompiledField -> selections.filterIsInstance() + selections.filterIsInstance() + .flatMap { it.fieldSelections() } - override fun serialize(internalValue: Any?): JsonValue { - return internalValue + is CompiledFragment -> selections.filterIsInstance() + selections.filterIsInstance() + .flatMap { it.fieldSelections() } + } } + return fieldSelections().associateBy { it.responseName } } override fun readFragment( diff --git a/tests/partial-results/src/commonMain/graphql/operation.graphql b/tests/partial-results/src/commonMain/graphql/operation.graphql index 68fc9226..1ada7585 100644 --- a/tests/partial-results/src/commonMain/graphql/operation.graphql +++ b/tests/partial-results/src/commonMain/graphql/operation.graphql @@ -81,3 +81,22 @@ query UserByCategoryQuery($category: Category!) { category } } + +query WithFragmentsQuery { + me { + id + firstName0: firstName + ... on User { + lastName + ... on User { + nickName0: nickName + } + } + ... UserFields + } +} + +fragment UserFields on User { + email0: email + category +} diff --git a/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt b/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt index 36c0d5af..9e69230d 100644 --- a/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt +++ b/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt @@ -14,13 +14,12 @@ import com.apollographql.cache.normalized.fetchPolicy import com.apollographql.cache.normalized.memory.MemoryCacheFactory import com.apollographql.cache.normalized.normalizedCache import com.apollographql.cache.normalized.returnPartialResponses -import com.apollographql.cache.normalized.schema import com.apollographql.cache.normalized.store import com.apollographql.cache.normalized.storePartialResponses import com.apollographql.mockserver.MockServer import com.apollographql.mockserver.enqueueString import okio.use -import test.cache.Schema +import test.fragment.UserFields import kotlin.test.Test import kotlin.test.assertContentEquals import kotlin.test.assertEquals @@ -59,7 +58,6 @@ class CachePartialResultTest { .serverUrl(mockServer.url()) .normalizedCache(MemoryCacheFactory()) .returnPartialResponses(true) - .schema(Schema.schema) .build() .use { apolloClient -> val networkResult = apolloClient.query(MeWithoutNickNameWithEmailQuery()) @@ -164,7 +162,6 @@ class CachePartialResultTest { ) ) .returnPartialResponses(true) - .schema(Schema.schema) .build() .use { apolloClient -> val networkResult = apolloClient.query(UsersQuery(listOf("1", "2", "3"))) @@ -256,7 +253,6 @@ class CachePartialResultTest { .serverUrl(mockServer.url()) .normalizedCache(MemoryCacheFactory()) .returnPartialResponses(true) - .schema(Schema.schema) .build() .use { apolloClient -> // Prime the cache @@ -388,6 +384,8 @@ class CachePartialResultTest { assertNull(cacheResult3.data) assertErrorsEquals( listOf( + Error.Builder("Object 'User:2' not found in the cache").path(listOf("me", "bestFriend")).build(), + Error.Builder("Object 'User:3' not found in the cache").path(listOf("me", "projects", 0, "lead")).build(), Error.Builder("Object 'User:4' not found in the cache").path(listOf("me", "projects", 0, "users", 0)).build() ), cacheResult3.errors @@ -428,7 +426,6 @@ class CachePartialResultTest { ) ) .returnPartialResponses(true) - .schema(Schema.schema) .build() .use { apolloClient -> val networkResult = apolloClient.query(DefaultProjectQuery()) @@ -485,7 +482,6 @@ class CachePartialResultTest { .serverUrl(mockServer.url()) .normalizedCache(MemoryCacheFactory()) .returnPartialResponses(true) - .schema(Schema.schema) .build() .use { apolloClient -> val networkResult = apolloClient.query(UserByCategoryQuery(Category(2, "Second"))) @@ -517,6 +513,76 @@ class CachePartialResultTest { ) } } + + @Test + fun fragmentsAndAliases() = runTest(before = { setUp() }, after = { tearDown() }) { + mockServer.enqueueString( + // language=JSON + """ + { + "data": { + "me": { + "__typename": "User", + "id": "1", + "firstName0": "John", + "lastName": "Smith", + "nickName0": "JS", + "email0": "jdoe@example.com", + "category": { + "code": 1, + "name": "First" + } + } + } + } + """ + ) + ApolloClient.Builder() + .serverUrl(mockServer.url()) + .normalizedCache(MemoryCacheFactory()) + .returnPartialResponses(true) + .build() + .use { apolloClient -> + val networkResult = apolloClient.query(WithFragmentsQuery()) + .fetchPolicy(FetchPolicy.NetworkOnly) + .execute() + assertEquals( + WithFragmentsQuery.Data( + WithFragmentsQuery.Me( + __typename = "User", + id = "1", + firstName0 = "John", + onUser = WithFragmentsQuery.OnUser( + lastName = "Smith", + onUser = WithFragmentsQuery.OnUser1( + nickName0 = "JS" + ), + __typename = "User", + ), + userFields = UserFields( + email0 = "jdoe@example.com", + category = Category( + code = 1, + name = "First" + ), + id = "1", + __typename = "User", + ), + ) + ), + networkResult.data + ) + + val cacheResult = apolloClient.query(WithFragmentsQuery()) + .fetchPolicy(FetchPolicy.CacheOnly) + .execute() + assertEquals( + networkResult.data, + cacheResult.data + ) + } + } + } /** From 8cd30a6fc839b490f3b7101690212599cdd97638 Mon Sep 17 00:00:00 2001 From: BoD Date: Wed, 5 Feb 2025 11:22:44 +0100 Subject: [PATCH 07/11] Add a cache control test. Also surface the CacheMissException in the Errors --- .../normalized/internal/CacheBatchReader.kt | 21 +++--- tests/partial-results/build.gradle.kts | 1 - .../src/commonMain/graphql/extra.graphqls | 7 ++ .../kotlin/test/CachePartialResultTest.kt | 75 +++++++++++++++++-- 4 files changed, 85 insertions(+), 19 deletions(-) diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/CacheBatchReader.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/CacheBatchReader.kt index 43d3fad7..68f88492 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/CacheBatchReader.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/CacheBatchReader.kt @@ -118,7 +118,7 @@ internal class CacheBatchReader( } else { if (returnPartialResponses) { data[pendingReference.path] = - cacheMissError(key = pendingReference.key, fieldName = null, stale = false, path = pendingReference.path) + cacheMissError(CacheMissException(key = pendingReference.key, fieldName = null, stale = false), path = pendingReference.path) return@forEach } else { throw CacheMissException(pendingReference.key) @@ -292,22 +292,19 @@ internal class CacheBatchReader( } } - private fun cacheMissError(key: String, fieldName: String?, stale: Boolean, path: List): Error { - val message = if (fieldName == null) { - "Object '$key' not found in the cache" + private fun cacheMissError(exception: CacheMissException, path: List): Error { + val message = if (exception.fieldName == null) { + "Object '${exception.key}' not found in the cache" } else { - if (stale) { - "Field '$key' on object '$fieldName' is stale in the cache" + if (exception.stale) { + "Field '${exception.key}' on object '${exception.fieldName}' is stale in the cache" } else { - "Object '$key' has no field named '$fieldName' in the cache" + "Object '${exception.key}' has no field named '${exception.fieldName}' in the cache" } } return Error.Builder(message) - .path(path) + .path(path = path) + .putExtension("exception", exception) .build() } - - private fun cacheMissError(exception: CacheMissException, path: List): Error { - return cacheMissError(key = exception.key, fieldName = exception.fieldName, stale = exception.stale, path = path) - } } diff --git a/tests/partial-results/build.gradle.kts b/tests/partial-results/build.gradle.kts index 2af20c9b..f0e14739 100644 --- a/tests/partial-results/build.gradle.kts +++ b/tests/partial-results/build.gradle.kts @@ -41,7 +41,6 @@ apollo { plugin("com.apollographql.cache:normalized-cache-apollo-compiler-plugin") { argument("packageName", packageName.get()) - argument("generateSchema", true) } mapScalar("Category", "test.Category", "test.CategoryAdapter") diff --git a/tests/partial-results/src/commonMain/graphql/extra.graphqls b/tests/partial-results/src/commonMain/graphql/extra.graphqls index cc0acb33..a7709299 100644 --- a/tests/partial-results/src/commonMain/graphql/extra.graphqls +++ b/tests/partial-results/src/commonMain/graphql/extra.graphqls @@ -3,6 +3,13 @@ extend schema url: "https://specs.apollo.dev/kotlin_labs/v0.3", import: ["@fieldPolicy", "@typePolicy"] ) +@link( + url: "https://specs.apollo.dev/cache/v0.1", + import: ["@cacheControl", "@cacheControlField"] +) + extend type User @typePolicy(keyFields: "id") extend type Query @fieldPolicy(forField: "users", keyArgs: "ids") + +extend type User @cacheControlField(name: "nickName", maxAge: 0) diff --git a/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt b/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt index 9e69230d..51fe9e1a 100644 --- a/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt +++ b/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt @@ -6,9 +6,11 @@ import com.apollographql.apollo.api.Error.Location import com.apollographql.apollo.testing.internal.runTest import com.apollographql.cache.normalized.ApolloStore import com.apollographql.cache.normalized.FetchPolicy +import com.apollographql.cache.normalized.api.CacheControlCacheResolver import com.apollographql.cache.normalized.api.CacheKey import com.apollographql.cache.normalized.api.IdCacheKeyGenerator import com.apollographql.cache.normalized.api.IdCacheKeyResolver +import com.apollographql.cache.normalized.api.SchemaCoordinatesMaxAgeProvider import com.apollographql.cache.normalized.apolloStore import com.apollographql.cache.normalized.fetchPolicy import com.apollographql.cache.normalized.memory.MemoryCacheFactory @@ -16,14 +18,17 @@ import com.apollographql.cache.normalized.normalizedCache import com.apollographql.cache.normalized.returnPartialResponses import com.apollographql.cache.normalized.store import com.apollographql.cache.normalized.storePartialResponses +import com.apollographql.cache.normalized.storeReceiveDate import com.apollographql.mockserver.MockServer import com.apollographql.mockserver.enqueueString import okio.use +import test.cache.Cache import test.fragment.UserFields import kotlin.test.Test import kotlin.test.assertContentEquals import kotlin.test.assertEquals import kotlin.test.assertNull +import kotlin.time.Duration class CachePartialResultTest { private lateinit var mockServer: MockServer @@ -583,6 +588,70 @@ class CachePartialResultTest { } } + @Test + fun cacheControl() = runTest(before = { setUp() }, after = { tearDown() }) { + mockServer.enqueueString( + // language=JSON + """ + { + "data": { + "me": { + "__typename": "User", + "id": "1", + "firstName": "John", + "lastName": "Smith", + "nickName": "JS" + } + } + } + """ + ) + ApolloClient.Builder() + .serverUrl(mockServer.url()) + .normalizedCache(MemoryCacheFactory(), cacheResolver = CacheControlCacheResolver(SchemaCoordinatesMaxAgeProvider(Cache.maxAges, Duration.INFINITE))) + .storeReceiveDate(true) + .returnPartialResponses(true) + .build() + .use { apolloClient -> + val networkResult = apolloClient.query(MeWithNickNameQuery()) + .fetchPolicy(FetchPolicy.NetworkOnly) + .execute() + assertEquals( + MeWithNickNameQuery.Data( + MeWithNickNameQuery.Me( + __typename = "User", + id = "1", + firstName = "John", + lastName = "Smith", + nickName = "JS" + ) + ), + networkResult.data + ) + + val cacheMissResult = apolloClient.query(MeWithNickNameQuery()) + .fetchPolicy(FetchPolicy.CacheOnly) + .execute() + assertEquals( + MeWithNickNameQuery.Data( + MeWithNickNameQuery.Me( + id = "1", + firstName = "John", + lastName = "Smith", + nickName = null, + __typename = "User" + ) + ), + cacheMissResult.data + ) + assertErrorsEquals( + listOf( + Error.Builder("Field 'User:1' on object 'nickName' is stale in the cache").path(listOf("me", "nickName")).build() + ), + cacheMissResult.errors + ) + } + } } /** @@ -592,8 +661,6 @@ private data class ComparableError( val message: String, val locations: List?, val path: List?, - val extensions: Map?, - val nonStandardFields: Map?, ) private fun assertErrorsEquals(expected: Iterable?, actual: Iterable?) = @@ -602,15 +669,11 @@ private fun assertErrorsEquals(expected: Iterable?, actual: Iterable Date: Wed, 5 Feb 2025 14:36:05 +0100 Subject: [PATCH 08/11] Naming tweaks --- .../normalized/internal/DefaultApolloStore.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt index 1a89ec60..f3ce523d 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt @@ -128,11 +128,11 @@ internal class DefaultApolloStore( return if (returnPartialResponses) { readOperationPartial(operation, customScalarAdapters, cacheHeaders) } else { - readOperationThrowCacheMiss(operation, customScalarAdapters, cacheHeaders) + readOperationCacheMissException(operation, customScalarAdapters, cacheHeaders) } } - private fun readOperationThrowCacheMiss( + private fun readOperationCacheMissException( operation: Operation, customScalarAdapters: CustomScalarAdapters, cacheHeaders: CacheHeaders, @@ -198,10 +198,10 @@ internal class DefaultApolloStore( val errors = mutableListOf() @Suppress("UNCHECKED_CAST") - val dataWithNullBubbling: Map? = nullBubble(dataWithErrors, operation.rootField(), errors) as Map? + val dataWithNulls: Map? = propagateErrors(dataWithErrors, operation.rootField(), errors) as Map? val falseVariablesCustomScalarAdapter = customScalarAdapters.newBuilder().falseVariables(variables.valueMap.filter { it.value == false }.keys).build() - val data = dataWithNullBubbling?.let { operation.adapter().fromJson(it.jsonReader(), falseVariablesCustomScalarAdapter) } + val data = dataWithNulls?.let { operation.adapter().fromJson(it.jsonReader(), falseVariablesCustomScalarAdapter) } return ApolloResponse.Builder(operation, uuid4()) .data(data) .errors(errors.takeIf { it.isNotEmpty() }) @@ -217,9 +217,9 @@ internal class DefaultApolloStore( } /** - * If a position contains an Error, replace it by a null if the field's type is nullable, bubble up if not. + * If a position contains an Error, replace it by a null if the field's type is nullable, propagate the error if not. */ - private fun nullBubble(dataWithErrors: Any?, field: CompiledField, errors: MutableList): Any? { + private fun propagateErrors(dataWithErrors: Any?, field: CompiledField, errors: MutableList): Any? { return when (dataWithErrors) { is Map<*, *> -> { @Suppress("UNCHECKED_CAST") @@ -238,7 +238,7 @@ internal class DefaultApolloStore( } else -> { - nullBubble(value, selection, errors).also { + propagateErrors(value, selection, errors).also { if (it == null && selection.type is CompiledNotNullType) { return null } @@ -270,7 +270,7 @@ internal class DefaultApolloStore( } else -> { - nullBubble(value, field, errors).also { + propagateErrors(value, field, errors).also { if (it == null && elementType is CompiledNotNullType) { return null } From 008b48cce90fe531308f330327e51b07148fc60f Mon Sep 17 00:00:00 2001 From: BoD Date: Wed, 5 Feb 2025 16:43:20 +0100 Subject: [PATCH 09/11] Handle fields selected multiple times --- .../normalized/internal/DefaultApolloStore.kt | 14 ++- .../src/commonMain/graphql/operation.graphql | 16 ++++ .../src/commonMain/graphql/schema.graphqls | 2 + .../kotlin/test/CachePartialResultTest.kt | 89 ++++++++++++++++++- 4 files changed, 116 insertions(+), 5 deletions(-) diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt index f3ce523d..a679d1cd 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt @@ -225,7 +225,7 @@ internal class DefaultApolloStore( @Suppress("UNCHECKED_CAST") dataWithErrors as Map dataWithErrors.mapValues { (key, value) -> - val selection = field.fieldSelections()[key] + val selection = field.fieldSelection(key) ?: // Scalar return@mapValues value when (value) { @@ -286,7 +286,7 @@ internal class DefaultApolloStore( } } - private fun CompiledSelection.fieldSelections(): Map { + private fun CompiledSelection.fieldSelection(responseName: String): CompiledField? { fun CompiledSelection.fieldSelections(): List { return when (this) { is CompiledField -> selections.filterIsInstance() + selections.filterIsInstance() @@ -296,7 +296,15 @@ internal class DefaultApolloStore( .flatMap { it.fieldSelections() } } } - return fieldSelections().associateBy { it.responseName } + // Fields can be selected multiple times, combine the selections + return fieldSelections().filter { it.responseName == responseName }.reduceOrNull { acc, compiledField -> + CompiledField.Builder( + name = acc.name, + type = acc.type, + ) + .selections(acc.selections + compiledField.selections) + .build() + } } override fun readFragment( diff --git a/tests/partial-results/src/commonMain/graphql/operation.graphql b/tests/partial-results/src/commonMain/graphql/operation.graphql index 1ada7585..7e881a18 100644 --- a/tests/partial-results/src/commonMain/graphql/operation.graphql +++ b/tests/partial-results/src/commonMain/graphql/operation.graphql @@ -94,6 +94,22 @@ query WithFragmentsQuery { } ... UserFields } + + me { + firstName0: firstName + mainProject { + id + lead0: lead { + id + } + } + mainProject { + lead0: lead { + id + firstName + } + } + } } fragment UserFields on User { diff --git a/tests/partial-results/src/commonMain/graphql/schema.graphqls b/tests/partial-results/src/commonMain/graphql/schema.graphqls index 760fb396..61ec3831 100644 --- a/tests/partial-results/src/commonMain/graphql/schema.graphqls +++ b/tests/partial-results/src/commonMain/graphql/schema.graphqls @@ -3,6 +3,8 @@ type Query { users(ids: [ID!]!): [User]! project(id: ID! = "1"): Project user(category: Category!): User! + someInt: Int + someInt2: Int } type User { diff --git a/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt b/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt index 51fe9e1a..831b13a0 100644 --- a/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt +++ b/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt @@ -7,9 +7,12 @@ import com.apollographql.apollo.testing.internal.runTest import com.apollographql.cache.normalized.ApolloStore import com.apollographql.cache.normalized.FetchPolicy import com.apollographql.cache.normalized.api.CacheControlCacheResolver +import com.apollographql.cache.normalized.api.CacheHeaders import com.apollographql.cache.normalized.api.CacheKey +import com.apollographql.cache.normalized.api.DefaultRecordMerger import com.apollographql.cache.normalized.api.IdCacheKeyGenerator import com.apollographql.cache.normalized.api.IdCacheKeyResolver +import com.apollographql.cache.normalized.api.Record import com.apollographql.cache.normalized.api.SchemaCoordinatesMaxAgeProvider import com.apollographql.cache.normalized.apolloStore import com.apollographql.cache.normalized.fetchPolicy @@ -485,7 +488,13 @@ class CachePartialResultTest { ) ApolloClient.Builder() .serverUrl(mockServer.url()) - .normalizedCache(MemoryCacheFactory()) + .store( + ApolloStore( + normalizedCacheFactory = MemoryCacheFactory(), + cacheKeyGenerator = IdCacheKeyGenerator(), + cacheResolver = IdCacheKeyResolver() + ) + ) .returnPartialResponses(true) .build() .use { apolloClient -> @@ -495,7 +504,6 @@ class CachePartialResultTest { assertEquals( UserByCategoryQuery.Data( UserByCategoryQuery.User( - firstName = "John", lastName = "Smith", category = Category( @@ -516,6 +524,24 @@ class CachePartialResultTest { networkResult.data, cacheResult.data ) + + // Remove the category from the cache + apolloClient.apolloStore.accessCache { cache -> + val record = cache.loadRecord("User:1", CacheHeaders.NONE)!! + cache.remove(CacheKey("User", "1"), false) + cache.merge(Record(record.key, record.fields - "category"), CacheHeaders.NONE, DefaultRecordMerger) + } + val cacheMissResult = apolloClient.query(UserByCategoryQuery(Category(2, "Second"))) + .fetchPolicy(FetchPolicy.CacheOnly) + .execute() + // Due to null bubbling the whole data is null + assertNull(cacheMissResult.data) + assertErrorsEquals( + listOf( + Error.Builder("Object 'User:1' has no field named 'category' in the cache").path(listOf("user", "category")).build() + ), + cacheMissResult.errors + ) } } @@ -530,6 +556,14 @@ class CachePartialResultTest { "__typename": "User", "id": "1", "firstName0": "John", + "mainProject": { + "id": "1", + "lead0": { + "id": "2", + "__typename": "User", + "firstName": "Jane" + } + }, "lastName": "Smith", "nickName0": "JS", "email0": "jdoe@example.com", @@ -557,6 +591,14 @@ class CachePartialResultTest { __typename = "User", id = "1", firstName0 = "John", + mainProject = WithFragmentsQuery.MainProject( + id = "1", + lead0 = WithFragmentsQuery.Lead0( + id = "2", + __typename = "User", + firstName = "Jane", + ), + ), onUser = WithFragmentsQuery.OnUser( lastName = "Smith", onUser = WithFragmentsQuery.OnUser1( @@ -585,6 +627,49 @@ class CachePartialResultTest { networkResult.data, cacheResult.data ) + + // Remove lead from the cache + apolloClient.apolloStore.remove(CacheKey("User", "2")) + + val cacheMissResult = apolloClient.query(WithFragmentsQuery()) + .fetchPolicy(FetchPolicy.CacheOnly) + .execute() + assertEquals( + WithFragmentsQuery.Data( + WithFragmentsQuery.Me( + __typename = "User", + id = "1", + firstName0 = "John", + mainProject = WithFragmentsQuery.MainProject( + id = "1", + lead0 = null, + ), + onUser = WithFragmentsQuery.OnUser( + lastName = "Smith", + onUser = WithFragmentsQuery.OnUser1( + nickName0 = "JS" + ), + __typename = "User", + ), + userFields = UserFields( + email0 = "jdoe@example.com", + category = Category( + code = 1, + name = "First" + ), + id = "1", + __typename = "User", + ), + ) + ), + cacheMissResult.data + ) + assertErrorsEquals( + listOf( + Error.Builder("Object 'User:2' not found in the cache").path(listOf("me", "mainProject", "lead0")).build() + ), + cacheMissResult.errors + ) } } From c30fbf16e0f0ac8d144ee3e9403fdc7cf2d81aa0 Mon Sep 17 00:00:00 2001 From: BoD Date: Wed, 5 Feb 2025 17:15:48 +0100 Subject: [PATCH 10/11] Handle scalars outside of mapValues/map --- .../normalized/internal/DefaultApolloStore.kt | 26 +++++++++++-------- .../src/commonMain/graphql/operation.graphql | 1 + .../src/commonMain/graphql/schema.graphqls | 2 ++ .../kotlin/test/CachePartialResultTest.kt | 4 ++- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt index a679d1cd..dd89144c 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt @@ -222,11 +222,15 @@ internal class DefaultApolloStore( private fun propagateErrors(dataWithErrors: Any?, field: CompiledField, errors: MutableList): Any? { return when (dataWithErrors) { is Map<*, *> -> { + if (field.selections.isEmpty()) { + // This is a scalar represented as a Map. + return dataWithErrors + } @Suppress("UNCHECKED_CAST") dataWithErrors as Map dataWithErrors.mapValues { (key, value) -> val selection = field.fieldSelection(key) - ?: // Scalar + ?: // Should never happen return@mapValues value when (value) { is Error -> { @@ -249,16 +253,16 @@ internal class DefaultApolloStore( } is List<*> -> { - dataWithErrors.mapIndexed { index, value -> - val listType = if (field.type is CompiledNotNullType) { - (field.type as CompiledNotNullType).ofType as? CompiledListType - } else { - field.type as? CompiledListType - } - if (listType == null) { - // Scalar - return@mapIndexed value - } + val listType = if (field.type is CompiledNotNullType) { + (field.type as CompiledNotNullType).ofType + } else { + field.type + } + if (listType !is CompiledListType) { + // This is a scalar represented as a List. + return dataWithErrors + } + dataWithErrors.map { value -> val elementType = listType.ofType when (value) { is Error -> { diff --git a/tests/partial-results/src/commonMain/graphql/operation.graphql b/tests/partial-results/src/commonMain/graphql/operation.graphql index 7e881a18..bf99fea5 100644 --- a/tests/partial-results/src/commonMain/graphql/operation.graphql +++ b/tests/partial-results/src/commonMain/graphql/operation.graphql @@ -79,6 +79,7 @@ query UserByCategoryQuery($category: Category!) { firstName lastName category + moreInfo } } diff --git a/tests/partial-results/src/commonMain/graphql/schema.graphqls b/tests/partial-results/src/commonMain/graphql/schema.graphqls index 61ec3831..3de5e880 100644 --- a/tests/partial-results/src/commonMain/graphql/schema.graphqls +++ b/tests/partial-results/src/commonMain/graphql/schema.graphqls @@ -17,6 +17,7 @@ type User { projects: [Project!]! mainProject: Project! category: Category! + moreInfo: Json! } type Project { @@ -28,3 +29,4 @@ type Project { } scalar Category +scalar Json diff --git a/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt b/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt index 831b13a0..b9d3a783 100644 --- a/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt +++ b/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt @@ -480,7 +480,8 @@ class CachePartialResultTest { "category": { "code": 1, "name": "First" - } + }, + "moreInfo": [0, "no", false, {}, []] } } } @@ -510,6 +511,7 @@ class CachePartialResultTest { code = 1, name = "First" ), + moreInfo = listOf(0, "no", false, mapOf(), emptyList()), id = "1", __typename = "User", ) From 6e7befdd4cbb4c619af6f48e95b36be8eedb3800 Mon Sep 17 00:00:00 2001 From: BoD Date: Fri, 7 Feb 2025 20:02:41 +0100 Subject: [PATCH 11/11] Partial results is the default in ApolloStore. Bundled FetchPolicy interceptors still treat partial results as a cache miss --- .../api/normalized-cache-incubating.api | 7 ++- .../api/normalized-cache-incubating.klib.api | 6 +- .../cache/normalized/ApolloStore.kt | 9 +-- .../normalized/CacheMissLoggingInterceptor.kt | 4 +- .../cache/normalized/ClientCacheExtensions.kt | 29 +-------- .../cache/normalized/FetchPolicy.kt | 16 +++-- .../normalized/FetchPolicyInterceptors.kt | 23 +++++-- .../internal/ApolloCacheInterceptor.kt | 3 - .../normalized/internal/CacheBatchReader.kt | 2 + .../normalized/internal/DefaultApolloStore.kt | 61 ------------------- .../kotlin/test/CachePartialResultTest.kt | 51 ++++++++++------ 11 files changed, 78 insertions(+), 133 deletions(-) diff --git a/normalized-cache-incubating/api/normalized-cache-incubating.api b/normalized-cache-incubating/api/normalized-cache-incubating.api index 59a64475..26807113 100644 --- a/normalized-cache-incubating/api/normalized-cache-incubating.api +++ b/normalized-cache-incubating/api/normalized-cache-incubating.api @@ -8,7 +8,7 @@ public abstract interface class com/apollographql/cache/normalized/ApolloStore { public abstract fun normalize (Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/api/Operation$Data;Lcom/apollographql/apollo/api/CustomScalarAdapters;)Ljava/util/Map; public abstract fun publish (Ljava/util/Set;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun readFragment (Lcom/apollographql/apollo/api/Fragment;Lcom/apollographql/cache/normalized/api/CacheKey;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;)Lcom/apollographql/cache/normalized/ApolloStore$ReadResult; - public abstract fun readOperation (Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;Z)Lcom/apollographql/apollo/api/ApolloResponse; + public abstract fun readOperation (Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;)Lcom/apollographql/apollo/api/ApolloResponse; public abstract fun remove (Lcom/apollographql/cache/normalized/api/CacheKey;Z)Z public abstract fun remove (Ljava/util/List;Z)I public abstract fun rollbackOptimisticUpdates (Ljava/util/UUID;)Ljava/util/Set; @@ -24,7 +24,7 @@ public final class com/apollographql/cache/normalized/ApolloStore$Companion { public final class com/apollographql/cache/normalized/ApolloStore$DefaultImpls { public static synthetic fun readFragment$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/apollo/api/Fragment;Lcom/apollographql/cache/normalized/api/CacheKey;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;ILjava/lang/Object;)Lcom/apollographql/cache/normalized/ApolloStore$ReadResult; - public static synthetic fun readOperation$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;ZILjava/lang/Object;)Lcom/apollographql/apollo/api/ApolloResponse; + public static synthetic fun readOperation$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;ILjava/lang/Object;)Lcom/apollographql/apollo/api/ApolloResponse; public static synthetic fun remove$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/cache/normalized/api/CacheKey;ZILjava/lang/Object;)Z public static synthetic fun remove$default (Lcom/apollographql/cache/normalized/ApolloStore;Ljava/util/List;ZILjava/lang/Object;)I public static synthetic fun writeFragment$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/apollo/api/Fragment;Lcom/apollographql/cache/normalized/api/CacheKey;Lcom/apollographql/apollo/api/Fragment$Data;Lcom/apollographql/apollo/api/CustomScalarAdapters;Lcom/apollographql/cache/normalized/api/CacheHeaders;ILjava/lang/Object;)Ljava/util/Set; @@ -141,11 +141,13 @@ public final class com/apollographql/cache/normalized/NormalizedCache { public static final fun configureApolloClientBuilder2 (Lcom/apollographql/apollo/ApolloClient$Builder;Lcom/apollographql/cache/normalized/api/NormalizedCacheFactory;Lcom/apollographql/cache/normalized/api/CacheKeyGenerator;Lcom/apollographql/cache/normalized/api/MetadataGenerator;Lcom/apollographql/cache/normalized/api/CacheResolver;Lcom/apollographql/cache/normalized/api/RecordMerger;Lcom/apollographql/cache/normalized/api/FieldKeyGenerator;Lcom/apollographql/cache/normalized/api/EmbeddedFieldsProvider;Z)Lcom/apollographql/apollo/ApolloClient$Builder; public static synthetic fun configureApolloClientBuilder2$default (Lcom/apollographql/apollo/ApolloClient$Builder;Lcom/apollographql/cache/normalized/api/NormalizedCacheFactory;Lcom/apollographql/cache/normalized/api/CacheKeyGenerator;Lcom/apollographql/cache/normalized/api/MetadataGenerator;Lcom/apollographql/cache/normalized/api/CacheResolver;Lcom/apollographql/cache/normalized/api/RecordMerger;Lcom/apollographql/cache/normalized/api/FieldKeyGenerator;Lcom/apollographql/cache/normalized/api/EmbeddedFieldsProvider;ZILjava/lang/Object;)Lcom/apollographql/apollo/ApolloClient$Builder; public static final fun doNotStore (Lcom/apollographql/apollo/api/MutableExecutionOptions;Z)Ljava/lang/Object; + public static final fun fetchFromCache (Lcom/apollographql/apollo/api/ApolloRequest$Builder;Z)Lcom/apollographql/apollo/api/ApolloRequest$Builder; public static final fun fetchPolicy (Lcom/apollographql/apollo/api/MutableExecutionOptions;Lcom/apollographql/cache/normalized/FetchPolicy;)Ljava/lang/Object; public static final fun fetchPolicyInterceptor (Lcom/apollographql/apollo/api/MutableExecutionOptions;Lcom/apollographql/apollo/interceptor/ApolloInterceptor;)Ljava/lang/Object; public static final fun getApolloStore (Lcom/apollographql/apollo/ApolloClient;)Lcom/apollographql/cache/normalized/ApolloStore; public static final fun getCacheHeaders (Lcom/apollographql/apollo/api/ApolloResponse;)Lcom/apollographql/cache/normalized/api/CacheHeaders; public static final fun getCacheInfo (Lcom/apollographql/apollo/api/ApolloResponse;)Lcom/apollographql/cache/normalized/CacheInfo; + public static final fun getFetchFromCache (Lcom/apollographql/apollo/api/ApolloRequest;)Z public static final fun isFromCache (Lcom/apollographql/apollo/api/ApolloResponse;)Z public static final fun maxStale-HG0u8IE (Lcom/apollographql/apollo/api/MutableExecutionOptions;J)Ljava/lang/Object; public static final fun memoryCacheOnly (Lcom/apollographql/apollo/api/MutableExecutionOptions;Z)Ljava/lang/Object; @@ -153,7 +155,6 @@ public final class com/apollographql/cache/normalized/NormalizedCache { public static final fun optimisticUpdates (Lcom/apollographql/apollo/api/ApolloRequest$Builder;Lcom/apollographql/apollo/api/Mutation$Data;)Lcom/apollographql/apollo/api/ApolloRequest$Builder; public static final fun refetchPolicy (Lcom/apollographql/apollo/api/MutableExecutionOptions;Lcom/apollographql/cache/normalized/FetchPolicy;)Ljava/lang/Object; public static final fun refetchPolicyInterceptor (Lcom/apollographql/apollo/api/MutableExecutionOptions;Lcom/apollographql/apollo/interceptor/ApolloInterceptor;)Ljava/lang/Object; - public static final fun returnPartialResponses (Lcom/apollographql/apollo/api/MutableExecutionOptions;Z)Ljava/lang/Object; public static final fun store (Lcom/apollographql/apollo/ApolloClient$Builder;Lcom/apollographql/cache/normalized/ApolloStore;Z)Lcom/apollographql/apollo/ApolloClient$Builder; public static synthetic fun store$default (Lcom/apollographql/apollo/ApolloClient$Builder;Lcom/apollographql/cache/normalized/ApolloStore;ZILjava/lang/Object;)Lcom/apollographql/apollo/ApolloClient$Builder; public static final fun storeExpirationDate (Lcom/apollographql/apollo/api/MutableExecutionOptions;Z)Ljava/lang/Object; diff --git a/normalized-cache-incubating/api/normalized-cache-incubating.klib.api b/normalized-cache-incubating/api/normalized-cache-incubating.klib.api index a2ef1fd5..fe931702 100644 --- a/normalized-cache-incubating/api/normalized-cache-incubating.klib.api +++ b/normalized-cache-incubating/api/normalized-cache-incubating.klib.api @@ -84,7 +84,7 @@ abstract interface com.apollographql.cache.normalized/ApolloStore { // com.apoll abstract fun <#A1: com.apollographql.apollo.api/Fragment.Data> writeFragment(com.apollographql.apollo.api/Fragment<#A1>, com.apollographql.cache.normalized.api/CacheKey, #A1, com.apollographql.apollo.api/CustomScalarAdapters = ..., com.apollographql.cache.normalized.api/CacheHeaders = ...): kotlin.collections/Set // com.apollographql.cache.normalized/ApolloStore.writeFragment|writeFragment(com.apollographql.apollo.api.Fragment<0:0>;com.apollographql.cache.normalized.api.CacheKey;0:0;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheHeaders){0§}[0] abstract fun <#A1: com.apollographql.apollo.api/Fragment.Data> writeOptimisticUpdates(com.apollographql.apollo.api/Fragment<#A1>, com.apollographql.cache.normalized.api/CacheKey, #A1, com.benasher44.uuid/Uuid, com.apollographql.apollo.api/CustomScalarAdapters = ...): kotlin.collections/Set // com.apollographql.cache.normalized/ApolloStore.writeOptimisticUpdates|writeOptimisticUpdates(com.apollographql.apollo.api.Fragment<0:0>;com.apollographql.cache.normalized.api.CacheKey;0:0;com.benasher44.uuid.Uuid;com.apollographql.apollo.api.CustomScalarAdapters){0§}[0] abstract fun <#A1: com.apollographql.apollo.api/Operation.Data> normalize(com.apollographql.apollo.api/Operation<#A1>, #A1, com.apollographql.apollo.api/CustomScalarAdapters): kotlin.collections/Map // com.apollographql.cache.normalized/ApolloStore.normalize|normalize(com.apollographql.apollo.api.Operation<0:0>;0:0;com.apollographql.apollo.api.CustomScalarAdapters){0§}[0] - abstract fun <#A1: com.apollographql.apollo.api/Operation.Data> readOperation(com.apollographql.apollo.api/Operation<#A1>, com.apollographql.apollo.api/CustomScalarAdapters = ..., com.apollographql.cache.normalized.api/CacheHeaders = ..., kotlin/Boolean = ...): com.apollographql.apollo.api/ApolloResponse<#A1> // com.apollographql.cache.normalized/ApolloStore.readOperation|readOperation(com.apollographql.apollo.api.Operation<0:0>;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheHeaders;kotlin.Boolean){0§}[0] + abstract fun <#A1: com.apollographql.apollo.api/Operation.Data> readOperation(com.apollographql.apollo.api/Operation<#A1>, com.apollographql.apollo.api/CustomScalarAdapters = ..., com.apollographql.cache.normalized.api/CacheHeaders = ...): com.apollographql.apollo.api/ApolloResponse<#A1> // com.apollographql.cache.normalized/ApolloStore.readOperation|readOperation(com.apollographql.apollo.api.Operation<0:0>;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheHeaders){0§}[0] abstract fun <#A1: com.apollographql.apollo.api/Operation.Data> writeOperation(com.apollographql.apollo.api/Operation<#A1>, #A1, com.apollographql.apollo.api/CustomScalarAdapters = ..., com.apollographql.cache.normalized.api/CacheHeaders = ...): kotlin.collections/Set // com.apollographql.cache.normalized/ApolloStore.writeOperation|writeOperation(com.apollographql.apollo.api.Operation<0:0>;0:0;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheHeaders){0§}[0] abstract fun <#A1: com.apollographql.apollo.api/Operation.Data> writeOptimisticUpdates(com.apollographql.apollo.api/Operation<#A1>, #A1, com.benasher44.uuid/Uuid, com.apollographql.apollo.api/CustomScalarAdapters = ...): kotlin.collections/Set // com.apollographql.cache.normalized/ApolloStore.writeOptimisticUpdates|writeOptimisticUpdates(com.apollographql.apollo.api.Operation<0:0>;0:0;com.benasher44.uuid.Uuid;com.apollographql.apollo.api.CustomScalarAdapters){0§}[0] abstract fun <#A1: kotlin/Any?> accessCache(kotlin/Function1): #A1 // com.apollographql.cache.normalized/ApolloStore.accessCache|accessCache(kotlin.Function1){0§}[0] @@ -534,6 +534,8 @@ final val com.apollographql.cache.normalized/cacheHeaders // com.apollographql.c final fun <#A1: com.apollographql.apollo.api/Operation.Data> (com.apollographql.apollo.api/ApolloResponse<#A1>).(): com.apollographql.cache.normalized.api/CacheHeaders // com.apollographql.cache.normalized/cacheHeaders.|@com.apollographql.apollo.api.ApolloResponse<0:0>(){0§}[0] final val com.apollographql.cache.normalized/cacheInfo // com.apollographql.cache.normalized/cacheInfo|@com.apollographql.apollo.api.ApolloResponse<0:0>{0§}cacheInfo[0] final fun <#A1: com.apollographql.apollo.api/Operation.Data> (com.apollographql.apollo.api/ApolloResponse<#A1>).(): com.apollographql.cache.normalized/CacheInfo? // com.apollographql.cache.normalized/cacheInfo.|@com.apollographql.apollo.api.ApolloResponse<0:0>(){0§}[0] +final val com.apollographql.cache.normalized/fetchFromCache // com.apollographql.cache.normalized/fetchFromCache|@com.apollographql.apollo.api.ApolloRequest<0:0>{0§}fetchFromCache[0] + final fun <#A1: com.apollographql.apollo.api/Operation.Data> (com.apollographql.apollo.api/ApolloRequest<#A1>).(): kotlin/Boolean // com.apollographql.cache.normalized/fetchFromCache.|@com.apollographql.apollo.api.ApolloRequest<0:0>(){0§}[0] final val com.apollographql.cache.normalized/isFromCache // com.apollographql.cache.normalized/isFromCache|@com.apollographql.apollo.api.ApolloResponse<0:0>{0§}isFromCache[0] final fun <#A1: com.apollographql.apollo.api/Operation.Data> (com.apollographql.apollo.api/ApolloResponse<#A1>).(): kotlin/Boolean // com.apollographql.cache.normalized/isFromCache.|@com.apollographql.apollo.api.ApolloResponse<0:0>(){0§}[0] @@ -559,6 +561,7 @@ final fun <#A: com.apollographql.apollo.api/Executable.Data> (com.apollographql. final fun <#A: com.apollographql.apollo.api/Executable.Data> (com.apollographql.apollo.api/Executable<#A>).com.apollographql.cache.normalized.api/readDataFromCache(com.apollographql.cache.normalized.api/CacheKey, com.apollographql.apollo.api/CustomScalarAdapters, com.apollographql.cache.normalized.api/ReadOnlyNormalizedCache, com.apollographql.cache.normalized.api/CacheResolver, com.apollographql.cache.normalized.api/CacheHeaders, com.apollographql.cache.normalized.api/FieldKeyGenerator = ...): #A // com.apollographql.cache.normalized.api/readDataFromCache|readDataFromCache@com.apollographql.apollo.api.Executable<0:0>(com.apollographql.cache.normalized.api.CacheKey;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.ReadOnlyNormalizedCache;com.apollographql.cache.normalized.api.CacheResolver;com.apollographql.cache.normalized.api.CacheHeaders;com.apollographql.cache.normalized.api.FieldKeyGenerator){0§}[0] final fun <#A: com.apollographql.apollo.api/Mutation.Data> (com.apollographql.apollo.api/ApolloRequest.Builder<#A>).com.apollographql.cache.normalized/optimisticUpdates(#A): com.apollographql.apollo.api/ApolloRequest.Builder<#A> // com.apollographql.cache.normalized/optimisticUpdates|optimisticUpdates@com.apollographql.apollo.api.ApolloRequest.Builder<0:0>(0:0){0§}[0] final fun <#A: com.apollographql.apollo.api/Mutation.Data> (com.apollographql.apollo/ApolloCall<#A>).com.apollographql.cache.normalized/optimisticUpdates(#A): com.apollographql.apollo/ApolloCall<#A> // com.apollographql.cache.normalized/optimisticUpdates|optimisticUpdates@com.apollographql.apollo.ApolloCall<0:0>(0:0){0§}[0] +final fun <#A: com.apollographql.apollo.api/Operation.Data> (com.apollographql.apollo.api/ApolloRequest.Builder<#A>).com.apollographql.cache.normalized/fetchFromCache(kotlin/Boolean): com.apollographql.apollo.api/ApolloRequest.Builder<#A> // com.apollographql.cache.normalized/fetchFromCache|fetchFromCache@com.apollographql.apollo.api.ApolloRequest.Builder<0:0>(kotlin.Boolean){0§}[0] final fun <#A: com.apollographql.apollo.api/Operation.Data> (com.apollographql.apollo.api/ApolloResponse.Builder<#A>).com.apollographql.cache.normalized/cacheHeaders(com.apollographql.cache.normalized.api/CacheHeaders): com.apollographql.apollo.api/ApolloResponse.Builder<#A> // com.apollographql.cache.normalized/cacheHeaders|cacheHeaders@com.apollographql.apollo.api.ApolloResponse.Builder<0:0>(com.apollographql.cache.normalized.api.CacheHeaders){0§}[0] final fun <#A: com.apollographql.apollo.api/Operation.Data> (com.apollographql.apollo.api/Operation<#A>).com.apollographql.cache.normalized.api/normalize(#A, com.apollographql.apollo.api/CustomScalarAdapters, com.apollographql.cache.normalized.api/CacheKeyGenerator, com.apollographql.cache.normalized.api/MetadataGenerator = ..., com.apollographql.cache.normalized.api/FieldKeyGenerator = ..., com.apollographql.cache.normalized.api/EmbeddedFieldsProvider = ...): kotlin.collections/Map // com.apollographql.cache.normalized.api/normalize|normalize@com.apollographql.apollo.api.Operation<0:0>(0:0;com.apollographql.apollo.api.CustomScalarAdapters;com.apollographql.cache.normalized.api.CacheKeyGenerator;com.apollographql.cache.normalized.api.MetadataGenerator;com.apollographql.cache.normalized.api.FieldKeyGenerator;com.apollographql.cache.normalized.api.EmbeddedFieldsProvider){0§}[0] final fun <#A: com.apollographql.apollo.api/Query.Data> (com.apollographql.apollo/ApolloCall<#A>).com.apollographql.cache.normalized/watch(#A?): kotlinx.coroutines.flow/Flow> // com.apollographql.cache.normalized/watch|watch@com.apollographql.apollo.ApolloCall<0:0>(0:0?){0§}[0] @@ -572,7 +575,6 @@ final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOption final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/memoryCacheOnly(kotlin/Boolean): #A // com.apollographql.cache.normalized/memoryCacheOnly|memoryCacheOnly@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/refetchPolicy(com.apollographql.cache.normalized/FetchPolicy): #A // com.apollographql.cache.normalized/refetchPolicy|refetchPolicy@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(com.apollographql.cache.normalized.FetchPolicy){0§}[0] final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/refetchPolicyInterceptor(com.apollographql.apollo.interceptor/ApolloInterceptor): #A // com.apollographql.cache.normalized/refetchPolicyInterceptor|refetchPolicyInterceptor@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(com.apollographql.apollo.interceptor.ApolloInterceptor){0§}[0] -final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/returnPartialResponses(kotlin/Boolean): #A // com.apollographql.cache.normalized/returnPartialResponses|returnPartialResponses@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/storeExpirationDate(kotlin/Boolean): #A // com.apollographql.cache.normalized/storeExpirationDate|storeExpirationDate@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/storePartialResponses(kotlin/Boolean): #A // com.apollographql.cache.normalized/storePartialResponses|storePartialResponses@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] final fun <#A: kotlin/Any?> (com.apollographql.apollo.api/MutableExecutionOptions<#A>).com.apollographql.cache.normalized/storeReceiveDate(kotlin/Boolean): #A // com.apollographql.cache.normalized/storeReceiveDate|storeReceiveDate@com.apollographql.apollo.api.MutableExecutionOptions<0:0>(kotlin.Boolean){0§}[0] diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ApolloStore.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ApolloStore.kt index a98bb346..2fa5a9f8 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ApolloStore.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ApolloStore.kt @@ -57,23 +57,18 @@ interface ApolloStore { /** * Reads an operation from the store. * - * When [returnPartialResponses] is `false`, in case of missing data the returned [ApolloResponse.data] is `null` and - * [ApolloResponse.exception] is a [com.apollographql.apollo.exception.CacheMissException]. - * - * When [returnPartialResponses] is `true`, the returned [ApolloResponse.data] has `null` values for any missing fields if their - * type is nullable, bubbling up to their parent otherwise. Missing fields have a corresponding [com.apollographql.apollo.api.Error] + * The returned [ApolloResponse.data] has `null` values for any missing fields if their type is nullable, propagating up to their parent + * otherwise. Missing fields have a corresponding [com.apollographql.apollo.api.Error] * in [ApolloResponse.errors]. * * This is a synchronous operation that might block if the underlying cache is doing IO. * * @param operation the operation to read - * @param returnPartialResponses whether to return partial responses */ fun readOperation( operation: Operation, customScalarAdapters: CustomScalarAdapters = CustomScalarAdapters.Empty, cacheHeaders: CacheHeaders = CacheHeaders.NONE, - returnPartialResponses: Boolean = false, ): ApolloResponse /** diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/CacheMissLoggingInterceptor.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/CacheMissLoggingInterceptor.kt index 91eea381..7e26207f 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/CacheMissLoggingInterceptor.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/CacheMissLoggingInterceptor.kt @@ -12,8 +12,8 @@ import kotlinx.coroutines.flow.onEach class CacheMissLoggingInterceptor(private val log: (String) -> Unit) : ApolloInterceptor { override fun intercept(request: ApolloRequest, chain: ApolloInterceptorChain): Flow> { return chain.proceed(request).onEach { - if (it.exception is CacheMissException) { - log(it.exception!!.message.toString()) + it.errors.orEmpty().mapNotNull { it.extensions?.get("exception") as? CacheMissException }.forEach { + log(it.message.toString()) } } } diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ClientCacheExtensions.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ClientCacheExtensions.kt index 799395f9..b23a6ddc 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ClientCacheExtensions.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/ClientCacheExtensions.kt @@ -272,16 +272,6 @@ fun MutableExecutionOptions.storeReceiveDate(storeReceiveDate: Boolean) = StoreReceiveDateContext(storeReceiveDate) ) -/** - * @param returnPartialResponses Whether to return partial data from the cache (`true`), or no data with a [CacheMissException] whenever a field - * is missing (`false`). - * - * Default: false - */ -fun MutableExecutionOptions.returnPartialResponses(returnPartialResponses: Boolean) = addExecutionContext( - ReturnPartialResponsesContext(returnPartialResponses) -) - /** * @param storeExpirationDate Whether to store the expiration date in the cache. * @@ -415,9 +405,6 @@ internal val ExecutionOptions.cacheHeaders: CacheHeaders internal val ApolloRequest.watchContext: WatchContext? get() = executionContext[WatchContext] -internal val ApolloRequest.returnPartialResponses - get() = executionContext[ReturnPartialResponsesContext]?.value ?: false - class CacheInfo private constructor( val cacheStartMillis: Long, val cacheEndMillis: Long, @@ -430,20 +417,17 @@ class CacheInfo private constructor( val isFromCache: Boolean, /** - * True if all the fields are found in the cache, false for full or partial cache misses. + * True if **all** the fields are found in the cache, false for full or partial cache misses. */ val isCacheHit: Boolean, /** * The exception that occurred while reading the cache. - * Always `null` if [isFromCache] is false, or when partial responses are enabled. - * @see MutableExecutionOptions.returnPartialResponses */ val cacheMissException: CacheMissException?, /** * The exception that occurred while reading the network. - * Always `null` if [isFromCache] is true. */ val networkException: ApolloException?, @@ -636,18 +620,11 @@ internal class FetchFromCacheContext(val value: Boolean) : ExecutionContext.Elem companion object Key : ExecutionContext.Key } -internal class ReturnPartialResponsesContext(val value: Boolean) : ExecutionContext.Element { - override val key: ExecutionContext.Key<*> - get() = Key - - companion object Key : ExecutionContext.Key -} - -internal fun ApolloRequest.Builder.fetchFromCache(fetchFromCache: Boolean) = apply { +fun ApolloRequest.Builder.fetchFromCache(fetchFromCache: Boolean) = apply { addExecutionContext(FetchFromCacheContext(fetchFromCache)) } -internal val ApolloRequest.fetchFromCache +val ApolloRequest.fetchFromCache get() = executionContext[FetchFromCacheContext]?.value ?: false fun ApolloResponse.Builder.cacheHeaders(cacheHeaders: CacheHeaders) = diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/FetchPolicy.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/FetchPolicy.kt index 385c0f3e..ca7ec39f 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/FetchPolicy.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/FetchPolicy.kt @@ -1,11 +1,15 @@ package com.apollographql.cache.normalized +import com.apollographql.apollo.api.ApolloResponse +import com.apollographql.apollo.exception.ApolloException + enum class FetchPolicy { /** * Try the cache, if that failed, try the network. * * This [FetchPolicy] emits one or more [ApolloResponse]s. - * Cache misses and network errors have [ApolloResponse.exception] set to a non-null [ApolloException] + * Cache misses have [ApolloResponse.errors] set to a non-empty list. + * Network errors have [ApolloResponse.exception] set to a non-null [ApolloException]. * * This is the default behaviour. */ @@ -15,7 +19,7 @@ enum class FetchPolicy { * Only try the cache. * * This [FetchPolicy] emits one [ApolloResponse]. - * Cache misses have [ApolloResponse.exception] set to a non-null [ApolloException] + * Cache misses have [ApolloResponse.errors] set to a non-empty list. */ CacheOnly, @@ -23,7 +27,8 @@ enum class FetchPolicy { * Try the network, if that failed, try the cache. * * This [FetchPolicy] emits one or more [ApolloResponse]s. - * Cache misses and network errors have [ApolloResponse.exception] set to a non-null [ApolloException] + * Network errors have [ApolloResponse.exception] set to a non-null [ApolloException]. + * Cache misses have [ApolloResponse.errors] set to a non-empty list. */ NetworkFirst, @@ -32,7 +37,7 @@ enum class FetchPolicy { * * This [FetchPolicy] emits one or more [ApolloResponse]s. Several [ApolloResponse]s * may be emitted if your [NetworkTransport] supports it, for example with `@defer`. - * Network errors have [ApolloResponse.exception] set to a non-null [ApolloException] + * Network errors have [ApolloResponse.exception] set to a non-null [ApolloException]. */ NetworkOnly, @@ -40,7 +45,8 @@ enum class FetchPolicy { * Try the cache, then also try the network. * * This [FetchPolicy] emits two or more [ApolloResponse]s. - * Cache misses and network errors have [ApolloResponse.exception] set to a non-null [ApolloException] + * Cache misses have [ApolloResponse.errors] set to a non-empty list. + * Network errors have [ApolloResponse.exception] set to a non-null [ApolloException]. */ CacheAndNetwork, } diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/FetchPolicyInterceptors.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/FetchPolicyInterceptors.kt index 227e772e..ad7dff93 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/FetchPolicyInterceptors.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/FetchPolicyInterceptors.kt @@ -32,7 +32,7 @@ val CacheOnlyInterceptor = object : ApolloInterceptor { .newBuilder() .fetchFromCache(true) .build() - ) + ).map { it.cacheMissAsException() } } } @@ -56,7 +56,7 @@ val CacheFirstInterceptor = object : ApolloInterceptor { .newBuilder() .fetchFromCache(true) .build() - ).single() + ).single().cacheMissAsException() emit(cacheResponse.newBuilder().isLast(cacheResponse.exception == null).build()) if (cacheResponse.exception == null) { return@flow @@ -102,7 +102,7 @@ val NetworkFirstInterceptor = object : ApolloInterceptor { .newBuilder() .fetchFromCache(true) .build() - ).single() + ).single().cacheMissAsException() emit(cacheResponse) } } @@ -119,7 +119,7 @@ val CacheAndNetworkInterceptor = object : ApolloInterceptor { .newBuilder() .fetchFromCache(true) .build() - ).single() + ).single().cacheMissAsException() emit(cacheResponse.newBuilder().isLast(false).build()) @@ -129,6 +129,21 @@ val CacheAndNetworkInterceptor = object : ApolloInterceptor { } } +private fun ApolloResponse.cacheMissAsException(): ApolloResponse { + return if (cacheInfo!!.isCacheHit) { + this + } else { + val cacheMissException = errors.orEmpty().mapNotNull { it.extensions?.get("exception") as? ApolloException }.reduceOrNull { acc, e -> + acc.addSuppressed(e) + acc + } + newBuilder() + .exception(cacheMissException) + .data(null) + .build() + } +} + internal object FetchPolicyRouterInterceptor : ApolloInterceptor, ApolloStoreInterceptor { override fun intercept(request: ApolloRequest, chain: ApolloInterceptorChain): Flow> { if (request.operation !is Query) { diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/ApolloCacheInterceptor.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/ApolloCacheInterceptor.kt index f0dd654b..004d87b5 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/ApolloCacheInterceptor.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/ApolloCacheInterceptor.kt @@ -25,7 +25,6 @@ import com.apollographql.cache.normalized.doNotStore import com.apollographql.cache.normalized.fetchFromCache import com.apollographql.cache.normalized.memoryCacheOnly import com.apollographql.cache.normalized.optimisticData -import com.apollographql.cache.normalized.returnPartialResponses import com.apollographql.cache.normalized.storePartialResponses import com.apollographql.cache.normalized.storeReceiveDate import com.apollographql.cache.normalized.writeToCacheAsynchronously @@ -210,12 +209,10 @@ internal class ApolloCacheInterceptor( cacheHeaders += CacheHeaders.Builder().addHeader(ApolloCacheHeaders.MEMORY_CACHE_ONLY, "true").build() } val startMillis = currentTimeMillis() - val returnPartialResponses = request.returnPartialResponses val response = store.readOperation( operation = request.operation, customScalarAdapters = customScalarAdapters, cacheHeaders = cacheHeaders, - returnPartialResponses = returnPartialResponses, ) return response.newBuilder() .requestUuid(request.requestUuid) diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/CacheBatchReader.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/CacheBatchReader.kt index 68f88492..536974fa 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/CacheBatchReader.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/CacheBatchReader.kt @@ -148,6 +148,7 @@ internal class CacheBatchReader( ) ).unwrap() } catch (e: CacheMissException) { + if (e.stale) isStale = true if (returnPartialResponses) { cacheMissError(e, pendingReference.path + it.responseName) } else { @@ -232,6 +233,7 @@ internal class CacheBatchReader( ) ).unwrap() } catch (e: CacheMissException) { + if (e.stale) isStale = true if (returnPartialResponses) { cacheMissError(e, path + it.responseName) } else { diff --git a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt index dd89144c..9babb59d 100644 --- a/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt +++ b/normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/cache/normalized/internal/DefaultApolloStore.kt @@ -12,7 +12,6 @@ import com.apollographql.apollo.api.Fragment import com.apollographql.apollo.api.Operation import com.apollographql.apollo.api.json.jsonReader import com.apollographql.apollo.api.variables -import com.apollographql.apollo.exception.CacheMissException import com.apollographql.cache.normalized.ApolloStore import com.apollographql.cache.normalized.ApolloStore.ReadResult import com.apollographql.cache.normalized.CacheInfo @@ -123,66 +122,6 @@ internal class DefaultApolloStore( operation: Operation, customScalarAdapters: CustomScalarAdapters, cacheHeaders: CacheHeaders, - returnPartialResponses: Boolean, - ): ApolloResponse { - return if (returnPartialResponses) { - readOperationPartial(operation, customScalarAdapters, cacheHeaders) - } else { - readOperationCacheMissException(operation, customScalarAdapters, cacheHeaders) - } - } - - private fun readOperationCacheMissException( - operation: Operation, - customScalarAdapters: CustomScalarAdapters, - cacheHeaders: CacheHeaders, - ): ApolloResponse { - return try { - val variables = operation.variables(customScalarAdapters, true) - val batchReaderData = operation.readDataFromCacheInternal( - cache = cache, - cacheResolver = cacheResolver, - cacheHeaders = cacheHeaders, - cacheKey = CacheKey.rootKey(), - variables = variables, - fieldKeyGenerator = fieldKeyGenerator, - returnPartialResponses = false, - ) - val readResult = ReadResult( - data = batchReaderData.toData(operation.adapter(), customScalarAdapters, variables), - cacheHeaders = batchReaderData.cacheHeaders, - ) - ApolloResponse.Builder(operation, uuid4()) - .data(readResult.data) - .cacheHeaders(readResult.cacheHeaders) - .cacheInfo( - CacheInfo.Builder() - .fromCache(true) - .cacheHit(true) - .stale(readResult.cacheHeaders.headerValue(ApolloCacheHeaders.STALE) == "true") - .build() - ) - .build() - } catch (e: CacheMissException) { - ApolloResponse.Builder(operation, uuid4()) - .data(null) - .exception(e) - .cacheInfo( - CacheInfo.Builder() - .fromCache(true) - .cacheHit(false) - .cacheMissException(e) - .stale(e.stale) - .build() - ) - .build() - } - } - - private fun readOperationPartial( - operation: Operation, - customScalarAdapters: CustomScalarAdapters, - cacheHeaders: CacheHeaders, ): ApolloResponse { val variables = operation.variables(customScalarAdapters, true) val batchReaderData = operation.readDataFromCacheInternal( diff --git a/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt b/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt index b9d3a783..d4f22feb 100644 --- a/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt +++ b/tests/partial-results/src/commonTest/kotlin/test/CachePartialResultTest.kt @@ -1,8 +1,13 @@ package test import com.apollographql.apollo.ApolloClient +import com.apollographql.apollo.api.ApolloRequest +import com.apollographql.apollo.api.ApolloResponse import com.apollographql.apollo.api.Error import com.apollographql.apollo.api.Error.Location +import com.apollographql.apollo.api.Operation +import com.apollographql.apollo.interceptor.ApolloInterceptor +import com.apollographql.apollo.interceptor.ApolloInterceptorChain import com.apollographql.apollo.testing.internal.runTest import com.apollographql.cache.normalized.ApolloStore import com.apollographql.cache.normalized.FetchPolicy @@ -15,15 +20,17 @@ import com.apollographql.cache.normalized.api.IdCacheKeyResolver import com.apollographql.cache.normalized.api.Record import com.apollographql.cache.normalized.api.SchemaCoordinatesMaxAgeProvider import com.apollographql.cache.normalized.apolloStore +import com.apollographql.cache.normalized.fetchFromCache import com.apollographql.cache.normalized.fetchPolicy +import com.apollographql.cache.normalized.fetchPolicyInterceptor import com.apollographql.cache.normalized.memory.MemoryCacheFactory import com.apollographql.cache.normalized.normalizedCache -import com.apollographql.cache.normalized.returnPartialResponses import com.apollographql.cache.normalized.store import com.apollographql.cache.normalized.storePartialResponses import com.apollographql.cache.normalized.storeReceiveDate import com.apollographql.mockserver.MockServer import com.apollographql.mockserver.enqueueString +import kotlinx.coroutines.flow.Flow import okio.use import test.cache.Cache import test.fragment.UserFields @@ -65,7 +72,6 @@ class CachePartialResultTest { ApolloClient.Builder() .serverUrl(mockServer.url()) .normalizedCache(MemoryCacheFactory()) - .returnPartialResponses(true) .build() .use { apolloClient -> val networkResult = apolloClient.query(MeWithoutNickNameWithEmailQuery()) @@ -88,7 +94,7 @@ class CachePartialResultTest { ) val cacheResult = apolloClient.query(MeWithoutNickNameWithoutEmailQuery()) - .fetchPolicy(FetchPolicy.CacheOnly) + .fetchPolicyInterceptor(PartialCacheOnlyInterceptor) .execute() assertEquals( MeWithoutNickNameWithoutEmailQuery.Data( @@ -103,7 +109,7 @@ class CachePartialResultTest { ) val cacheMissResult = apolloClient.query(MeWithNickNameQuery()) - .fetchPolicy(FetchPolicy.CacheOnly) + .fetchPolicyInterceptor(PartialCacheOnlyInterceptor) .execute() assertEquals( MeWithNickNameQuery.Data( @@ -169,7 +175,6 @@ class CachePartialResultTest { cacheResolver = IdCacheKeyResolver() ) ) - .returnPartialResponses(true) .build() .use { apolloClient -> val networkResult = apolloClient.query(UsersQuery(listOf("1", "2", "3"))) @@ -200,7 +205,7 @@ class CachePartialResultTest { ) val cacheResult = apolloClient.query(UsersQuery(listOf("1", "2", "3"))) - .fetchPolicy(FetchPolicy.CacheOnly) + .fetchPolicyInterceptor(PartialCacheOnlyInterceptor) .execute() assertEquals( networkResult.data, @@ -260,7 +265,6 @@ class CachePartialResultTest { ApolloClient.Builder() .serverUrl(mockServer.url()) .normalizedCache(MemoryCacheFactory()) - .returnPartialResponses(true) .build() .use { apolloClient -> // Prime the cache @@ -306,7 +310,7 @@ class CachePartialResultTest { // Remove project lead from the cache apolloClient.apolloStore.remove(CacheKey("User", "3")) val cacheResult = apolloClient.query(MeWithBestFriendQuery()) - .fetchPolicy(FetchPolicy.CacheOnly) + .fetchPolicyInterceptor(PartialCacheOnlyInterceptor) .execute() assertEquals( MeWithBestFriendQuery.Data( @@ -348,7 +352,7 @@ class CachePartialResultTest { // Remove best friend from the cache apolloClient.apolloStore.remove(CacheKey("User", "2")) val cacheResult2 = apolloClient.query(MeWithBestFriendQuery()) - .fetchPolicy(FetchPolicy.CacheOnly) + .fetchPolicyInterceptor(PartialCacheOnlyInterceptor) .execute() assertEquals( MeWithBestFriendQuery.Data( @@ -386,7 +390,7 @@ class CachePartialResultTest { // Remove project user from the cache apolloClient.apolloStore.remove(CacheKey("User", "4")) val cacheResult3 = apolloClient.query(MeWithBestFriendQuery()) - .fetchPolicy(FetchPolicy.CacheOnly) + .fetchPolicyInterceptor(PartialCacheOnlyInterceptor) .execute() // Due to null bubbling the whole data is null assertNull(cacheResult3.data) @@ -433,7 +437,6 @@ class CachePartialResultTest { cacheResolver = IdCacheKeyResolver() ) ) - .returnPartialResponses(true) .build() .use { apolloClient -> val networkResult = apolloClient.query(DefaultProjectQuery()) @@ -456,7 +459,7 @@ class CachePartialResultTest { ) val cacheResult = apolloClient.query(DefaultProjectQuery()) - .fetchPolicy(FetchPolicy.CacheOnly) + .fetchPolicyInterceptor(PartialCacheOnlyInterceptor) .execute() assertEquals( networkResult.data, @@ -496,7 +499,6 @@ class CachePartialResultTest { cacheResolver = IdCacheKeyResolver() ) ) - .returnPartialResponses(true) .build() .use { apolloClient -> val networkResult = apolloClient.query(UserByCategoryQuery(Category(2, "Second"))) @@ -520,7 +522,7 @@ class CachePartialResultTest { ) val cacheResult = apolloClient.query(UserByCategoryQuery(Category(2, "Second"))) - .fetchPolicy(FetchPolicy.CacheOnly) + .fetchPolicyInterceptor(PartialCacheOnlyInterceptor) .execute() assertEquals( networkResult.data, @@ -534,7 +536,7 @@ class CachePartialResultTest { cache.merge(Record(record.key, record.fields - "category"), CacheHeaders.NONE, DefaultRecordMerger) } val cacheMissResult = apolloClient.query(UserByCategoryQuery(Category(2, "Second"))) - .fetchPolicy(FetchPolicy.CacheOnly) + .fetchPolicyInterceptor(PartialCacheOnlyInterceptor) .execute() // Due to null bubbling the whole data is null assertNull(cacheMissResult.data) @@ -581,7 +583,6 @@ class CachePartialResultTest { ApolloClient.Builder() .serverUrl(mockServer.url()) .normalizedCache(MemoryCacheFactory()) - .returnPartialResponses(true) .build() .use { apolloClient -> val networkResult = apolloClient.query(WithFragmentsQuery()) @@ -623,7 +624,7 @@ class CachePartialResultTest { ) val cacheResult = apolloClient.query(WithFragmentsQuery()) - .fetchPolicy(FetchPolicy.CacheOnly) + .fetchPolicyInterceptor(PartialCacheOnlyInterceptor) .execute() assertEquals( networkResult.data, @@ -634,7 +635,7 @@ class CachePartialResultTest { apolloClient.apolloStore.remove(CacheKey("User", "2")) val cacheMissResult = apolloClient.query(WithFragmentsQuery()) - .fetchPolicy(FetchPolicy.CacheOnly) + .fetchPolicyInterceptor(PartialCacheOnlyInterceptor) .execute() assertEquals( WithFragmentsQuery.Data( @@ -697,7 +698,6 @@ class CachePartialResultTest { .serverUrl(mockServer.url()) .normalizedCache(MemoryCacheFactory(), cacheResolver = CacheControlCacheResolver(SchemaCoordinatesMaxAgeProvider(Cache.maxAges, Duration.INFINITE))) .storeReceiveDate(true) - .returnPartialResponses(true) .build() .use { apolloClient -> val networkResult = apolloClient.query(MeWithNickNameQuery()) @@ -717,7 +717,7 @@ class CachePartialResultTest { ) val cacheMissResult = apolloClient.query(MeWithNickNameQuery()) - .fetchPolicy(FetchPolicy.CacheOnly) + .fetchPolicyInterceptor(PartialCacheOnlyInterceptor) .execute() assertEquals( MeWithNickNameQuery.Data( @@ -741,6 +741,17 @@ class CachePartialResultTest { } } +val PartialCacheOnlyInterceptor = object : ApolloInterceptor { + override fun intercept(request: ApolloRequest, chain: ApolloInterceptorChain): Flow> { + return chain.proceed( + request = request + .newBuilder() + .fetchFromCache(true) + .build() + ) + } +} + /** * Helps using assertEquals. */