Skip to content

Commit

Permalink
fix(graphcache): Cascade @defer, @_optional, and @_required sta…
Browse files Browse the repository at this point in the history
…te only per nested fragment spread (#3517)
  • Loading branch information
kitten committed Mar 2, 2024
1 parent ceeb73b commit e9b476b
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 18 deletions.
5 changes: 5 additions & 0 deletions .changeset/sixty-needles-exercise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@urql/exchange-graphcache': patch
---

Prevent `@defer` from being applied in child field selections. Previously, a child field (i.e. a nested field) under a `@defer`-ed fragment would also become optional, which was based on a prior version of the DeferStream spec which didn't require deferred fields to be delivered as a group.
6 changes: 4 additions & 2 deletions exchanges/graphcache/src/cacheExchange.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -909,8 +909,10 @@ describe('directives', () => {
todos {
id
text
... on Todo @_optional {
completed
... @_optional {
... on Todo {
completed
}
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions exchanges/graphcache/src/operations/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ const readRoot = (
const iterate = makeSelectionIterator(
entityKey,
entityKey,
deferRef,
false,
undefined,
select,
ctx
Expand Down Expand Up @@ -390,7 +390,7 @@ const readSelection = (
const iterate = makeSelectionIterator(
typename,
entityKey,
deferRef,
false,
undefined,
select,
ctx
Expand Down
44 changes: 31 additions & 13 deletions exchanges/graphcache/src/operations/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,6 @@ export const makeContext = (
entityKey: string,
error: CombinedError | undefined
): Context => {
deferRef = false;

const ctx: Context = {
store,
variables,
Expand Down Expand Up @@ -163,23 +161,42 @@ interface SelectionIterator {
(): FormattedNode<FieldNode> | undefined;
}

export const makeSelectionIterator = (
typename: void | string,
// NOTE: Outside of this file, we expect `_defer` to always be reset to `false`
export function makeSelectionIterator(
typename: undefined | string,
entityKey: string,
_defer: false,
_optional: undefined,
selectionSet: FormattedNode<SelectionSet>,
ctx: Context
): SelectionIterator;
// NOTE: Inside this file we expect the state to be recursively passed on
export function makeSelectionIterator(
typename: undefined | string,
entityKey: string,
_defer: boolean,
_optional: undefined | boolean,
selectionSet: FormattedNode<SelectionSet>,
ctx: Context
): SelectionIterator;

export function makeSelectionIterator(
typename: undefined | string,
entityKey: string,
defer: boolean,
optional: boolean | undefined,
_defer: boolean,
_optional: boolean | undefined,
selectionSet: FormattedNode<SelectionSet>,
ctx: Context
): SelectionIterator => {
): SelectionIterator {
let child: SelectionIterator | void;
let index = 0;

return function next() {
let node: FormattedNode<FieldNode> | undefined;
while (child || index < selectionSet.length) {
node = undefined;
deferRef = defer;
optionalRef = optional;
deferRef = _defer;
optionalRef = _optional;
if (child) {
if ((node = child())) {
return node;
Expand Down Expand Up @@ -212,13 +229,14 @@ export const makeSelectionIterator = (
if (isMatching) {
if (process.env.NODE_ENV !== 'production')
pushDebugNode(typename, fragment);

const isFragmentOptional = isOptional(select);
child = makeSelectionIterator(
typename,
entityKey,
defer || isDeferred(select, ctx.variables),
isFragmentOptional,
_defer || isDeferred(select, ctx.variables),
isFragmentOptional !== undefined
? isFragmentOptional
: _optional,
getSelectionSet(fragment),
ctx
);
Expand All @@ -230,7 +248,7 @@ export const makeSelectionIterator = (
}
}
};
};
}

export const ensureData = (x: DataField): Data | NullArray<Data> | null =>
x == null ? null : (x as Data | NullArray<Data>);
Expand Down
2 changes: 1 addition & 1 deletion exchanges/graphcache/src/operations/write.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ const writeSelection = (
const iterate = makeSelectionIterator(
typename,
entityKey || typename,
deferRef,
false,
undefined,
select,
ctx
Expand Down

0 comments on commit e9b476b

Please sign in to comment.