Skip to content

Commit

Permalink
Prevent import cycle between inMemoryCache.ts and readFromStore.ts (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
benjamn authored Sep 27, 2021
1 parent b7f89f3 commit d9a1039
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 70 deletions.
7 changes: 4 additions & 3 deletions src/cache/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ export {
} from '../utilities';

export { EntityStore } from './inmemory/entityStore';
export { fieldNameFromStoreName } from './inmemory/helpers'
export {
fieldNameFromStoreName,
defaultDataIdFromObject,
} from './inmemory/helpers'

export {
InMemoryCache,
InMemoryCacheConfig,
} from './inmemory/inMemoryCache';

export {
Expand All @@ -29,7 +31,6 @@ export {
} from './inmemory/reactiveVars';

export {
defaultDataIdFromObject,
TypePolicies,
TypePolicy,
FieldPolicy,
Expand Down
3 changes: 2 additions & 1 deletion src/cache/inmemory/__tests__/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import gql, { disableFragmentWarnings } from 'graphql-tag';
import { cloneDeep } from '../../../utilities/common/cloneDeep';
import { makeReference, Reference, makeVar, TypedDocumentNode, isReference, DocumentNode } from '../../../core';
import { Cache } from '../../../cache';
import { InMemoryCache, InMemoryCacheConfig } from '../inMemoryCache';
import { InMemoryCache } from '../inMemoryCache';
import { InMemoryCacheConfig } from '../types';

jest.mock('optimism');
import { wrap } from 'optimism';
Expand Down
2 changes: 1 addition & 1 deletion src/cache/inmemory/__tests__/diffAgainstStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import gql, { disableFragmentWarnings } from 'graphql-tag';

import { StoreReader } from '../readFromStore';
import { StoreWriter } from '../writeToStore';
import { defaultDataIdFromObject } from '../policies';
import { defaultDataIdFromObject } from '../helpers';
import { NormalizedCache, Reference } from '../types';
import { InMemoryCache } from '../inMemoryCache';
import {
Expand Down
51 changes: 50 additions & 1 deletion src/cache/inmemory/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { SelectionSetNode } from 'graphql';

import { NormalizedCache } from './types';
import {
NormalizedCache,
InMemoryCacheConfig,
} from './types';

import { KeyFieldsContext } from './policies';

import {
Reference,
isReference,
Expand All @@ -11,12 +17,55 @@ import {
resultKeyNameFromField,
shouldInclude,
isNonNullObject,
compact,
} from '../../utilities';

export const {
hasOwnProperty: hasOwn,
} = Object.prototype;

export function defaultDataIdFromObject(
{ __typename, id, _id }: Readonly<StoreObject>,
context?: KeyFieldsContext,
): string | undefined {
if (typeof __typename === "string") {
if (context) {
context.keyObject =
id !== void 0 ? { id } :
_id !== void 0 ? { _id } :
void 0;
}
// If there is no object.id, fall back to object._id.
if (id === void 0) id = _id;
if (id !== void 0) {
return `${__typename}:${(
typeof id === "number" ||
typeof id === "string"
) ? id : JSON.stringify(id)}`;
}
}
}

const defaultConfig = {
dataIdFromObject: defaultDataIdFromObject,
addTypename: true,
resultCaching: true,
// Thanks to the shouldCanonizeResults helper, this should be the only line
// you have to change to reenable canonization by default in the future.
canonizeResults: false,
};

export function normalizeConfig(config: InMemoryCacheConfig) {
return compact(defaultConfig, config);
}

export function shouldCanonizeResults(
config: Pick<InMemoryCacheConfig, "canonizeResults">,
): boolean {
const value = config.canonizeResults;
return value === void 0 ? defaultConfig.canonizeResults : value;
}

export function getTypenameFromStoreObject(
store: NormalizedCache,
objectOrReference: StoreObject | Reference,
Expand Down
41 changes: 4 additions & 37 deletions src/cache/inmemory/inMemoryCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,55 +13,22 @@ import {
StoreObject,
Reference,
isReference,
compact,
} from '../../utilities';
import {
ApolloReducerConfig,
NormalizedCacheObject,
} from './types';
import { InMemoryCacheConfig, NormalizedCacheObject } from './types';
import { StoreReader } from './readFromStore';
import { StoreWriter } from './writeToStore';
import { EntityStore, supportsResultCaching } from './entityStore';
import { makeVar, forgetCache, recallCache } from './reactiveVars';
import {
defaultDataIdFromObject,
PossibleTypesMap,
Policies,
TypePolicies,
} from './policies';
import { hasOwn } from './helpers';
import { Policies } from './policies';
import { hasOwn, normalizeConfig, shouldCanonizeResults } from './helpers';
import { canonicalStringify } from './object-canon';

export interface InMemoryCacheConfig extends ApolloReducerConfig {
resultCaching?: boolean;
possibleTypes?: PossibleTypesMap;
typePolicies?: TypePolicies;
resultCacheMaxSize?: number;
canonizeResults?: boolean;
}

type BroadcastOptions = Pick<
Cache.BatchOptions<InMemoryCache>,
| "optimistic"
| "onWatchUpdated"
>

const defaultConfig = {
dataIdFromObject: defaultDataIdFromObject,
addTypename: true,
resultCaching: true,
// Thanks to the shouldCanonizeResults helper, this should be the only line
// you have to change to reenable canonization by default in the future.
canonizeResults: false,
};

export function shouldCanonizeResults(
config: Pick<InMemoryCacheConfig, "canonizeResults">,
): boolean {
const value = config.canonizeResults;
return value === void 0 ? defaultConfig.canonizeResults : value;
}

export class InMemoryCache extends ApolloCache<NormalizedCacheObject> {
private data: EntityStore;
private optimisticData: EntityStore;
Expand All @@ -88,7 +55,7 @@ export class InMemoryCache extends ApolloCache<NormalizedCacheObject> {

constructor(config: InMemoryCacheConfig = {}) {
super();
this.config = compact(defaultConfig, config);
this.config = normalizeConfig(config);
this.addTypename = !!this.config.addTypename;

this.policies = new Policies({
Expand Down
25 changes: 2 additions & 23 deletions src/cache/inmemory/policies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
storeValueIsStoreObject,
selectionSetMatchesResult,
TypeOrFieldNameRegExp,
defaultDataIdFromObject,
} from './helpers';
import { cacheSlot } from './reactiveVars';
import { InMemoryCache } from './inMemoryCache';
Expand Down Expand Up @@ -65,7 +66,7 @@ export type TypePolicies = {
// type KeySpecifier = (string | KeySpecifier)[]
type KeySpecifier = (string | any[])[];

type KeyFieldsContext = {
export type KeyFieldsContext = {
typename?: string;
selectionSet?: SelectionSetNode;
fragmentMap?: FragmentMap;
Expand Down Expand Up @@ -230,28 +231,6 @@ export type FieldMergeFunction<TExisting = any, TIncoming = TExisting> = (
options: FieldFunctionOptions,
) => SafeReadonly<TExisting>;

export const defaultDataIdFromObject = (
{ __typename, id, _id }: Readonly<StoreObject>,
context?: KeyFieldsContext,
) => {
if (typeof __typename === "string") {
if (context) {
context.keyObject =
id !== void 0 ? { id } :
_id !== void 0 ? { _id } :
void 0;
}
// If there is no object.id, fall back to object._id.
if (id === void 0) id = _id;
if (id !== void 0) {
return `${__typename}:${(
typeof id === "number" ||
typeof id === "string"
) ? id : JSON.stringify(id)}`;
}
}
};

const nullKeyFieldsFn: KeyFieldsFunction = () => void 0;
const simpleKeyArgsFn: KeyArgsFunction = (_args, context) => context.fieldName;

Expand Down
4 changes: 2 additions & 2 deletions src/cache/inmemory/readFromStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ import {
ReadMergeModifyContext,
} from './types';
import { maybeDependOnExistenceOfEntity, supportsResultCaching } from './entityStore';
import { getTypenameFromStoreObject } from './helpers';
import { getTypenameFromStoreObject, shouldCanonizeResults } from './helpers';
import { Policies } from './policies';
import { shouldCanonizeResults, InMemoryCache } from './inMemoryCache';
import { InMemoryCache } from './inMemoryCache';
import { MissingFieldError } from '../core/types/common';
import { canonicalStringify, ObjectCanon } from './object-canon';

Expand Down
17 changes: 16 additions & 1 deletion src/cache/inmemory/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,20 @@ import {
Reference,
} from '../../utilities';
import { FieldValueGetter } from './entityStore';
import { KeyFieldsFunction, StorageType, FieldMergeFunction } from './policies';
import {
TypePolicies,
PossibleTypesMap,
KeyFieldsFunction,
StorageType,
FieldMergeFunction,
} from './policies';
import {
Modifier,
Modifiers,
ToReferenceFunction,
CanReadFunction,
} from '../core/types/common';

export { StoreObject, StoreValue, Reference }

export interface IdGetterObj extends Object {
Expand Down Expand Up @@ -117,6 +124,14 @@ export type ApolloReducerConfig = {
addTypename?: boolean;
};

export interface InMemoryCacheConfig extends ApolloReducerConfig {
resultCaching?: boolean;
possibleTypes?: PossibleTypesMap;
typePolicies?: TypePolicies;
resultCacheMaxSize?: number;
canonizeResults?: boolean;
}

export interface MergeInfo {
field: FieldNode;
typename: string | undefined;
Expand Down
2 changes: 1 addition & 1 deletion src/core/__tests__/QueryManager/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { setVerbosity } from 'ts-invariant';

import { Observable, Observer } from '../../../utilities/observables/Observable';
import { ApolloLink, GraphQLRequest, FetchResult } from '../../../link/core';
import { InMemoryCache, InMemoryCacheConfig } from '../../../cache/inmemory/inMemoryCache';
import { InMemoryCache, InMemoryCacheConfig } from '../../../cache';
import {
ApolloReducerConfig,
NormalizedCacheObject
Expand Down

0 comments on commit d9a1039

Please sign in to comment.