Skip to content

Make SimpleApolloStore.apolloStore public and add SimpleApolloStore GC extensions #134

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Apr 28, 2025
8 changes: 8 additions & 0 deletions normalized-cache/api/normalized-cache.api
Original file line number Diff line number Diff line change
Expand Up @@ -121,17 +121,23 @@ public final class com/apollographql/cache/normalized/GarbageCollectResult {
public final class com/apollographql/cache/normalized/GarbageCollectionKt {
public static final fun allRecords (Lcom/apollographql/cache/normalized/api/NormalizedCache;)Ljava/util/Map;
public static final fun garbageCollect-SxA4cEA (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/cache/normalized/api/MaxAgeProvider;J)Lcom/apollographql/cache/normalized/GarbageCollectResult;
public static final fun garbageCollect-SxA4cEA (Lcom/apollographql/cache/normalized/SimpleApolloStore;Lcom/apollographql/cache/normalized/api/MaxAgeProvider;J)Lcom/apollographql/cache/normalized/GarbageCollectResult;
public static final fun garbageCollect-SxA4cEA (Lcom/apollographql/cache/normalized/api/NormalizedCache;Lcom/apollographql/cache/normalized/api/MaxAgeProvider;J)Lcom/apollographql/cache/normalized/GarbageCollectResult;
public static synthetic fun garbageCollect-SxA4cEA$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/cache/normalized/api/MaxAgeProvider;JILjava/lang/Object;)Lcom/apollographql/cache/normalized/GarbageCollectResult;
public static synthetic fun garbageCollect-SxA4cEA$default (Lcom/apollographql/cache/normalized/SimpleApolloStore;Lcom/apollographql/cache/normalized/api/MaxAgeProvider;JILjava/lang/Object;)Lcom/apollographql/cache/normalized/GarbageCollectResult;
public static synthetic fun garbageCollect-SxA4cEA$default (Lcom/apollographql/cache/normalized/api/NormalizedCache;Lcom/apollographql/cache/normalized/api/MaxAgeProvider;JILjava/lang/Object;)Lcom/apollographql/cache/normalized/GarbageCollectResult;
public static final fun getReachableCacheKeys (Ljava/util/Map;)Ljava/util/Set;
public static final fun removeDanglingReferences (Lcom/apollographql/cache/normalized/ApolloStore;)Lcom/apollographql/cache/normalized/RemovedFieldsAndRecords;
public static final fun removeDanglingReferences (Lcom/apollographql/cache/normalized/SimpleApolloStore;)Lcom/apollographql/cache/normalized/RemovedFieldsAndRecords;
public static final fun removeDanglingReferences (Lcom/apollographql/cache/normalized/api/NormalizedCache;)Lcom/apollographql/cache/normalized/RemovedFieldsAndRecords;
public static final fun removeStaleFields-SxA4cEA (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/cache/normalized/api/MaxAgeProvider;J)Lcom/apollographql/cache/normalized/RemovedFieldsAndRecords;
public static final fun removeStaleFields-SxA4cEA (Lcom/apollographql/cache/normalized/SimpleApolloStore;Lcom/apollographql/cache/normalized/api/MaxAgeProvider;J)Lcom/apollographql/cache/normalized/RemovedFieldsAndRecords;
public static final fun removeStaleFields-SxA4cEA (Lcom/apollographql/cache/normalized/api/NormalizedCache;Lcom/apollographql/cache/normalized/api/MaxAgeProvider;J)Lcom/apollographql/cache/normalized/RemovedFieldsAndRecords;
public static synthetic fun removeStaleFields-SxA4cEA$default (Lcom/apollographql/cache/normalized/ApolloStore;Lcom/apollographql/cache/normalized/api/MaxAgeProvider;JILjava/lang/Object;)Lcom/apollographql/cache/normalized/RemovedFieldsAndRecords;
public static synthetic fun removeStaleFields-SxA4cEA$default (Lcom/apollographql/cache/normalized/SimpleApolloStore;Lcom/apollographql/cache/normalized/api/MaxAgeProvider;JILjava/lang/Object;)Lcom/apollographql/cache/normalized/RemovedFieldsAndRecords;
public static synthetic fun removeStaleFields-SxA4cEA$default (Lcom/apollographql/cache/normalized/api/NormalizedCache;Lcom/apollographql/cache/normalized/api/MaxAgeProvider;JILjava/lang/Object;)Lcom/apollographql/cache/normalized/RemovedFieldsAndRecords;
public static final fun removeUnreachableRecords (Lcom/apollographql/cache/normalized/ApolloStore;)Ljava/util/Set;
public static final fun removeUnreachableRecords (Lcom/apollographql/cache/normalized/SimpleApolloStore;)Ljava/util/Set;
public static final fun removeUnreachableRecords (Lcom/apollographql/cache/normalized/api/NormalizedCache;)Ljava/util/Set;
}

