Skip to content

Commit

Permalink
Merge pull request #8696 from apollographql/make-cache.batch-return-o…
Browse files Browse the repository at this point in the history
…ptions.update-result

Use `cache.batch` within `cache.updateQuery` and `cache.updateFragment`
  • Loading branch information
benjamn committed Sep 17, 2021
2 parents 756ab87 + 6bf12cb commit 8ff2f49
Show file tree
Hide file tree
Showing 7 changed files with 331 additions and 40 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
- A new nested entry point called `@apollo/client/testing/core` has been created. Importing from this entry point instead of `@apollo/client/testing` excludes any React-related dependencies. <br/>
[@wassim-k](https://github.com/wassim-k) in [#8687](https://github.com/apollographql/apollo-client/pull/8687)

- Make `cache.batch` return the result of calling the `options.update` function. <br/>
[@benjamn](https://github.com/benjamn) in [#8696](https://github.com/apollographql/apollo-client/pull/8696)

### React Refactoring

#### Bug Fixes (due to [@brainkim](https://github.com/brainkim) in [#8596](https://github.com/apollographql/apollo-client/pull/8596)):
Expand Down
1 change: 1 addition & 0 deletions src/cache/core/__tests__/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class TestCache extends ApolloCache<unknown> {
}

public performTransaction(transaction: <TSerialized>(c: ApolloCache<TSerialized>) => void): void {
transaction(this);
}

public read<T, TVariables = any>(query: Cache.ReadOptions<TVariables>): T | null {
Expand Down
51 changes: 33 additions & 18 deletions src/cache/core/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ export type Transaction<T> = (c: ApolloCache<T>) => void;
export abstract class ApolloCache<TSerialized> implements DataProxy {
// required to implement
// core API
public abstract read<T, TVariables = any>(
query: Cache.ReadOptions<TVariables, T>,
): T | null;
public abstract write<TResult = any, TVariables = any>(
write: Cache.WriteOptions<TResult, TVariables>,
public abstract read<TData = any, TVariables = any>(
query: Cache.ReadOptions<TVariables, TData>,
): TData | null;
public abstract write<TData = any, TVariables = any>(
write: Cache.WriteOptions<TData, TVariables>,
): Reference | undefined;
public abstract diff<T>(query: Cache.DiffOptions): Cache.DiffResult<T>;
public abstract watch(watch: Cache.WatchOptions): () => void;
public abstract watch<TData = any, TVariables = any>(
watch: Cache.WatchOptions<TData, TVariables>,
): () => void;
public abstract reset(): Promise<void>;

// Remove whole objects from the cache by passing just options.id, or
Expand Down Expand Up @@ -59,11 +61,16 @@ export abstract class ApolloCache<TSerialized> implements DataProxy {
// provide a default batch implementation that's just another way of calling
// performTransaction. Subclasses of ApolloCache (such as InMemoryCache) can
// override the batch method to do more interesting things with its options.
public batch(options: Cache.BatchOptions<this>) {
public batch<U>(options: Cache.BatchOptions<this, U>): U {
const optimisticId =
typeof options.optimistic === "string" ? options.optimistic :
options.optimistic === false ? null : void 0;
this.performTransaction(options.update, optimisticId);
let updateResult: U;
this.performTransaction(
() => updateResult = options.update(this),
optimisticId,
);
return updateResult!;
}

public abstract performTransaction(
Expand Down Expand Up @@ -171,21 +178,29 @@ export abstract class ApolloCache<TSerialized> implements DataProxy {
options: Cache.UpdateQueryOptions<TData, TVariables>,
update: (data: TData | null) => TData | null | void,
): TData | null {
const value = this.readQuery<TData, TVariables>(options);
const data = update(value);
if (data === void 0 || data === null) return value;
this.writeQuery<TData, TVariables>({ ...options, data });
return data;
return this.batch({
update(cache) {
const value = cache.readQuery<TData, TVariables>(options);
const data = update(value);
if (data === void 0 || data === null) return value;
cache.writeQuery<TData, TVariables>({ ...options, data });
return data;
},
});
}

public updateFragment<TData = any, TVariables = any>(
options: Cache.UpdateFragmentOptions<TData, TVariables>,
update: (data: TData | null) => TData | null | void,
): TData | null {
const value = this.readFragment<TData, TVariables>(options);
const data = update(value);
if (data === void 0 || data === null) return value;
this.writeFragment<TData, TVariables>({ ...options, data });
return data;
return this.batch({
update(cache) {
const value = cache.readFragment<TData, TVariables>(options);
const data = update(value);
if (data === void 0 || data === null) return value;
cache.writeFragment<TData, TVariables>({ ...options, data });
return data;
},
});
}
}
33 changes: 20 additions & 13 deletions src/cache/core/types/Cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { Modifier, Modifiers } from './common';
import { ApolloCache } from '../cache';

export namespace Cache {
export type WatchCallback = (
diff: Cache.DiffResult<any>,
lastDiff?: Cache.DiffResult<any>,
export type WatchCallback<TData = any> = (
diff: Cache.DiffResult<TData>,
lastDiff?: Cache.DiffResult<TData>,
) => void;

export interface ReadOptions<TVariables = any, TData = any>
Expand All @@ -25,19 +25,23 @@ export namespace Cache {
result: TResult;
}

export interface DiffOptions extends ReadOptions {
export interface DiffOptions<
TData = any,
TVariables = any,
> extends ReadOptions<TVariables, TData> {
// The DiffOptions interface is currently just an alias for
// ReadOptions, though DiffOptions used to be responsible for
// declaring the returnPartialData option.
}

export interface WatchOptions<
Watcher extends object = Record<string, any>
> extends ReadOptions {
watcher?: Watcher;
TData = any,
TVariables = any,
> extends ReadOptions<TVariables, TData> {
watcher?: object;
immediate?: boolean;
callback: WatchCallback;
lastDiff?: DiffResult<any>;
callback: WatchCallback<TData>;
lastDiff?: DiffResult<TData>;
}

export interface EvictOptions {
Expand All @@ -54,10 +58,13 @@ export namespace Cache {
broadcast?: boolean;
}

export interface BatchOptions<C extends ApolloCache<any>> {
export interface BatchOptions<
TCache extends ApolloCache<any>,
TUpdateResult = void,
> {
// Same as the first parameter of performTransaction, except the cache
// argument will have the subclass type rather than ApolloCache.
update(cache: C): void;
update(cache: TCache): TUpdateResult;

// Passing a string for this option creates a new optimistic layer, with the
// given string as its layer.id, just like passing a string for the
Expand All @@ -66,7 +73,7 @@ export namespace Cache {
// against the current top layer of the cache), and passing false is the
// same as passing null (running the operation against root/non-optimistic
// cache data).
optimistic: string | boolean;
optimistic?: string | boolean;

// If you specify the ID of an optimistic layer using this option, that
// layer will be removed as part of the batch transaction, triggering at
Expand All @@ -80,7 +87,7 @@ export namespace Cache {
// this batch operation, pass this optional callback function. Returning
// false from the callback will prevent broadcasting this result.
onWatchUpdated?: (
this: C,
this: TCache,
watch: Cache.WatchOptions,
diff: Cache.DiffResult<any>,
lastDiff: Cache.DiffResult<any> | undefined,
Expand Down
Loading

0 comments on commit 8ff2f49

Please sign in to comment.