From e90f54da624d66c5370a8bd92d11a47f924284e7 Mon Sep 17 00:00:00 2001 From: Ian MacLeod Date: Sun, 10 Jul 2016 19:44:05 -0700 Subject: [PATCH] Pass a context object around with store data This makes it quite a bit easier to pass additional configuration to the data/* functions --- src/QueryManager.ts | 30 ++++++++++++++--------- src/data/diffAgainstStore.ts | 46 ++++++++++++++++-------------------- src/data/readFromStore.ts | 18 +++++++------- test/diffAgainstStore.ts | 31 +++++++++++++++++------- 4 files changed, 70 insertions(+), 55 deletions(-) diff --git a/src/QueryManager.ts b/src/QueryManager.ts index f45e0fbb53f..9b4263f3c68 100644 --- a/src/QueryManager.ts +++ b/src/QueryManager.ts @@ -325,12 +325,14 @@ export class QueryManager { try { const resultFromStore = { data: readSelectionSetFromStore({ - store: this.getDataWithOptimisticResults(), + context: { + store: this.getDataWithOptimisticResults(), + fragmentMap: queryStoreValue.fragmentMap, + }, rootId: queryStoreValue.query.id, selectionSet: queryStoreValue.query.selectionSet, variables: queryStoreValue.variables, returnPartialData: options.returnPartialData || options.noFetch, - fragmentMap: queryStoreValue.fragmentMap, }), loading: queryStoreValue.loading, }; @@ -558,15 +560,17 @@ export class QueryManager { } const previousResult = readSelectionSetFromStore({ - // In case of an optimistic change, apply reducer on top of the - // results including previous optimistic updates. Otherwise, apply it - // on top of the real data only. - store: isOptimistic ? this.getDataWithOptimisticResults() : this.getApolloState().data, + context: { + // In case of an optimistic change, apply reducer on top of the + // results including previous optimistic updates. Otherwise, apply it + // on top of the real data only. + store: isOptimistic ? this.getDataWithOptimisticResults() : this.getApolloState().data, + fragmentMap: createFragmentMap(fragments || []), + }, rootId: 'ROOT_QUERY', selectionSet: queryDefinition.selectionSet, variables: queryOptions.variables, returnPartialData: queryOptions.returnPartialData || queryOptions.noFetch, - fragmentMap: createFragmentMap(fragments || []), }); return { @@ -674,12 +678,14 @@ export class QueryManager { initialResult: Object, } { const { missingSelectionSets, result } = diffSelectionSetAgainstStore({ + context: { + store: this.store.getState()[this.reduxRootKey].data, + fragmentMap, + }, selectionSet: queryDef.selectionSet, - store: this.store.getState()[this.reduxRootKey].data, throwOnMissingField: false, rootId, variables, - fragmentMap, }); const initialResult = result; @@ -761,12 +767,14 @@ export class QueryManager { // this will throw an error if there are missing fields in // the results if returnPartialData is false. resultFromStore = readSelectionSetFromStore({ - store: this.getApolloState().data, + context: { + store: this.getApolloState().data, + fragmentMap, + }, rootId: querySS.id, selectionSet: querySS.selectionSet, variables, returnPartialData: returnPartialData || noFetch, - fragmentMap, }); // ensure multiple errors don't get thrown /* tslint:disable */ diff --git a/src/data/diffAgainstStore.ts b/src/data/diffAgainstStore.ts index c1710364ec0..6e8544b6269 100644 --- a/src/data/diffAgainstStore.ts +++ b/src/data/diffAgainstStore.ts @@ -52,6 +52,13 @@ export interface DiffResult { missingSelectionSets?: SelectionSetWithRoot[]; } +// Contexual state and configuration that is used throught a request from the +// store. +export interface StoreContext { + store: NormalizedCache; + fragmentMap: FragmentMap; +} + export function diffQueryAgainstStore({ store, query, @@ -64,7 +71,7 @@ export function diffQueryAgainstStore({ const queryDef = getQueryDefinition(query); return diffSelectionSetAgainstStore({ - store, + context: { store, fragmentMap: {} }, rootId: 'ROOT_QUERY', selectionSet: queryDef.selectionSet, throwOnMissingField: false, @@ -86,7 +93,7 @@ export function diffFragmentAgainstStore({ const fragmentDef = getFragmentDefinition(fragment); return diffSelectionSetAgainstStore({ - store, + context: { store, fragmentMap: {} }, rootId, selectionSet: fragmentDef.selectionSet, throwOnMissingField: false, @@ -126,28 +133,22 @@ export function handleFragmentErrors(fragmentErrors: { [typename: string]: Error * @return {result: Object, missingSelectionSets: [SelectionSet]} */ export function diffSelectionSetAgainstStore({ + context, selectionSet, - store, rootId, throwOnMissingField = false, variables, - fragmentMap, }: { + context: StoreContext, selectionSet: SelectionSet, - store: NormalizedCache, rootId: string, throwOnMissingField: boolean, variables: Object, - fragmentMap?: FragmentMap, }): DiffResult { if (selectionSet.kind !== 'SelectionSet') { throw new Error('Must be a selection set.'); } - if (!fragmentMap) { - fragmentMap = {}; - } - const result = {}; const missingFields: Selection[] = []; @@ -177,12 +178,11 @@ export function diffSelectionSetAgainstStore({ if (isField(selection)) { const diffResult = diffFieldAgainstStore({ + context, field: selection, throwOnMissingField, variables, rootId, - store, - fragmentMap, included, }); fieldIsMissing = diffResult.isMissing; @@ -204,12 +204,11 @@ export function diffSelectionSetAgainstStore({ if (included) { try { const diffResult = diffSelectionSetAgainstStore({ + context, selectionSet: selection.selectionSet, throwOnMissingField, variables, rootId, - store, - fragmentMap, }); fieldIsMissing = diffResult.isMissing; fieldResult = diffResult.result; @@ -232,7 +231,7 @@ export function diffSelectionSetAgainstStore({ } } } else { - const fragment = fragmentMap[selection.name.value]; + const fragment = context.fragmentMap[selection.name.value]; if (!fragment) { throw new Error(`No fragment named ${selection.name.value}`); @@ -243,12 +242,11 @@ export function diffSelectionSetAgainstStore({ if (included) { try { const diffResult = diffSelectionSetAgainstStore({ + context, selectionSet: fragment.selectionSet, throwOnMissingField, variables, rootId, - store, - fragmentMap, }); fieldIsMissing = diffResult.isMissing; fieldResult = diffResult.result; @@ -311,23 +309,21 @@ export function diffSelectionSetAgainstStore({ } function diffFieldAgainstStore({ + context, field, throwOnMissingField, variables, rootId, - store, - fragmentMap, included = true, }: { + context: StoreContext, field: Field, throwOnMissingField: boolean, variables: Object, rootId: string, - store: NormalizedCache, - fragmentMap?: FragmentMap, included?: Boolean, }): FieldDiffResult { - const storeObj = store[rootId] || {}; + const storeObj = context.store[rootId] || {}; const storeFieldKey = storeKeyNameFromField(field, variables); if (! has(storeObj, storeFieldKey)) { @@ -382,12 +378,11 @@ Perhaps you want to use the \`returnPartialData\` option?`, } const itemDiffResult = diffSelectionSetAgainstStore({ - store, + context, throwOnMissingField, rootId: id, selectionSet: field.selectionSet, variables, - fragmentMap, }); if (itemDiffResult.isMissing) { @@ -409,12 +404,11 @@ Perhaps you want to use the \`returnPartialData\` option?`, if (isIdValue(storeValue)) { const unescapedId = storeValue.id; return diffSelectionSetAgainstStore({ - store, + context, throwOnMissingField, rootId: unescapedId, selectionSet: field.selectionSet, variables, - fragmentMap, }); } diff --git a/src/data/readFromStore.ts b/src/data/readFromStore.ts index 510b7ea7e95..a7164cdfbbd 100644 --- a/src/data/readFromStore.ts +++ b/src/data/readFromStore.ts @@ -1,5 +1,6 @@ import { diffSelectionSetAgainstStore, + StoreContext, } from './diffAgainstStore'; import { @@ -37,12 +38,14 @@ export function readQueryFromStore({ const queryDef = getQueryDefinition(query); return readSelectionSetFromStore({ - store, + context: { + store, + fragmentMap: fragmentMap || {}, + }, rootId: 'ROOT_QUERY', selectionSet: queryDef.selectionSet, variables, returnPartialData, - fragmentMap, }); } @@ -62,7 +65,7 @@ export function readFragmentFromStore({ const fragmentDef = getFragmentDefinition(fragment); return readSelectionSetFromStore({ - store, + context: { store, fragmentMap: {} }, rootId, selectionSet: fragmentDef.selectionSet, variables, @@ -71,29 +74,26 @@ export function readFragmentFromStore({ } export function readSelectionSetFromStore({ - store, + context, rootId, selectionSet, variables, returnPartialData = false, - fragmentMap, }: { - store: NormalizedCache, + context: StoreContext, rootId: string, selectionSet: SelectionSet, variables: Object, returnPartialData?: boolean, - fragmentMap?: FragmentMap, }): Object { const { result, } = diffSelectionSetAgainstStore({ + context, selectionSet, rootId, - store, throwOnMissingField: !returnPartialData, variables, - fragmentMap, }); return result; diff --git a/test/diffAgainstStore.ts b/test/diffAgainstStore.ts index 7b2cc3830d3..b218e9c6f0b 100644 --- a/test/diffAgainstStore.ts +++ b/test/diffAgainstStore.ts @@ -311,7 +311,10 @@ describe('diffing queries against the store', () => { }`; assert.throws(() => { diffSelectionSetAgainstStore({ - store, + context: { + store, + fragmentMap: {}, + }, rootId: 'ROOT_QUERY', selectionSet: getQueryDefinition(unionQuery).selectionSet, variables: null, @@ -353,7 +356,10 @@ describe('diffing queries against the store', () => { }`; assert.doesNotThrow(() => { diffSelectionSetAgainstStore({ - store, + context: { + store, + fragmentMap: {}, + }, rootId: 'ROOT_QUERY', selectionSet: getQueryDefinition(unionQuery).selectionSet, variables: null, @@ -395,12 +401,14 @@ describe('diffing queries against the store', () => { }`; assert.doesNotThrow(() => { diffSelectionSetAgainstStore({ - store, + context: { + store, + fragmentMap: createFragmentMap(getFragmentDefinitions(unionQuery)), + }, rootId: 'ROOT_QUERY', selectionSet: getQueryDefinition(unionQuery).selectionSet, variables: null, throwOnMissingField: true, - fragmentMap: createFragmentMap(getFragmentDefinitions(unionQuery)), }); }); }); @@ -439,12 +447,14 @@ describe('diffing queries against the store', () => { }`; assert.throw(() => { diffSelectionSetAgainstStore({ - store, + context: { + store, + fragmentMap: createFragmentMap(getFragmentDefinitions(unionQuery)), + }, rootId: 'ROOT_QUERY', selectionSet: getQueryDefinition(unionQuery).selectionSet, variables: null, throwOnMissingField: true, - fragmentMap: createFragmentMap(getFragmentDefinitions(unionQuery)), }); }); }); @@ -484,7 +494,10 @@ describe('diffing queries against the store', () => { assert.throw(() => { diffSelectionSetAgainstStore({ - store, + context: { + store, + fragmentMap: {}, + }, rootId: 'ROOT_QUERY', selectionSet: getQueryDefinition(unionQuery).selectionSet, variables: null, @@ -527,7 +540,7 @@ describe('diffing queries against the store', () => { `; const { result } = diffSelectionSetAgainstStore({ - store, + context: { store, fragmentMap: {} }, rootId: 'ROOT_QUERY', selectionSet: getQueryDefinition(queryWithMissingField).selectionSet, variables: null, @@ -541,7 +554,7 @@ describe('diffing queries against the store', () => { }); assert.throws(function() { diffSelectionSetAgainstStore({ - store, + context: { store, fragmentMap: {} }, rootId: 'ROOT_QUERY', selectionSet: getQueryDefinition(queryWithMissingField).selectionSet, variables: null,