Skip to content

Support simple list cases in FieldPolicyCacheResolver #155

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 1 commit into from
May 16, 2025
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
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.apollographql.cache.normalized.api

import com.apollographql.apollo.api.CompiledField
import com.apollographql.apollo.api.CompiledListType
import com.apollographql.apollo.api.CompiledNotNullType
import com.apollographql.apollo.api.Executable
import com.apollographql.apollo.api.MutableExecutionOptions
import com.apollographql.apollo.exception.CacheMissException
Expand Down Expand Up @@ -230,12 +232,28 @@ class CacheControlCacheResolver(
*/
object FieldPolicyCacheResolver : CacheResolver {
override fun resolveField(context: ResolverContext): Any? {
val keyArgsValues = context.field.argumentValues(context.variables) { it.definition.isKey }.values.map { it.toString() }

if (keyArgsValues.isNotEmpty()) {
return CacheKey(context.field.type.rawType().name, keyArgsValues)
val keyArgsValues = context.field.argumentValues(context.variables) { it.definition.isKey }.values
if (keyArgsValues.isEmpty()) {
return DefaultCacheResolver.resolveField(context)
}

return DefaultCacheResolver.resolveField(context)
var type = context.field.type
if (type is CompiledNotNullType) {
type = type.ofType
}
if (type is CompiledListType) {
// Only support flat lists
if (type.ofType !is CompiledListType && !(type.ofType is CompiledNotNullType && (type.ofType as CompiledNotNullType).ofType is CompiledListType)) {
// Only support single key argument which is a flat list
if (keyArgsValues.size == 1) {
val keyArgsValue = keyArgsValues.first() as? List<*>
if (keyArgsValue != null && keyArgsValue.firstOrNull() !is List<*>) {
return keyArgsValue.map {
CacheKey(type.rawType().name, it.toString())
}
}
}
}
}
return CacheKey(type.rawType().name, keyArgsValues.map { it.toString() })
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ extend type Author @typePolicy(keyFields: "firstName lastName")

extend type Book @typePolicy(keyFields: "isbn")

extend type Query @fieldPolicy(forField: "book", keyArgs: "isbn") @fieldPolicy(forField: "author", keyArgs: "firstName lastName")
extend type Query
@fieldPolicy(forField: "book", keyArgs: "isbn")
@fieldPolicy(forField: "author", keyArgs: "firstName lastName")
@fieldPolicy(forField: "books", keyArgs: "isbns")

interface Node @typePolicy(keyFields: "id") {
id: ID!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,20 @@ class DeclarativeCacheTest {
assertEquals("Bordage", authorData2.author?.lastName)
}

@Test
fun fieldPolicyWithLists() = runTest {
val cacheManager = CacheManager(MemoryCacheFactory())
cacheManager.writeOperation(GetPromoBookQuery(), GetPromoBookQuery.Data(GetPromoBookQuery.PromoBook(title = "Promo", isbn = "42", __typename = "Book")))
cacheManager.writeOperation(GetOtherBookQuery(), GetOtherBookQuery.Data(GetOtherBookQuery.OtherBook(isbn = "43", title = "Other Book", __typename = "Book")))

val booksQuery = GetBooksQuery(listOf("42", "43"))
val booksCacheResponse = cacheManager.readOperation(booksQuery)
val booksData = booksCacheResponse.data!!
assertEquals(2, booksData.books.size)
assertEquals(GetBooksQuery.Book("Promo", "42", "Book"), booksData.books[0])
assertEquals(GetBooksQuery.Book("Other Book", "43", "Book"), booksData.books[1])
}

@Test
fun canResolveListProgrammatically() = runTest {
val cacheResolver = object : CacheResolver {
Expand Down