https://kotlinlang.org logo
#apollo-kotlin
Title
# apollo-kotlin
j

Jacob Rhoda

09/19/2023, 9:43 PM
Is there a way to get a Flow to watch the cache when you are reading directly from the cache? I have a query that returns a list of fragments (paginated), and mutations that operate on the CacheKey of those fragments, and the need to consume updates from those mutations.
s

Stylianos Gakis

09/19/2023, 9:54 PM
Is just this
.fetchPolicy(FetchPolicy.CacheOnly).watch()
what you may be looking for? Unless I am misunderstanding what you mean here.
j

Jacob Rhoda

09/19/2023, 9:58 PM
I need to read the fragment directly from the cache, because my graph QL API does not give me an individual query for that fragment
s

Stylianos Gakis

09/19/2023, 10:07 PM
Aha sorry then I am not sure. You’re looking inside there by doing
apolloClient.apolloStore.readFragment()
I assume right? Might be a bit hacky, but could you use one of your queries which does return that type, so you can create a new query which just reads that fragment, and make it CacheOnly and it should just update when cache changes no? But maybe wait for someone who can help you better here 🤕
j

Jacob Rhoda

09/20/2023, 1:28 AM
Hmm… Would it matter if the query is paginated / has other inputs? I don’t know if it would emit changes to the fragment in that scenario.
m

mbonnin

09/20/2023, 8:46 AM
Good question. Fragments are very similar to queries but indeed there's no API to "watch" a fragment
From the top of my head, I'd "extend" the schema locally to read the fragment. If you have a fragment like so:
Copy code
fragment heroDetails on Hero {
  id
  name
  friends(first: $first, after: $after) {
    id 
    name
  }
}
You can extend your query in a
extra.graphqls
file next to your schema
Copy code
extend type Query {
  heroDetailsAccessor: Hero
}
Then you can write a query that reads your fragment:
Copy code
query GetHeroDetails(first: String!, after: String!) {
  heroDetailsAccessor {
    ...heroDetails
  }
}
It's a bit of boilerplate so if you use this pattern a lot, we'll want to provide first-class APIs for fragments but in the short term this should work
Also you might be interested in this RFC about fragment modularity that intents to make it easier to work with fragments
j

Jacob Rhoda

09/20/2023, 2:17 PM
How would I specify the cache key?
m

mbonnin

09/20/2023, 2:29 PM
If you have an id, you can use
fieldPolicy
to specify the id:
Copy code
extend type Query @fieldPolicy(forField: "heroDetailsAccessor", keyArgs:"id") {
  heroDetailsAccessor(id: ID!): Hero
}
And then use
id
in your query:
Copy code
query GetHeroDetails(id: ID!, first: String!, after: String!) {
  heroDetailsAccessor(id: $id) {
    ...heroDetails
  }
}
j

Jacob Rhoda

09/20/2023, 7:49 PM
Cool! I managed to set this up. I’m trying to consume the flow…but when I call collect, nothing is ever emitted.
m

mbonnin

09/20/2023, 7:51 PM
Are you on v4? v4 will emit the cache misses with some more info in response.exception
j

Jacob Rhoda

09/20/2023, 7:51 PM
No, I’m still on v3
I dumped the cache and it shouldn’t be missing…
m

mbonnin

09/20/2023, 7:51 PM
You can have that on v3 too IIRC. There's a parameter to watch
Maybe 'emitCacheMisses' ?
(i'm AFK at the moment but can send more details a bit later)
j

Jacob Rhoda

09/20/2023, 7:57 PM
well that seems to have done something at least 🙂
Okay, the cacheMissException is
Object ‘QUERY_ROOT’ has no field named ‘fmisFieldRecordDataAccessor({“fieldRecordId”:“26b4bc5f-b338-42ac-8a6f-e4a9c09c5d95"})’
My extended query looks like
Copy code
extend type Query @fieldPolicy(forField: "fmisFieldRecordDataAccessor", keyArgs: "id") {
    fmisFieldRecordDataAccessor(fieldRecordId: ID!): FmisFieldRecord
}
My query:
Copy code
query GetFmisFieldRecordData($fieldRecordId: ID!) {
    fmisFieldRecordDataAccessor(fieldRecordId: $fieldRecordId) {
        ...FmisFieldRecordData
    }
}
Ah, I see my problem. The keyArgs should be set to “fieldRecordId”
m

mbonnin

09/20/2023, 9:21 PM
Yep, good call 👍