From 1b8d95b6515eb66f89adcf29ddd8379c37500a4d Mon Sep 17 00:00:00 2001 From: Dominik Ferber Date: Mon, 7 May 2018 21:35:48 +0200 Subject: [PATCH] Avoid removing used generated data from cache --- .../src/__tests__/writeToStore.ts | 224 ++++++++++-------- .../apollo-cache-inmemory/src/writeToStore.ts | 7 +- 2 files changed, 129 insertions(+), 102 deletions(-) diff --git a/packages/apollo-cache-inmemory/src/__tests__/writeToStore.ts b/packages/apollo-cache-inmemory/src/__tests__/writeToStore.ts index 23bdb4de592..1d5918d23ca 100644 --- a/packages/apollo-cache-inmemory/src/__tests__/writeToStore.ts +++ b/packages/apollo-cache-inmemory/src/__tests__/writeToStore.ts @@ -1882,174 +1882,196 @@ describe('writing to the store', () => { }); }); - it('should updated nested inlined array fields', () => { + it('should keep reference when type of mixed inlined field with changes', () => { const store = defaultNormalizedCacheFactory(); const query = gql` query { - shelter { - id - animals { + animals { + species { name - species { - name - } } } } `; - const dataIdFromObject = (object: any) => { - if (object.__typename && object.id) { - return object.__typename + '__' + object.id; - } - return undefined; - }; - writeQueryToStore({ query, - dataIdFromObject, result: { - shelter: { - __typename: 'Shelter', - animals: [ - { - __typename: 'Animal', - name: 'Carol', - species: { - __typename: 'Cat', - name: 'cat', - }, - }, - { - __typename: 'Animal', - name: 'Dieter', - species: { - __typename: 'Dog', - name: 'dog', - }, + animals: [ + { + __typename: 'Animal', + species: { + __typename: 'Cat', + name: 'cat', }, - ], - id: 'some-id', - }, + }, + ], }, store, }); expect(store.toObject()).toEqual({ - '$Shelter__some-id.animals.0.species': { - name: 'cat', - }, - '$Shelter__some-id.animals.1.species': { - name: 'dog', - }, - 'Shelter__some-id': { + '$ROOT_QUERY.animals.0.species': { name: 'cat' }, + ROOT_QUERY: { animals: [ { generated: true, - id: 'Shelter__some-id.animals.0', - type: 'id', - typename: 'Animal', - }, - { - generated: true, - id: 'Shelter__some-id.animals.1', + id: 'ROOT_QUERY.animals.0', type: 'id', typename: 'Animal', }, ], - id: 'some-id', }, - 'Shelter__some-id.animals.0': { - name: 'Carol', + 'ROOT_QUERY.animals.0': { species: { generated: true, - id: '$Shelter__some-id.animals.0.species', + id: '$ROOT_QUERY.animals.0.species', type: 'id', typename: 'Cat', }, }, - 'Shelter__some-id.animals.1': { - name: 'Dieter', + }); + + writeQueryToStore({ + query, + result: { + animals: [ + { + __typename: 'Animal', + species: { + __typename: 'Dog', + name: 'dog', + }, + }, + ], + }, + store, + }); + + expect(store.toObject()).toEqual({ + '$ROOT_QUERY.animals.0.species': { name: 'dog' }, + ROOT_QUERY: { + animals: [ + { + generated: true, + id: 'ROOT_QUERY.animals.0', + type: 'id', + typename: 'Animal', + }, + ], + }, + 'ROOT_QUERY.animals.0': { species: { generated: true, - id: '$Shelter__some-id.animals.1.species', + id: '$ROOT_QUERY.animals.0.species', type: 'id', typename: 'Dog', }, }, - ROOT_QUERY: { - shelter: { - generated: false, - id: 'Shelter__some-id', - type: 'id', - typename: 'Shelter', - }, - }, }); + }); + + it('should not keep reference when type of mixed inlined field with changes to non-inlined field', () => { + const store = defaultNormalizedCacheFactory(); + + const dataIdFromObject = (object: any) => { + if (object.__typename && object.id) { + return object.__typename + '__' + object.id; + } + return undefined; + }; + + const query = gql` + query { + animals { + species { + id + name + } + } + } + `; writeQueryToStore({ query, - dataIdFromObject, result: { - shelter: { - __typename: 'Shelter', - animals: [ - // First element deleted -> nested "type" field has GraphQL Type change - { - __typename: 'Animal', - name: 'Dieter', - species: { - __typename: 'Dog', - name: 'dog', - }, + animals: [ + { + __typename: 'Animal', + species: { + __typename: 'Cat', + name: 'cat', }, - ], - id: 'some-id', - }, + }, + ], }, + dataIdFromObject, store, }); expect(store.toObject()).toEqual({ - '$Shelter__some-id.animals.0.species': { - name: 'dog', - }, - 'Shelter__some-id': { + '$ROOT_QUERY.animals.0.species': { name: 'cat' }, + ROOT_QUERY: { animals: [ { generated: true, - id: 'Shelter__some-id.animals.0', + id: 'ROOT_QUERY.animals.0', type: 'id', typename: 'Animal', }, ], - id: 'some-id', }, - 'Shelter__some-id.animals.0': { - name: 'Dieter', + 'ROOT_QUERY.animals.0': { species: { generated: true, - id: '$Shelter__some-id.animals.0.species', + id: '$ROOT_QUERY.animals.0.species', type: 'id', - typename: 'Dog', + typename: 'Cat', }, }, - 'Shelter__some-id.animals.1': { - name: 'Dieter', - species: { - generated: true, - id: '$Shelter__some-id.animals.1.species', - type: 'id', - typename: 'Dog', - }, + }); + + writeQueryToStore({ + query, + result: { + animals: [ + { + __typename: 'Animal', + species: { + id: 'dog-species', + __typename: 'Dog', + name: 'dog', + }, + }, + ], + }, + dataIdFromObject, + store, + }); + + expect(store.toObject()).toEqual({ + '$ROOT_QUERY.animals.0.species': undefined, + 'Dog__dog-species': { + id: 'dog-species', + name: 'dog', }, ROOT_QUERY: { - shelter: { + animals: [ + { + generated: true, + id: 'ROOT_QUERY.animals.0', + type: 'id', + typename: 'Animal', + }, + ], + }, + 'ROOT_QUERY.animals.0': { + species: { generated: false, - id: 'Shelter__some-id', + id: 'Dog__dog-species', type: 'id', - typename: 'Shelter', + typename: 'Dog', }, }, }); diff --git a/packages/apollo-cache-inmemory/src/writeToStore.ts b/packages/apollo-cache-inmemory/src/writeToStore.ts index ae2d65baab5..47886451eda 100644 --- a/packages/apollo-cache-inmemory/src/writeToStore.ts +++ b/packages/apollo-cache-inmemory/src/writeToStore.ts @@ -453,7 +453,12 @@ function writeFieldToStore({ // we should only merge if it's an object of the same type // otherwise, we should delete the generated object if (typenameChanged) { - store.delete(generatedKey); + // remove the old generated value in case the old value was + // inlined and the new value is not, which is indicated by + // the old id being generated and the new id being real + if (!generated) { + store.delete(generatedKey); + } } else { shouldMerge = true; }