houdini
houdini copied to clipboard
Imperative cache API
Houdini needs to provide the user a way to interact with the cache imperatively to handle situations that aren't covered by the declarative API
The biggest hurdle atm is how to compute the storage key for particular piece of data in the cache. I think the current selection object is not friendly enough for a user facing API so I think we need to come up with something different.
Fundamentally, writing data to the cache relies on 3 things besides the value: the ID of the object, the key of the field, and the type of the value (to marshal any complex values the user might provide).
Some use cases the API should cover:
- Providing a new value for a field or link
- Marking a certain field as stale
- Refresh all current queries/stores
Some random thoughts:
- if schema information is stored as users navigate the page it must be tied into garbage collection so we can delete it
- this complicates manually preloading data since the schema isn't known before hand.
- must be written to the top-most non-optimistic layer of the cache at write time
- specifying the key manually can be made more ergonomic if we hide it behind something like
myObject.getField("firstName", {arg: "Hello"}) - store api's can be used to embed type information without having to store it in some global place
- ie
MyFragmentStore.writeToCache({ })orMyFragmentStore.preloadbut that might be confusing on a QueryStore - Maybe something like
cache.writeDocument({ document: MyFragmentStore, data: {}, variables: {} })is better since its more clear its happening to the store itself - Specify a fragment means asking for the parent ID means giving the user a way to calculate the ID that doesn't couple them to the exact format used internally
- ie
- are these methods on the cache, or methods on objects that represent an entity in the cache?
cache.write("User", "2", { ... })looks alright butwriteLinkgets really gnarly since you need to embed a parent and a target which is just asking for arbitrary names that are hard to remember.
Not an easy topic, thx for putting a starting point 👍 I would also like to collect "Use Cases" to understand the different things to handle and provide THE good API. I'll put notes here when I hit some
@AlecAivazis @jycouet so I found an interesting use case for this (I'm actually doing this on one of my projects):
- so I have an entity (let's call it
A) that has a list of other entity (let's call itB) - I have a mutation to delete
B, and when deletingBI need to updateAto reflect those changes on the screen - so I call the
Bdelete mutation, and then I get allBfrom the list insideAto filter the deletedB - then I call
Cache.write()function to updateAwith the new list ofB
After a call with @AlecAivazis , let's put down a few thoughts:
// reset everything
cache.markAllStale()
// root
const rootCache = cache.getRoot()
// reset all `quoteEdge`
rootCache.markStale("quoteEdge")
// GQL_quoteEdge.markStale();
// reset some fields
const quoteEdge = rootCache.getFields("quoteEdge")
quoteEdge.markStale("nodes")
quoteEdge.markStale("totalCount")
quoteEdge.set("totalCount", 10)
// set a reference
user.set("favoriteFood", cache.get("Recipe", {id: 5})
// reset some fields when specific inputs
rootCache.markStale("quoteEdge", {edge: { pagination: { skip: 0 }, filters: { creatorUserId: null} }})
rootCache.markStale("user", { name: 'JYC'} )
// add an updater to the layer
quoteEdge.set("totalCount", count => count + 1)
A lot of things are subject to change... but it's a start 😊
Don't have this is a HUGE BLOCKER for us to switching from urql to houdini.
I wish you to work on it expressing the best of yourself. 😄
@frederikhors it's looking like this will be the next thing we focus on. stay tuned!
@frederikhors mind telling me which features/ use cases you need most out of the imperative api? I'm assuming marking data as stale is an important one but I'm curious if there are others?
For now I only need invalidation.
We're using it hard because we invalidate & refetch in case of update/delete of an item.
I'll let you know if something else is needed.
Awesome! Thanks for the quick reply. Would you want a way to automatically trigger refetches of the deleted value or is that something you would do by hand? Or just the next time the query is fired?
I think this depends each time.
All the options? It's difficult?
Nope, not difficult just trying to figure out the priority for all of the features. There's a lot that I'd like to be able to do with this API but with 1.0 coming soon I'll have to shift focus over to accommodating some of the recent changes that will effect houdini so I'm trying to get something out quickly before I get distracted