From de38f3c2ba51b7c64a3ec826d3d33df775769b40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Greg=20Berg=C3=A9?= Date: Mon, 29 Jan 2018 12:30:10 -0400 Subject: [PATCH] feat(apollo-cache-inmemory): support custom directives (#2710) Before this change, using a custom directive corrupted the cache. It is now possible to safely use a custom directive without breaking it. Example of custom directives: https://github.com/smooth-code/graphql-directive --- .../src/__tests__/readFromStore.ts | 32 +++++++++++++++++++ .../src/__tests__/writeToStore.ts | 32 +++++++++++++++++++ packages/apollo-client/AUTHORS | 1 + packages/apollo-utilities/CHANGELOG.md | 3 ++ packages/apollo-utilities/src/storeUtils.ts | 18 +++++++++-- 5 files changed, 84 insertions(+), 2 deletions(-) diff --git a/packages/apollo-cache-inmemory/src/__tests__/readFromStore.ts b/packages/apollo-cache-inmemory/src/__tests__/readFromStore.ts index 35a990e9f67..f2a77c39965 100644 --- a/packages/apollo-cache-inmemory/src/__tests__/readFromStore.ts +++ b/packages/apollo-cache-inmemory/src/__tests__/readFromStore.ts @@ -165,6 +165,38 @@ describe('reading from the store', () => { }); }); + it('runs a basic query with custom directives', () => { + const query = gql` + query { + id + firstName @include(if: true) + lastName @upperCase + birthDate @dateFormat(format: "DD-MM-YYYY") + } + `; + + const store = defaultNormalizedCacheFactory({ + ROOT_QUERY: { + id: 'abcd', + firstName: 'James', + 'lastName@upperCase': 'BOND', + 'birthDate@dateFormat({"format":"DD-MM-YYYY"})': '20-05-1940', + }, + }); + + const result = readQueryFromStore({ + store, + query, + }); + + expect(result).toEqual({ + id: 'abcd', + firstName: 'James', + lastName: 'BOND', + birthDate: '20-05-1940', + }); + }); + it('runs a basic query with default values for arguments', () => { const query = gql` query someBigQuery( diff --git a/packages/apollo-cache-inmemory/src/__tests__/writeToStore.ts b/packages/apollo-cache-inmemory/src/__tests__/writeToStore.ts index 0384c92e678..967f42c3a77 100644 --- a/packages/apollo-cache-inmemory/src/__tests__/writeToStore.ts +++ b/packages/apollo-cache-inmemory/src/__tests__/writeToStore.ts @@ -221,6 +221,38 @@ describe('writing to the store', () => { }); }); + it('properly normalizes a query with custom directives', () => { + const query = gql` + query { + id + firstName @include(if: true) + lastName @upperCase + birthDate @dateFormat(format: "DD-MM-YYYY") + } + `; + + const result: any = { + id: 'abcd', + firstName: 'James', + lastName: 'BOND', + birthDate: '20-05-1940', + }; + + const normalized = writeQueryToStore({ + result, + query, + }); + + expect(normalized.toObject()).toEqual({ + ROOT_QUERY: { + id: 'abcd', + firstName: 'James', + 'lastName@upperCase': 'BOND', + 'birthDate@dateFormat({"format":"DD-MM-YYYY"})': '20-05-1940', + }, + }); + }); + it('properly normalizes a nested object with an ID', () => { const query = gql` { diff --git a/packages/apollo-client/AUTHORS b/packages/apollo-client/AUTHORS index 7d2825b5608..1845df4e602 100644 --- a/packages/apollo-client/AUTHORS +++ b/packages/apollo-client/AUTHORS @@ -89,3 +89,4 @@ Robert Simon Sondre Maere Overskaug Tim Griesser Adam Tuttle +Greg Bergé diff --git a/packages/apollo-utilities/CHANGELOG.md b/packages/apollo-utilities/CHANGELOG.md index 303ca6ae892..6f2afeb4b3c 100644 --- a/packages/apollo-utilities/CHANGELOG.md +++ b/packages/apollo-utilities/CHANGELOG.md @@ -4,6 +4,9 @@ ### vNext - Fix typo in error message for invalid argument being passed to @skip or @include directives [PR#2867](https://github.com/apollographql/apollo-client/pull/2867) +### 1.1.0 +- update `getStoreKeyName` to support custom directives + ### 1.0.5 - package dependency updates diff --git a/packages/apollo-utilities/src/storeUtils.ts b/packages/apollo-utilities/src/storeUtils.ts index bf330ea2f48..ea7ee44d74d 100644 --- a/packages/apollo-utilities/src/storeUtils.ts +++ b/packages/apollo-utilities/src/storeUtils.ts @@ -164,6 +164,8 @@ export type Directives = { }; }; +const KNOWN_DIRECTIVES: string[] = ['connection', 'include', 'skip']; + export function getStoreKeyName( fieldName: string, args?: Object, @@ -197,13 +199,25 @@ export function getStoreKeyName( } } + let completeFieldName: string = fieldName; + if (args) { const stringifiedArgs: string = JSON.stringify(args); + completeFieldName += `(${stringifiedArgs})`; + } - return `${fieldName}(${stringifiedArgs})`; + if (directives) { + Object.keys(directives).forEach(key => { + if (KNOWN_DIRECTIVES.indexOf(key) !== -1) return; + if (directives[key] && Object.keys(directives[key]).length) { + completeFieldName += `@${key}(${JSON.stringify(directives[key])})`; + } else { + completeFieldName += `@${key}`; + } + }); } - return fieldName; + return completeFieldName; } export function argumentsObjectFromField(