Skip to content

Commit

Permalink
Auto-detect clientOptions.assumeImmutableResults from cache.
Browse files Browse the repository at this point in the history
This commit allows the default value of the `assumeImmutableResults`
option to be determined by the cache (any implementation of
`ApolloCache`), which allows our implementation of `InMemoryCache` to
express the safety of assuming `assumeImmutableResults` is `true`,
unlocking significant performance savings (fewer defensive deep copies
of query results), even if `assumeImmutableResults` is not configured.

Related past PRs:
- #4543
- #5153
- #9680
- [Apollo Client 2.6 blog post](https://www.apollographql.com/blog/announcement/frontend/whats-new-in-apollo-client-2-6/#rewarding-immutability)
  • Loading branch information
benjamn committed Feb 16, 2023
1 parent 380347c commit dd45307
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 12 deletions.
2 changes: 2 additions & 0 deletions src/cache/core/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import { Cache } from './types/Cache';
export type Transaction<T> = (c: ApolloCache<T>) => void;

export abstract class ApolloCache<TSerialized> implements DataProxy {
public readonly assumeImmutableResults: boolean = false;

// required to implement
// core API
public abstract read<TData = any, TVariables = any>(
Expand Down
4 changes: 4 additions & 0 deletions src/cache/inmemory/inMemoryCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ export class InMemoryCache extends ApolloCache<NormalizedCacheObject> {
any,
[Cache.WatchOptions]>;

// Override the default value, since InMemoryCache result objects are frozen
// in development and expected to remain logically immutable in production.
public readonly assumeImmutableResults = true;

// Dynamically imported code can augment existing typePolicies or
// possibleTypes by calling cache.policies.addTypePolicies or
// cache.policies.addPossibletypes.
Expand Down
18 changes: 9 additions & 9 deletions src/core/ApolloClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,14 @@ export class ApolloClient<TCacheShape> implements DataProxy {
* you are using.
*/
constructor(options: ApolloClientOptions<TCacheShape>) {
if (!options.cache) {
throw new InvariantError(
"To initialize Apollo Client, you must specify a 'cache' property " +
"in the options object. \n" +
"For more information, please visit: https://go.apollo.dev/c/docs"
);
}

const {
uri,
credentials,
Expand All @@ -143,7 +151,7 @@ export class ApolloClient<TCacheShape> implements DataProxy {
__DEV__,
queryDeduplication = true,
defaultOptions,
assumeImmutableResults = false,
assumeImmutableResults = cache.assumeImmutableResults,
resolvers,
typeDefs,
fragmentMatcher,
Expand All @@ -159,14 +167,6 @@ export class ApolloClient<TCacheShape> implements DataProxy {
: ApolloLink.empty();
}

if (!cache) {
throw new InvariantError(
"To initialize Apollo Client, you must specify a 'cache' property " +
"in the options object. \n" +
"For more information, please visit: https://go.apollo.dev/c/docs"
);
}

this.link = link;
this.cache = cache;
this.disableNetworkFetches = ssrMode || ssrForceFetchDelay > 0;
Expand Down
6 changes: 5 additions & 1 deletion src/core/QueryInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,13 @@ const destructiveMethodCounts = new (
canUseWeakMap ? WeakMap : Map
)<ApolloCache<any>, number>();

type KeyOfType<T, U> = {
[P in keyof T]: T[P] extends U ? P : never
}[keyof T]

function wrapDestructiveCacheMethod(
cache: ApolloCache<any>,
methodName: keyof ApolloCache<any>,
methodName: KeyOfType<ApolloCache<any>, Function>,
) {
const original = cache[methodName];
if (typeof original === "function") {
Expand Down
4 changes: 2 additions & 2 deletions src/core/QueryManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export class QueryManager<TStore> {
ssrMode = false,
clientAwareness = {},
localState,
assumeImmutableResults,
assumeImmutableResults = !!cache.assumeImmutableResults,
}: {
cache: ApolloCache<TStore>;
link: ApolloLink;
Expand All @@ -138,7 +138,7 @@ export class QueryManager<TStore> {
this.clientAwareness = clientAwareness;
this.localState = localState || new LocalState({ cache });
this.ssrMode = ssrMode;
this.assumeImmutableResults = !!assumeImmutableResults;
this.assumeImmutableResults = assumeImmutableResults;
if ((this.onBroadcast = onBroadcast)) {
this.mutationStore = Object.create(null);
}
Expand Down

0 comments on commit dd45307

Please sign in to comment.