Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Cache watchers behavior #681

Merged
merged 2 commits into from
Oct 16, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 16 additions & 9 deletions src/hooks/useApollo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ const LOGIN_WITH_DEVICE_TOKEN_MUTATION = gql(`
}
`);

type Watcher = () => void;

interface FullResult {
data: any;
variables: string;
watchers: (() => void)[];
}

// The Apollo InMemory cache is way too complex for our purpose
Expand All @@ -59,6 +60,7 @@ class FullResultCache extends ApolloCache<NormalizedCacheObject> {
// ----------- Cache -----------------

private cache: Map</* Query Name */ string, FullResult> = new Map();
private watchers = new Map</* Query Name */ string, Watcher[]>();

/* Extracts the name of a Query - query <name> { ... }
* This should be unique anyways as it is also used to generate typescript types
Expand Down Expand Up @@ -91,7 +93,9 @@ class FullResultCache extends ApolloCache<NormalizedCacheObject> {
if (!name) return undefined;
const entry = this.cache.get(name);

if (entry && JSON.stringify(query.variables) === entry.variables) {
if (!entry) return undefined;

if (JSON.stringify(query.variables) === entry.variables) {
log('GraphQL Cache', `Read ${name} from cache`, entry);
return entry;
} else {
Expand All @@ -107,20 +111,18 @@ class FullResultCache extends ApolloCache<NormalizedCacheObject> {
const name = this.getQueryName(query);
if (!name) return;

const existingEntry = this.getEntry(result);
const existingEntry = this.getEntry(query);
if (!existingEntry) {
this.cache.set(name, {
data: result,
watchers: [],
variables: JSON.stringify(query.variables),
variables: JSON.stringify(query.variables ?? {}),
});
log('GraphQL Cache', `Write ${name} to new Cache Entry`, result);
} else {
existingEntry.data = result;
existingEntry.watchers.forEach((it) => it());

log('GraphQL Cache', `Write ${name} to existing Cache Entry`, result);
}
this.watchers.get(name)?.forEach((watcher) => watcher());
}

// ----------- ApolloCache Interface --------------
Expand Down Expand Up @@ -149,6 +151,7 @@ class FullResultCache extends ApolloCache<NormalizedCacheObject> {

watch<TData = any, TVariables = any>(watch: Cache.WatchOptions<TData, TVariables>): () => void {
const entry = this.getEntry(watch);
const name = this.getQueryName(watch);

const watcher = () => {
log('GraphQL Cache', 'fire watcher');
Expand All @@ -158,10 +161,14 @@ class FullResultCache extends ApolloCache<NormalizedCacheObject> {
if (entry) {
log('GraphQL Cache', 'immediately fire watcher');
watch.callback(this.diff(watch));
}

entry.watchers.push(watcher);
if (name) {
log('GraphQL Cache', 'store watcher');
this.watchers.set(name, this.watchers.get(name)?.concat(watcher) ?? []);
JeangelLF marked this conversation as resolved.
Show resolved Hide resolved
return () => {
entry.watchers = entry.watchers.filter((it) => it !== watcher);
const updatedWatchers = this.watchers.get(name)?.filter((it) => it !== watcher) ?? [];
this.watchers.set(name, updatedWatchers);
log('GraphQL Cache', 'detach watcher');
};
}
Expand Down
Loading