Skip to content

Commit

Permalink
Let ApolloCache implementations specify default value for `assumeIm…
Browse files Browse the repository at this point in the history
…mutableResults` client option (#10567)
  • Loading branch information
benjamn committed Mar 21, 2023
1 parent b50b1ac commit c2ce649
Show file tree
Hide file tree
Showing 7 changed files with 28 additions and 13 deletions.
5 changes: 5 additions & 0 deletions .changeset/small-tomatoes-explode.md
@@ -0,0 +1,5 @@
---
'@apollo/client': minor
---

Allow `ApolloCache` implementations to specify default value for `assumeImmutableResults` client option, improving performance for applications currently using `InMemoryCache` without configuring `new ApolloClient({ assumeImmutableResults: true })`
2 changes: 2 additions & 0 deletions src/cache/core/cache.ts
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
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
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
4 changes: 2 additions & 2 deletions src/core/QueryInfo.ts
Expand Up @@ -6,7 +6,7 @@ import { DeepMerger } from "../utilities"
import { mergeIncrementalData } from '../utilities';
import { WatchQueryOptions, ErrorPolicy } from './watchQueryOptions';
import { ObservableQuery, reobserveCacheFirst } from './ObservableQuery';
import { QueryListener } from './types';
import { QueryListener, MethodKeys } from './types';
import { FetchResult } from '../link/core';
import {
ObservableSubscription,
Expand Down Expand Up @@ -40,7 +40,7 @@ const destructiveMethodCounts = new (

function wrapDestructiveCacheMethod(
cache: ApolloCache<any>,
methodName: keyof ApolloCache<any>,
methodName: MethodKeys<ApolloCache<any>>,
) {
const original = cache[methodName];
if (typeof original === "function") {
Expand Down
4 changes: 2 additions & 2 deletions src/core/QueryManager.ts
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
4 changes: 4 additions & 0 deletions src/core/types.ts
Expand Up @@ -13,6 +13,10 @@ import { IsStrictlyAny } from '../utilities';

export { TypedDocumentNode } from '@graphql-typed-document-node/core';

export type MethodKeys<T> = {
[P in keyof T]: T[P] extends Function ? P : never
}[keyof T];

export interface DefaultContext extends Record<string, any> {};

export type QueryListener = (queryInfo: QueryInfo) => void;
Expand Down

0 comments on commit c2ce649

Please sign in to comment.