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 entryIdmbonnin
10/21/2021, 1:52 PMCacheKeyResolvermbonnin
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 EntryOutputSeb 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 != EntryOutputmbonnin
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