Expand Down Expand Up @@ -190,7 +196,9 @@ public final class com/apollographql/cache/normalized/SimpleApolloStore {
public final fun clearAll ()Z
public final fun dispose ()V
public final fun dump ()Ljava/util/Map;
public final fun getApolloStore ()Lcom/apollographql/cache/normalized/ApolloStore;
public final fun getChangedKeys ()Lkotlinx/coroutines/flow/SharedFlow;
public final fun getCustomScalarAdapters ()Lcom/apollographql/apollo/api/CustomScalarAdapters;
public final fun normalize-Hljz6HE (Lcom/apollographql/apollo/api/Executable;Ljava/util/Map;Ljava/lang/String;)Ljava/util/Map;
public static synthetic fun normalize-Hljz6HE$default (Lcom/apollographql/cache/normalized/SimpleApolloStore;Lcom/apollographql/apollo/api/Executable;Ljava/util/Map;Ljava/lang/String;ILjava/lang/Object;)Ljava/util/Map;
public final fun publish (Ljava/util/Set;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
Expand Down
8 changes: 8 additions & 0 deletions normalized-cache/api/normalized-cache.klib.api
Original file line number Diff line number Diff line change
Expand Up @@ -473,8 +473,12 @@ final class com.apollographql.cache.normalized/RemovedFieldsAndRecords { // com.
final class com.apollographql.cache.normalized/SimpleApolloStore { // com.apollographql.cache.normalized/SimpleApolloStore|null[0]
constructor <init>(com.apollographql.cache.normalized/ApolloStore, com.apollographql.apollo.api/CustomScalarAdapters) // com.apollographql.cache.normalized/SimpleApolloStore.<init>|<init>(com.apollographql.cache.normalized.ApolloStore;com.apollographql.apollo.api.CustomScalarAdapters){}[0]

final val apolloStore // com.apollographql.cache.normalized/SimpleApolloStore.apolloStore|{}apolloStore[0]
final fun <get-apolloStore>(): com.apollographql.cache.normalized/ApolloStore // com.apollographql.cache.normalized/SimpleApolloStore.apolloStore.<get-apolloStore>|<get-apolloStore>(){}[0]
final val changedKeys // com.apollographql.cache.normalized/SimpleApolloStore.changedKeys|{}changedKeys[0]
final fun <get-changedKeys>(): kotlinx.coroutines.flow/SharedFlow<kotlin.collections/Set<kotlin/String>> // com.apollographql.cache.normalized/SimpleApolloStore.changedKeys.<get-changedKeys>|<get-changedKeys>(){}[0]
final val customScalarAdapters // com.apollographql.cache.normalized/SimpleApolloStore.customScalarAdapters|{}customScalarAdapters[0]
final fun <get-customScalarAdapters>(): com.apollographql.apollo.api/CustomScalarAdapters // com.apollographql.cache.normalized/SimpleApolloStore.customScalarAdapters.<get-customScalarAdapters>|<get-customScalarAdapters>(){}[0]

final fun <#A1: com.apollographql.apollo.api/Executable.Data> normalize(com.apollographql.apollo.api/Executable<#A1>, kotlin.collections/Map<kotlin/String, kotlin/Any?>, com.apollographql.cache.normalized.api/CacheKey = ...): kotlin.collections/Map<com.apollographql.cache.normalized.api/CacheKey, com.apollographql.cache.normalized.api/Record> // com.apollographql.cache.normalized/SimpleApolloStore.normalize|normalize(com.apollographql.apollo.api.Executable<0:0>;kotlin.collections.Map<kotlin.String,kotlin.Any?>;com.apollographql.cache.normalized.api.CacheKey){0§<com.apollographql.apollo.api.Executable.Data>}[0]
final fun <#A1: com.apollographql.apollo.api/Fragment.Data> readFragment(com.apollographql.apollo.api/Fragment<#A1>, com.apollographql.cache.normalized.api/CacheKey, com.apollographql.cache.normalized.api/CacheHeaders = ...): com.apollographql.cache.normalized/ApolloStore.ReadResult<#A1> // com.apollographql.cache.normalized/SimpleApolloStore.readFragment|readFragment(com.apollographql.apollo.api.Fragment<0:0>;com.apollographql.cache.normalized.api.CacheKey;com.apollographql.cache.normalized.api.CacheHeaders){0§<com.apollographql.apollo.api.Fragment.Data>}[0]
Expand Down Expand Up @@ -612,6 +616,10 @@ final fun (com.apollographql.cache.normalized/ApolloStore).com.apollographql.cac
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.api/CacheKey> // com.apollographql.cache.normalized/removeUnreachableRecords|removeUnreachableRecords@com.apollographql.cache.normalized.ApolloStore(){}[0]
final fun (com.apollographql.cache.normalized/SimpleApolloStore).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.SimpleApolloStore(com.apollographql.cache.normalized.api.MaxAgeProvider;kotlin.time.Duration){}[0]
final fun (com.apollographql.cache.normalized/SimpleApolloStore).com.apollographql.cache.normalized/removeDanglingReferences(): com.apollographql.cache.normalized/RemovedFieldsAndRecords // com.apollographql.cache.normalized/removeDanglingReferences|removeDanglingReferences@com.apollographql.cache.normalized.SimpleApolloStore(){}[0]
final fun (com.apollographql.cache.normalized/SimpleApolloStore).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.SimpleApolloStore(com.apollographql.cache.normalized.api.MaxAgeProvider;kotlin.time.Duration){}[0]
final fun (com.apollographql.cache.normalized/SimpleApolloStore).com.apollographql.cache.normalized/removeUnreachableRecords(): kotlin.collections/Set<com.apollographql.cache.normalized.api/CacheKey> // com.apollographql.cache.normalized/removeUnreachableRecords|removeUnreachableRecords@com.apollographql.cache.normalized.SimpleApolloStore(){}[0]
final fun (kotlin.collections/Collection<com.apollographql.cache.normalized.api/Record>?).com.apollographql.cache.normalized.api/dependentKeys(): kotlin.collections/Set<kotlin/String> // com.apollographql.cache.normalized.api/dependentKeys|dependentKeys@kotlin.collections.Collection<com.apollographql.cache.normalized.api.Record>?(){}[0]
final fun (kotlin.collections/Map<com.apollographql.cache.normalized.api/CacheKey, com.apollographql.cache.normalized.api/Record>).com.apollographql.cache.normalized/getReachableCacheKeys(): kotlin.collections/Set<com.apollographql.cache.normalized.api/CacheKey> // com.apollographql.cache.normalized/getReachableCacheKeys|getReachableCacheKeys@kotlin.collections.Map<com.apollographql.cache.normalized.api.CacheKey,com.apollographql.cache.normalized.api.Record>(){}[0]
final fun <#A: com.apollographql.apollo.api/Executable.Data> (#A).com.apollographql.cache.normalized.api/withErrors(com.apollographql.apollo.api/Executable<#A>, kotlin.collections/List<com.apollographql.apollo.api/Error>?, com.apollographql.apollo.api/CustomScalarAdapters = ...): kotlin.collections/Map<kotlin/String, kotlin/Any?> // com.apollographql.cache.normalized.api/withErrors|withErrors@0:0(com.apollographql.apollo.api.Executable<0:0>;kotlin.collections.List<com.apollographql.apollo.api.Error>?;com.apollographql.apollo.api.CustomScalarAdapters){0§<com.apollographql.apollo.api.Executable.Data>}[0]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ fun ApolloStore.removeUnreachableRecords(): Set<CacheKey> {
}
}

/**
* @see removeUnreachableRecords
*/
fun SimpleApolloStore.removeUnreachableRecords() = apolloStore.removeUnreachableRecords()

/**
* Remove all stale fields in the cache.
* A field is stale if its received date is older than its max age (configurable via [maxAgeProvider]) or if its expiration date has
Expand Down Expand Up @@ -186,6 +191,16 @@ fun ApolloStore.removeStaleFields(
}
}

/**
* @see removeStaleFields
*/
fun SimpleApolloStore.removeStaleFields(
maxAgeProvider: MaxAgeProvider,
maxStale: Duration = Duration.ZERO,
): RemovedFieldsAndRecords {
return apolloStore.removeStaleFields(maxAgeProvider, maxStale)
}

/**
* Remove all dangling references in the cache.
* A field is a dangling reference if its value (or, for lists, any of its values) is a reference to a record that does not exist.
Expand Down Expand Up @@ -248,6 +263,13 @@ fun ApolloStore.removeDanglingReferences(): RemovedFieldsAndRecords {
}
}

/**
* @see removeDanglingReferences
*/
fun SimpleApolloStore.removeDanglingReferences(): RemovedFieldsAndRecords {
return apolloStore.removeDanglingReferences()
}

private fun RecordValue.isDanglingReference(allRecords: Map<CacheKey, Record>): Boolean {
return when (this) {
is CacheKey -> allRecords[this] == null
Expand Down Expand Up @@ -317,6 +339,16 @@ fun ApolloStore.garbageCollect(
}
}

/**
* @see garbageCollect
*/
fun SimpleApolloStore.garbageCollect(
maxAgeProvider: MaxAgeProvider,
maxStale: Duration = Duration.ZERO,
): GarbageCollectResult {
return apolloStore.garbageCollect(maxAgeProvider, maxStale)
}

class RemovedFieldsAndRecords(
val removedFields: Set<String>,
val removedRecords: Set<CacheKey>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import kotlin.reflect.KClass
* A wrapper around [ApolloStore] that provides a simplified API for reading and writing data.
*/
class SimpleApolloStore(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not directly related to this PR but I would probably do the opposite naming choice. Keep ApolloStore for the thing that is used the most (this) and use something else for ApolloStore. Maybe even possibly hide it from public API altogether?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm we still need both the wrapper and the “wrapped” to be public because setting it takes the wrapped but getting returns the wrapper

// setting
fun ApolloClient.Builder.store(store: ApolloStore, writeToCacheAsynchronously: Boolean = false): ApolloClient.Builder

// getting
val ApolloClient.store: SimpleApolloStore

Re: naming, we could do ApolloStoreIApolloStore and SimpleApolloStoreApolloStore but not super fan of I and it’s different from what we do elsewhere.

Maybe at least SimpleApolloStore should be called something else (but not sure what!), since it’s not an ApolloStore implem.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting it doesn't really need a store, does it? I suspect most of the users use the .normalizedCache() function, and not .store()?

The only use case for using .store() is if someone wants to use their own ApolloStore implementation but I'm not sure what that would be useful for....

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect most of the users use the .normalizedCache() function, and not .store()?

Most probably yes (that's what we show in the docs).

Also not sure of specific use cases to bring your own implementation (but IIRC Netflix does it 😅) - but I think it's a nice flexibility to be able to do it and would be a bit sad to remove it IMO.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed, .apolloStore now returns ApolloStore, which is the wrapper. The interface is now called CacheManager.

private val apolloStore: ApolloStore,
private val customScalarAdapters: CustomScalarAdapters,
val apolloStore: ApolloStore,
val customScalarAdapters: CustomScalarAdapters,
) {
/**
* @see ApolloStore.changedKeys
Expand Down