From c61e6d524dd405d44202fb3aa042b1ed97cf0e02 Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Wed, 26 Jul 2023 20:31:03 +0100 Subject: [PATCH 1/5] Provide a more consistent parent[fieldName] rather than parent[fieldAlias] --- exchanges/graphcache/src/operations/query.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/exchanges/graphcache/src/operations/query.ts b/exchanges/graphcache/src/operations/query.ts index e87f1045e4..dc0429b3bd 100644 --- a/exchanges/graphcache/src/operations/query.ts +++ b/exchanges/graphcache/src/operations/query.ts @@ -426,13 +426,20 @@ const readSelection = ( updateContext(ctx, output, typename, entityKey, key, fieldName); // We have a resolver for this field. - // Prepare the actual fieldValue, so that the resolver can use it - if (fieldValue !== undefined) { - output[fieldAlias] = fieldValue; + // Prepare the actual fieldValue, so that the resolver can use it, + // as to avoid the user having to do `cache.resolve(parent, info.fieldKey)` + // only to get a scalar value. + let parent = output; + if (node.selectionSet === undefined && fieldValue !== undefined) { + parent = { + ...output, + [fieldAlias]: fieldValue, + [fieldName]: fieldValue, + }; } dataFieldValue = resolver( - output, + parent, fieldArgs || ({} as Variables), store, ctx From 4dbe1102ded62d0b55fb9d4ac935ce6856446a09 Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Wed, 26 Jul 2023 20:32:58 +0100 Subject: [PATCH 2/5] Prevent incorrect key from being passed to updateContext's fieldKey --- exchanges/graphcache/src/operations/query.ts | 2 +- exchanges/graphcache/src/operations/write.ts | 2 +- exchanges/graphcache/src/store/store.test.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/exchanges/graphcache/src/operations/query.ts b/exchanges/graphcache/src/operations/query.ts index dc0429b3bd..1f72af5e2e 100644 --- a/exchanges/graphcache/src/operations/query.ts +++ b/exchanges/graphcache/src/operations/query.ts @@ -423,7 +423,7 @@ const readSelection = ( } else if (InMemoryData.currentOperation === 'read' && resolver) { // We have to update the information in context to reflect the info // that the resolver will receive - updateContext(ctx, output, typename, entityKey, key, fieldName); + updateContext(ctx, output, typename, entityKey, fieldKey, fieldName); // We have a resolver for this field. // Prepare the actual fieldValue, so that the resolver can use it, diff --git a/exchanges/graphcache/src/operations/write.ts b/exchanges/graphcache/src/operations/write.ts index f5bbfe2a47..cf8f74c5bc 100644 --- a/exchanges/graphcache/src/operations/write.ts +++ b/exchanges/graphcache/src/operations/write.ts @@ -354,7 +354,7 @@ const writeSelection = ( data, typename, entityKey || typename, - joinKeys(typename, fieldKey), + fieldKey, fieldName ); diff --git a/exchanges/graphcache/src/store/store.test.ts b/exchanges/graphcache/src/store/store.test.ts index 041575059d..40222efe68 100644 --- a/exchanges/graphcache/src/store/store.test.ts +++ b/exchanges/graphcache/src/store/store.test.ts @@ -425,7 +425,7 @@ describe('Store with OptimisticMutationConfig', () => { randomData, 'Todo', 'Todo:1', - 'Todo:1.createdAt', + 'createdAt', 'createdAt' ); From f2d634e05165a3256d6c8aeb68e3c6eadaaa5767 Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Wed, 26 Jul 2023 20:34:49 +0100 Subject: [PATCH 3/5] Update parent passed to updateContext --- exchanges/graphcache/src/operations/query.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/exchanges/graphcache/src/operations/query.ts b/exchanges/graphcache/src/operations/query.ts index 1f72af5e2e..10aeff4f48 100644 --- a/exchanges/graphcache/src/operations/query.ts +++ b/exchanges/graphcache/src/operations/query.ts @@ -421,10 +421,6 @@ const readSelection = ( // The field is a scalar and can be retrieved directly from the result dataFieldValue = resultValue; } else if (InMemoryData.currentOperation === 'read' && resolver) { - // We have to update the information in context to reflect the info - // that the resolver will receive - updateContext(ctx, output, typename, entityKey, fieldKey, fieldName); - // We have a resolver for this field. // Prepare the actual fieldValue, so that the resolver can use it, // as to avoid the user having to do `cache.resolve(parent, info.fieldKey)` @@ -438,6 +434,10 @@ const readSelection = ( }; } + // We have to update the information in context to reflect the info + // that the resolver will receive + updateContext(ctx, parent, typename, entityKey, fieldKey, fieldName); + dataFieldValue = resolver( parent, fieldArgs || ({} as Variables), From 6f715c936740c5d7761a7db35fb6f2078964be8b Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Wed, 26 Jul 2023 20:37:02 +0100 Subject: [PATCH 4/5] Remove src/helpers/dict.ts --- exchanges/graphcache/src/helpers/dict.ts | 6 ------ exchanges/graphcache/src/store/data.ts | 5 ++--- 2 files changed, 2 insertions(+), 9 deletions(-) delete mode 100644 exchanges/graphcache/src/helpers/dict.ts diff --git a/exchanges/graphcache/src/helpers/dict.ts b/exchanges/graphcache/src/helpers/dict.ts deleted file mode 100644 index ac3cd501f8..0000000000 --- a/exchanges/graphcache/src/helpers/dict.ts +++ /dev/null @@ -1,6 +0,0 @@ -export const makeDict = (): any => Object.create(null); - -export const isDictEmpty = (x: any) => { - for (const _ in x) return false; - return true; -}; diff --git a/exchanges/graphcache/src/store/data.ts b/exchanges/graphcache/src/store/data.ts index 7346eb7457..87f78c2606 100644 --- a/exchanges/graphcache/src/store/data.ts +++ b/exchanges/graphcache/src/store/data.ts @@ -19,7 +19,6 @@ import { joinKeys, } from './keys'; -import { makeDict } from '../helpers/dict'; import { invariant, currentDebugStack } from '../helpers/help'; type Dict = Record; @@ -283,7 +282,7 @@ const setNode = ( // On the map itself we get or create the entity as a dict let entity = keymap.get(entityKey) as Dict; if (entity === undefined) { - keymap.set(entityKey, (entity = makeDict())); + keymap.set(entityKey, (entity = Object.create(null))); } // If we're setting undefined we delete the node's entry @@ -614,7 +613,7 @@ export const persistData = () => { if (currentData!.storage) { currentOptimistic = true; currentOperation = 'read'; - const entries: SerializedEntries = makeDict(); + const entries: SerializedEntries = {}; for (const key of currentData!.persist.keys()) { const { entityKey, fieldKey } = deserializeKeyInfo(key); let x: void | Link | EntityField; From d28171784733c479583ebeccb1a96ab0d4a3f64f Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Wed, 26 Jul 2023 20:40:22 +0100 Subject: [PATCH 5/5] Add changesets --- .changeset/hungry-experts-admire.md | 5 +++++ .changeset/tame-ways-obey.md | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 .changeset/hungry-experts-admire.md create mode 100644 .changeset/tame-ways-obey.md diff --git a/.changeset/hungry-experts-admire.md b/.changeset/hungry-experts-admire.md new file mode 100644 index 0000000000..e486762c21 --- /dev/null +++ b/.changeset/hungry-experts-admire.md @@ -0,0 +1,5 @@ +--- +'@urql/exchange-graphcache': minor +--- + +Allow scalar values on the parent to be accessed from `parent[info.fieldName]` consistently. Prior to this change `parent[fieldAlias]` would get populated, which wouldn’t always result in a field that’s consistently accessible. diff --git a/.changeset/tame-ways-obey.md b/.changeset/tame-ways-obey.md new file mode 100644 index 0000000000..e4c358c46c --- /dev/null +++ b/.changeset/tame-ways-obey.md @@ -0,0 +1,5 @@ +--- +'@urql/exchange-graphcache': patch +--- + +Fix cases where `ResolveInfo`’s `parentFieldKey` was incorrectly populated with a key that isn’t a field key (allowing for `cache.resolve(info.parentKey, info.parentFieldKey)` to be possible) but was instead set to `info.parentKey` combined with the field key.