Seb Jachec
10/21/2021, 12:54 PMEntry.<id>
using `ObjectIdGenerator`/`CacheKeyResolver` but I'm getting a cache miss for EntryQuery
– Object 'QUERY_ROOT' has no field named 'entry({"input":{...}})'
, before the inner Entry
from EntryOutput
can even be looked up in the cache (which I'd expect to succeed)
type Entry {
id: ID!
# ... etc
}
query EntriesQuery(...) {
entries(input: { ... }) { # produces EntriesOutput
nodes { # [Entry]
id
}
}
}
query EntryQuery($entryId: ID!) {
entry(input: { entryId: $entryId }) { # produces EntryOutput
entry { # Entry
id
}
}
}
mbonnin
10/21/2021, 1:16 PM@fieldPolicy
for this instead of writing ObjectIdGenerator
/ CacheKeyResolver
manuallly. There are sadly no docs yet (it's coming) but there are some integration tests there: https://github.com/apollographql/apollo-android/blob/2ca7d9b7805197ce388c9e96e65ce[…]/commonTest/kotlin/test/declarativecache/graphql/extra.graphqlsmbonnin
10/21/2021, 1:17 PMinput
is an input object. Not sure if that works alreadymbonnin
10/21/2021, 1:18 PMEntry
id from input
?Seb Jachec
10/21/2021, 1:37 PMinput
for the entry
query has entryId
mbonnin
10/21/2021, 1:52 PMCacheKeyResolver
mbonnin
10/21/2021, 1:56 PMobject CustomCacheKeyResolver: CacheKeyResolver() {
override fun cacheKeyForField(field: CompiledField, variables: Executable.Variables): CacheKey? {
if (field.name == "entry") {
val input = field.resolveArgument("input", variables) as? Map<String, Any?>
val id = input?.get("entryId") as? String
if (id != null) {
return CacheKey(id)
}
}
// Fallback
return null
}
}
Seb Jachec
10/21/2021, 2:18 PMCacheKeyResolver
I'm using at the moment, alongside my `ObjectIdGenerator`:
val objectIdGenerator = object : ObjectIdGenerator {
// Called after a network request, when writing to the cache
override fun cacheKeyForObject(
obj: Map<String, Any?>,
context: ObjectIdGeneratorContext,
): CacheKey? {
val typeName = obj["__typename"].toString()
if (obj["__typename"] == "Entry") {
val id = obj["id"].toString()
return CacheKey.from(typeName, listOf(id))
}
return null
}
}
mbonnin
10/21/2021, 2:20 PMCacheKeyResolver
?Seb Jachec
10/21/2021, 2:21 PMval cacheResolver = object : CacheKeyResolver() {
override fun cacheKeyForField(
field: CompiledField,
variables: Executable.Variables,
): CacheKey? {
return if (field.name == "entry" && field.type.leafType().name == "Entry") {
val input = field.resolveArgument("input", variables) as? HashMap<*, *>
return input?.let {
val entryId = input["entryId"].toString()
CacheKey.from("Entry", listOf(entryId))
}
} else {
null
}
}
}
mbonnin
10/21/2021, 2:24 PMmbonnin
10/21/2021, 2:24 PMmbonnin
10/21/2021, 2:27 PMstore.readOperation()
directly to rule out an issue in the cache interceptor or something elseSeb Jachec
10/21/2021, 2:32 PMCacheKeyResolver
– cacheKeyForField
gets called for EntryOutput
first, then I get a cache miss, without the chance for cacheKeyForField
to be called for the inner Entry
inside EntryOutput
Seb Jachec
10/21/2021, 2:32 PMreadOperation
– I'll check that next!mbonnin
10/21/2021, 2:33 PMmbonnin
10/21/2021, 2:33 PMEntryOutput
wrapper typembonnin
10/21/2021, 2:34 PMEntryOutput
type doesn't have an id
itselfmbonnin
10/21/2021, 2:35 PMquery EntryQuery($entryId: ID!) {
entry(input: { entryId: $entryId }) { # Entry or EntryOutput ?
is entry of Entry or EntryOutput type up there ?Seb Jachec
10/21/2021, 2:36 PMEntryOutput
does actually have an id
, but I hadn't been querying for it/using it at all –
type EntryOutput {
id: ID
node: Entry
}
mbonnin
10/21/2021, 2:38 PMquery EntriesQuery(...) {
entries(input: { ... }) { # produces EntriesOutput
nodes { # [Entry]
id
}
}
}
This is weird then... Is that a double list?mbonnin
10/21/2021, 2:38 PMEntriesOutput
!= EntryOutput
mbonnin
10/21/2021, 2:38 PMmbonnin
10/21/2021, 2:40 PMmbonnin
10/21/2021, 2:41 PMQUERY_ROOT.entries
and QUERY_ROOT.entry
since they have different typesSeb Jachec
10/21/2021, 2:57 PMinput
for our EntriesQuery
is has start
and end
DateTime
objects at the moment, so we're querying for a range of entriesmbonnin
10/21/2021, 2:59 PMmbonnin
10/21/2021, 3:00 PMEntryOutput
and return an Entry
instead. I think that'd do the jobSeb Jachec
10/21/2021, 3:07 PMSeb Jachec
10/26/2021, 2:16 PMEntriesQuery
and EntryQuery
now return the same type (EntryConnection
), with cache keys for EntryNode
and EntryEdge
in the format EntryNode:<id>
and EntryEdge:<id>
respectively. It still doesn't seem possible to reconcile these though – would you have any suggestions on what to try next?
type EntryConnection {
edges: [EntryEdge!]!
}
type EntryEdge {
id: ID!
node: EntryNode!
}
type EntryNode {
id: ID!
# Other fields left out (title etc.)
}
mbonnin
10/26/2021, 4:59 PMEntryQuery
should return an EntryNode
. There's no real need for a Connection if it's a single entrySeb Jachec
10/27/2021, 10:20 AMmbonnin
10/27/2021, 12:39 PM