Skip to content

Commit

Permalink
fix(graphcache): Replace default optional/required directive implemen…
Browse files Browse the repository at this point in the history
…tation (#3341)
  • Loading branch information
kitten authored Jul 27, 2023
1 parent 25a34c6 commit 438d75f
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 43 deletions.
5 changes: 5 additions & 0 deletions .changeset/hot-sloths-look.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@urql/exchange-graphcache': patch
---

Replace implementation for `@_optional` and `@_required` with built-in handling inside cache reads to allow `@_optional` to work for nested selection sets.
21 changes: 0 additions & 21 deletions exchanges/graphcache/src/helpers/defaultDirectives.ts

This file was deleted.

41 changes: 22 additions & 19 deletions exchanges/graphcache/src/operations/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,14 +298,13 @@ export const _queryFragment = (
};

function getFieldResolver(
ctx: Context,
node: FormattedNode<FieldNode>,
directives: ReturnType<typeof getDirectives>,
typename: string,
fieldName: string
fieldName: string,
ctx: Context
): Resolver | void {
const resolvers = ctx.store.resolvers[typename];
const fieldResolver = resolvers && resolvers[fieldName];
const directives = getDirectives(node);

let directiveResolver: Resolver | undefined;
for (const name in directives) {
Expand Down Expand Up @@ -398,8 +397,9 @@ const readSelection = (
const fieldName = getName(node);
const fieldArgs = getFieldArguments(node, ctx.variables);
const fieldAlias = getFieldAlias(node);
const directives = getDirectives(node);
const resolver = getFieldResolver(directives, typename, fieldName, ctx);
const fieldKey = keyOfField(fieldName, fieldArgs);
const resolver = getFieldResolver(ctx, node, typename, fieldName);
const key = joinKeys(entityKey, fieldKey);
const fieldValue = InMemoryData.readRecord(entityKey, fieldKey);
const resultValue = result ? result[fieldName] : undefined;
Expand Down Expand Up @@ -513,33 +513,36 @@ const readSelection = (
// Now that dataFieldValue has been retrieved it'll be set on data
// If it's uncached (undefined) but nullable we can continue assembling
// a partial query result
if (dataFieldValue === undefined && deferRef) {
// The field is undelivered and uncached, but is included in a deferred fragment
hasNext = true;
} else if (
if (
!deferRef &&
dataFieldValue === undefined &&
((store.schema && isFieldNullable(store.schema, typename, fieldName)) ||
!!getFieldError(ctx))
(directives.optional ||
!!getFieldError(ctx) ||
(store.schema && isFieldNullable(store.schema, typename, fieldName)))
) {
// The field is uncached or has errored, so it'll be set to null and skipped
ctx.partial = true;
dataFieldValue = null;
} else if (dataFieldValue === undefined) {
// If the field isn't deferred or partial then we have to abort and also reset
// the partial field
ctx.partial = hasPartials;
ctx.__internal.path.pop();
return undefined;
} else if (dataFieldValue === null && directives.required) {
dataFieldValue = undefined;
} else {
// Otherwise continue as usual
hasFields = hasFields || fieldName !== '__typename';
}

// After processing the field, remove the current alias from the path again
ctx.__internal.path.pop();
// Check for any referential changes in the field's value
hasChanged = hasChanged || dataFieldValue !== input[fieldAlias];
if (dataFieldValue !== undefined) output[fieldAlias] = dataFieldValue;
if (dataFieldValue !== undefined) {
output[fieldAlias] = dataFieldValue;
} else if (deferRef) {
hasNext = true;
} else {
// If the field isn't deferred or partial then we have to abort and also reset
// the partial field
ctx.partial = hasPartials;
return undefined;
}
}

ctx.partial = ctx.partial || hasPartials;
Expand Down
4 changes: 1 addition & 3 deletions exchanges/graphcache/src/store/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {
} from '../types';

import { invariant } from '../helpers/help';
import { defaultDirectives } from '../helpers/defaultDirectives';
import { contextRef, ensureLink } from '../operations/shared';
import { _query, _queryFragment } from '../operations/query';
import { _write, _writeFragment } from '../operations/write';
Expand Down Expand Up @@ -63,8 +62,7 @@ export class Store<
if (!opts) opts = {} as C;

this.resolvers = opts.resolvers || {};
this.directives =
{ ...defaultDirectives, ...opts.directives } || defaultDirectives;
this.directives = opts.directives || {};
this.optimisticMutations = opts.optimistic || {};
this.keys = opts.keys || {};

Expand Down

0 comments on commit 438d75f

Please sign in to comment.