Skip to content

Add ApolloStore.ALL_KEYS to notify all watchers #87

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 4 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Next version (unreleased)

PUT_CHANGELOG_HERE
- Add `ApolloStore.ALL_KEYS` to notify all watchers (#87)

# Version 0.0.5
_2024-12-18_
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
public abstract interface class com/apollographql/cache/normalized/ApolloStore {
public static final field Companion Lcom/apollographql/cache/normalized/ApolloStore$Companion;
public abstract fun accessCache (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public abstract fun clearAll ()Z
public abstract fun dispose ()V
Expand All @@ -17,6 +18,10 @@ public abstract interface class com/apollographql/cache/normalized/ApolloStore {
public abstract fun writeOptimisticUpdates (Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/api/Operation$Data;Ljava/util/UUID;Lcom/apollographql/apollo/api/CustomScalarAdapters;)Ljava/util/Set;
}

public final class com/apollographql/cache/normalized/ApolloStore$Companion {
public final fun getALL_KEYS ()Lkotlin/collections/AbstractSet;
}

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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ abstract interface com.apollographql.cache.normalized/ApolloStore { // com.apoll
final val data // com.apollographql.cache.normalized/ApolloStore.ReadResult.data|{}data[0]
final fun <get-data>(): #A1 // com.apollographql.cache.normalized/ApolloStore.ReadResult.data.<get-data>|<get-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 <get-ALL_KEYS>(): kotlin.collections/AbstractSet<kotlin/String> // com.apollographql.cache.normalized/ApolloStore.Companion.ALL_KEYS.<get-ALL_KEYS>|<get-ALL_KEYS>(){}[0]
}
}
final class com.apollographql.cache.normalized.api/CacheControlCacheResolver : com.apollographql.cache.normalized.api/CacheResolver { // com.apollographql.cache.normalized.api/CacheControlCacheResolver|null[0]
constructor <init>(com.apollographql.cache.normalized.api/CacheResolver = ...) // com.apollographql.cache.normalized.api/CacheControlCacheResolver.<init>|<init>(com.apollographql.cache.normalized.api.CacheResolver){}[0]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,22 @@ import kotlin.reflect.KClass
interface ApolloStore {
/**
* Exposes the keys of records that have changed.
* A special key [ALL_KEYS] is used to indicate that all records have changed.
*/
val changedKeys: SharedFlow<Set<String>>

companion object {
val ALL_KEYS = object : AbstractSet<String>() {
override val size = 0

override fun iterator() = emptySet<String>().iterator()

override fun equals(other: Any?) = other === this

override fun hashCode() = 0
}
}

/**
* Reads an operation from the store.
*
Expand Down Expand Up @@ -214,6 +227,8 @@ interface ApolloStore {
/**
* Publishes a set of keys that have changed. This will notify subscribers of [changedKeys].
*
* Pass [ALL_KEYS] to indicate that all records have changed, for instance after a [clearAll] operation.
*
* @see changedKeys
*
* @param keys A set of keys of [Record] which have changed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ internal class DefaultApolloStore(
}

override suspend fun publish(keys: Set<String>) {
if (keys.isEmpty()) {
if (keys.isEmpty() && keys !== ApolloStore.ALL_KEYS) {
return
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ internal class WatcherInterceptor(val store: ApolloStore) : ApolloInterceptor, A
emit(Unit)
}
.filter { changedKeys ->
if (changedKeys !is Set<*>) {
return@filter true
}
watchedKeys == null || changedKeys.intersect(watchedKeys!!).isNotEmpty()
changedKeys !is Set<*> ||
changedKeys === ApolloStore.ALL_KEYS ||
watchedKeys == null ||
changedKeys.intersect(watchedKeys!!).isNotEmpty()
}.map {
if (it == Unit) {
flowOf(ApolloResponse.Builder(request.operation, request.requestUuid).exception(WatcherSentinel).build())
Expand Down
22 changes: 22 additions & 0 deletions tests/normalized-cache/src/commonTest/kotlin/WatcherTest.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package test

import app.cash.turbine.test
import com.apollographql.apollo.ApolloClient
import com.apollographql.apollo.api.ApolloResponse
import com.apollographql.apollo.api.CustomScalarAdapters
Expand Down Expand Up @@ -642,6 +643,27 @@ class WatcherTest {
job.cancel()
}

@Test
fun publishAllKeys() = runTest(before = { setUp() }) {
val query = EpisodeHeroNameQuery(Episode.EMPIRE)
apolloClient.query(query)
.fetchPolicy(FetchPolicy.CacheOnly)
.watch()
.test {
// Start empty
assertIs<CacheMissException>(awaitItem().exception)

// Add data to the cache
apolloClient.enqueueTestResponse(query, episodeHeroNameData)
apolloClient.query(query).fetchPolicy(FetchPolicy.NetworkOnly).execute()
assertEquals("R2-D2", awaitItem().data?.hero?.name)

// Clear the cache
store.clearAll()
store.publish(ApolloStore.ALL_KEYS)
assertIs<CacheMissException>(awaitItem().exception)
}
}
}

internal suspend fun <D> Channel<D>.assertCount(count: Int) {
Expand Down