I’m using Apollo Kotlin with a normalized cache (Memory + SQL cache chaining) in a Supabase GraphQL setup. For simple (flat) queries and mutations, the cache updates correctly and watch() emits updates to the UI as expected.
However, when dealing with nested objects, specifically a favorites → quotes → nested collections structure, mutations (insert/delete) do not trigger UI updates via watch() even though the mutation returns the same nested structure.
I'm trying to understand whether this is:
- a limitation/bug in Apollo normalized cache
- or an issue with my cache configuration / schema policies
Environment
- Apollo Kotlin: 4.4.2
- Normalized cache: 1.0.1
- Backend: Supabase
Cache Configuration
val chainedCacheFactory = MemoryCacheFactory(maxSizeBytes = 10 * 1024 * 1024)
.chain(sqlCacheFactory)
install(GraphQL) {
apolloConfiguration {
cache(
normalizedCacheFactory = chainedCacheFactory,
keyScope = CacheKey.Scope.SERVICE
)
}
}
Type Policies
extend type Query @fieldPolicy(forField: "favoritesCollection", keyArgs: "filter")
extend type favorites @typePolicy(keyFields: "id quote_id") @cacheControl(maxAge: 7776000)
extend type Query @fieldPolicy(forField: "quotesCollection", keyArgs: "filter")
extend type quotes @typePolicy(keyFields: "id") @cacheControl(maxAge: 7776000)
extend type Query @fieldPolicy(forField: "book_sectionsCollection", keyArgs: "filter")
extend type book_sections @typePolicy(keyFields: "id") @cacheControl(maxAge: 7776000)
extend type Query @fieldPolicy(forField: "booksCollection", keyArgs: "filter")
extend type books @typePolicy(keyFields: "id") @cacheControl(maxAge: 7776000)
extend type Query @fieldPolicy(forField: "quote_questionsCollection", keyArgs: "filter")
extend type quote_questions @typePolicy(keyFields: "id") @cacheControl(maxAge: 7776000)
Query
query GetFavoriteQuotes($userId: UUID!, $limit: Int, $offset: Int) {
favoritesCollection(
filter: { id: { eq: $userId } }
first: $limit
offset: $offset
) {
edges {
node {
id
quote_id
__typename
quotes {
id
__typename
book_sectionsCollection {
edges {
node {
books {
id
name
__typename
}
}
}
}
quote_questionsCollection {
edges {
node {
id
question_text
__typename
}
}
}
}
}
}
}
}
Mutations
Insert
mutation InsertFavoriteQuote($userId: UUID!, $quoteId: Int!) {
insertIntofavoritesCollection(objects: { id: $userId, quote_id: $quoteId }) {
records {
id
quote_id
__typename
quotes {
id
__typename
...
}
}
}
}
Delete
mutation DeleteFavoriteQuote($userId: UUID!, $quoteId: Int!) {
deleteFromfavoritesCollection(
filter: { id: { eq: $userId }, quote_id: { eq: $quoteId } }
atMost: 1
) {
records {
id
quote_id
__typename
quotes {
id
__typename
...
}
}
}
}
Repository Code
override suspend fun toggleFavorite(
userId: String,
quoteId: Int,
isFavorite: Boolean
): AppResult<Unit> = safeCall(graphqlResolver) {
if (isFavorite) {
apolloClient.mutation(DeleteFavoriteQuoteMutation(userId, quoteId)).execute()
} else {
apolloClient.mutation(InsertFavoriteQuoteMutation(userId, quoteId)).execute()
}
}
override fun getFavoriteQuotes(
userId: String
): Flow<AppResult<List<FavoriteQuote>?>> =
apolloClient
.query(GetFavoriteQuotesQuery(userId, limit = Optional.present(100), offset = Optional.present(0)))
.fetchPolicy(FetchPolicy.CacheAndNetwork)
.watch()
.mapNotNull { response ->
val data = response.requireDataOrThrow()
data.favoritesCollection?.edges?.map { it.node.toFavoriteQuote() }
}
.asResultFlow(graphqlResolver)
Expected Behavior
After inserting or deleting a favorite:
- The normalized cache should update
watch() on GetFavoriteQuotesQuery should emit updated data
- UI should reflect changes immediately
Actual Behavior
I’m using Apollo Kotlin with a normalized cache (Memory + SQL cache chaining) in a Supabase GraphQL setup. For simple (flat) queries and mutations, the cache updates correctly and
watch()emits updates to the UI as expected.However, when dealing with nested objects, specifically a
favorites → quotes → nested collectionsstructure, mutations (insert/delete) do not trigger UI updates viawatch()even though the mutation returns the same nested structure.I'm trying to understand whether this is:
Environment
Cache Configuration
Type Policies
Query
Mutations
Insert
Delete
Repository Code
Expected Behavior
After inserting or deleting a favorite:
watch()onGetFavoriteQuotesQueryshould emit updated dataActual Behavior
Cache updates correctly for flat queries
For nested favorites query:
watch()