Apollo GQL - Clear cache for one type only - apollo-client

I would like to be able to clear the cache of only one specified type
e.g. if I have Authors and Books I would like to only clear cache for Authors
I'm using #apollo/client": "^3.2.5" (latest)
Just additional note, shouldn't matter much but I'm using it with Angular.
apollo.client.clearStore(); // this clears all store
Tried to use the apollo.client.cache.writeQuery, however no luck yet
Remove by the __typename would be ideal or something related

Using the v3 it seems by using the evict api is doing what I needed
this.apollo.client.cache.evict({
fieldName: "authors",
});

Related

How can I specify maximum cache-time for any data matching a regex in apollo-client with InMemoryCache?

Some fields coming from the graphql server will have the shape short-lived-token-XYZ123. Ideally we wouldn't even have to know the field names ahead of time, as any code we write will live in a library. How can I hook into the InMemoryCache or the ApolloClient object to set the cache time of fields with values matching a regex? Causing them to poll at a set interval would be really ideal, but because polling is query-centric, I dont think that is possible at the field level. Giving them a specific cache time would be enough. Is there a way to hook into the InMemoryCache with a function that gets called on every read?
Another option would be to make these token strings a graphql type Token like
type Token {
id: String
}
and then in the client it might be possible to define a custom cache behavior for this type when initializing the cache like
new InMemoryCache({
typePolicies: {
Token: {
fields: {
id: {
read(cachedVal) {
if (cacheTimeElapsed){
return null
} else {
return cachedVal
}
}
}
},
},
},
But Im also unclear HOW to bust the cache using the read function. What do I return from the function to tell the cache that it is busted and needs to refetch? These docs are...challenging. If I could just call a function on every single read and do what I need to do, that would be ideal.
These fields will also be annotated in the apollo-server with #token(for other reasons), and we could potentially hook in here to somehow tell the client to cache-bust these fields. Not sure how, but it's another option.
I posted the same question on the Apollo forums and received the answer that, remarkably, they don't support setting specific cache times or invalidating the cache from the read function of the typePolicies. It is apparently on the roadmap.
A third party caching library was suggested instead: https://github.com/NerdWalletOSS/apollo-cache-policies
Looking in the "Why does this exist?" in the NerdWallet README, you can see they mention that this is a common pain point with the InMemoryCache

How can I have custom identifiers/primary keys for my resources?

My table has a primary key other than id and react-admin enforces id to be returned in the response by the DataProvider. So can I configure different primary keys/identifiers for my resources?
I am using this library - https://github.com/Steams/ra-data-hasura-graphql
Right now I have made few changes in my library code to make this work, but I need an idea to implement it, so anyone using this library doesn't need to go thru whole code to make it work.
const config = {
'primaryKey': {
'tableName': 'primaryKey1', 'tableName2': 'primaryKey2'
}
};
I was thinking of something like passing configuration like this.
Thanks.
I don't believe it is currently possible with the 0.1.0 release. However in hasura you can expose the column with a different name
hasura column exposed name

Why do GraphQL fragments need __typename in queries?

I can't find or I am looking in the wrong place for any documentation on how fragments are matched. When I use the vanilla Apollo client if I turn off the option of addTypename when I use fragments I get a warning heuristic fragment matching going on! and if I add it this goes away but my response contains many __typename fields which I don't need. Why do they help?
The reason for this is that ApolloClient, like Relay, uses a global store to cache your data on the client.
In order to do this for you, global ids are required. For some reason, global ids are not something people think about, and in fact, it is something people complain about when switching to Relay all the time.
ApolloClient has a clever solution for this! (Apollo team correct me if I am wrong) They allow you to define how your records get keyed in the store! By default, it uses the typename and id to create a the kind of global IDs that Relay suggests you create. This is why they need the typename.
Since you are turning off the typename in the query, Apollo will do some smart stuff to try and figure out the type (and thus the key in the store). This smart stuff can lead to problems for you down the road.
If you want to create your own global ids instead of using all this smart stuff, you can specify it like so:
const cache = new InMemoryCache({
dataIdFromObject: object => object.key || null
});
https://www.apollographql.com/docs/react/advanced/caching.html#normalization

graphql multiple mutations using prior mutation return results?

I understand that mutations are sequential, so it makes sense to me that if Mutation 1 creates an entity and returns an id, that Mutation 2 should have access to that id. However I don't see any examples online and can't seem to get it to work. I see that people say you need to handle this in the resolve function of your route but it seems like extra unnecessary code if I can get this in just the query.
For example I have the following where accounts belong to clients and hence need the clientId before being created. However this does not work...
mutation createClientAndAccount($account: AccountInput, $client: ClientInput){
createClient(client: $client){ clientId }
createAccount(account: $account, clientId: USE_CLIENT_ID_FROM_ABOVE) { ... }
}
I've also tried nesting mutations but didn't have much luck there either...
Is what i'm trying to do possible? Would the resolve function of createAccount have the return data from createClient?
This is not possible right now, though would be useful.
See this PR.
Maybe using a custom schema directive we could achieve that.
Schema stitching will be a better approach(though usually it is preferred in API Gateway for merging APIs from different services).
If this requirement is very rare in your application, simply creating a new API that can do both CreateClientAndAccount is enough.

Doctrine2 Caching of updated Elements

I have a problem with doctrine. I like the caching, but if i update an Entity and flush, shouldn't doctrine2 be able to clear it's cache?
Otherwise the cache is of very little use to me since this project has a lot of interaction and i would literally always have to disable the cache for every query.
The users wouldn't see their interaction if the cache would always show them the old, cached version.
Is there a way arround it?
Are you talking about saving and fetching a new Entity within the same runtime (request)? If so then you need to refresh the entity.
$entity = new Entity();
$em->persist($entity);
$em->flush();
$em->refresh($entity);
If the entity is managed and you make changes, these will be applied to Entity object but only persisted to your database when calling $em->flush().
If your cache is returning an old dataset for a fresh request (despite it being updated successfully in the DB) then it sounds like you've discovered a bug. Which you can file here >> http://www.doctrine-project.org/jira/secure/Dashboard.jspa
Doctrine2 never has those delete methods such as deleteByPrefix, which was in Doctrine1 at some point (3 years ago) and was removed because it caused more trouble.
The page http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/caching.html#deleting is outdated (The next version of the doctrine2 document will see those methods removed). The only thing you can do now is manually managing the cache: find the id and delete it manually after each update.
More advanced doctrine caching is WIP: https://github.com/doctrine/doctrine2/pull/580.
This is according to the documentation on Doctrine2 on how to clear the cache. I'm not even sure this is what you want, but I guess it is something to try.
Doctrine2's cache driver has different levels of deleting cached entries.
You can delete by the direct id, using a regex, by suffix, by prefix and plain deleting all values in the cache
So to delete all you'd do:
$deleted = $cacheDriver->deleteAll();
And to delete by prefix, you'd do:
$deleted = $cacheDriver->deleteByPrefix('users_');
I'm not sure how Doctrine2 names their cache ids though, so you'd have to dig for that.
Information on deleting cache is found here: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/caching.html#deleting
To get the cache driver, you can do the following. It wasn't described in the docs, so I just traced through the code a little.
I'm assuming you have an entity manager instance in this example:
$config = $em->getConfiguration(); //Get an instance of the configuration
$queryCacheDriver = $config->getQueryCacheImpl(); //Gets Query Cache Driver
$metadataCacheDriver = $config->getMetadataCacheImpl(); //You probably don't need this one unless the schema changed
Alternatively, I guess you could save the cacheDriver instance in some kind of Registry class and retrieve it that way. But depends on your preference. Personally I try not to depend on Registries too much.
Another thing you can do is tell the query you're executing to not use the result cache. Again I don't think this is what you want, but just throwing it out there. Mainly it seems you might as well turn off the query cache altogether. That is unless it's only a few specific queries where you don't want to use the cache.
This example is from the docs: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/caching.html#result-cache
$query = $em->createQuery('select u from \Entities\User u');
$query->useResultCache(false); //Don't use query cache on this query
$results = $query->getResult();

Resources