Skip to content

Commit

Permalink
Optimize shouldInclude for common case of no directives.
Browse files Browse the repository at this point in the history
Since shouldInclude gets called for every single field in any read or
write operation, it's important that it takes any available shortcuts to
handle the common case (no directives) as cheaply as possible.
  • Loading branch information
benjamn committed Feb 15, 2020
1 parent d6edbae commit db1a73d
Showing 1 changed file with 41 additions and 30 deletions.
71 changes: 41 additions & 30 deletions src/utilities/graphql/directives.ts
Expand Up @@ -19,15 +19,18 @@ export type DirectiveInfo = {
};

export function shouldInclude(
selection: SelectionNode,
variables: { [name: string]: any } = {},
{ directives }: SelectionNode,
variables?: Record<string, any>,
): boolean {
if (!directives || !directives.length) {
return true;
}
return getInclusionDirectives(
selection.directives,
directives
).every(({ directive, ifArgument }) => {
let evaledValue: boolean = false;
if (ifArgument.value.kind === 'Variable') {
evaledValue = variables[(ifArgument.value as VariableNode).name.value];
evaledValue = variables && variables[(ifArgument.value as VariableNode).name.value];
invariant(
evaledValue !== void 0,
`Invalid variable referenced in @${directive.name.value} directive.`,
Expand Down Expand Up @@ -77,31 +80,39 @@ function isInclusionDirective({ name: { value } }: DirectiveNode): boolean {
export function getInclusionDirectives(
directives: ReadonlyArray<DirectiveNode>,
): InclusionDirectives {
return directives ? directives.filter(isInclusionDirective).map(directive => {
const directiveArguments = directive.arguments;
const directiveName = directive.name.value;

invariant(
directiveArguments && directiveArguments.length === 1,
`Incorrect number of arguments for the @${directiveName} directive.`,
);

const ifArgument = directiveArguments[0];
invariant(
ifArgument.name && ifArgument.name.value === 'if',
`Invalid argument for the @${directiveName} directive.`,
);

const ifValue: ValueNode = ifArgument.value;

// means it has to be a variable value if this is a valid @skip or @include directive
invariant(
ifValue &&
(ifValue.kind === 'Variable' || ifValue.kind === 'BooleanValue'),
`Argument for the @${directiveName} directive must be a variable or a boolean value.`,
);

return { directive, ifArgument };
}) : [];
const result: InclusionDirectives = [];

if (directives && directives.length) {
directives.forEach(directive => {
if (!isInclusionDirective(directive)) return;

const directiveArguments = directive.arguments;
const directiveName = directive.name.value;

invariant(
directiveArguments && directiveArguments.length === 1,
`Incorrect number of arguments for the @${directiveName} directive.`,
);

const ifArgument = directiveArguments[0];
invariant(
ifArgument.name && ifArgument.name.value === 'if',
`Invalid argument for the @${directiveName} directive.`,
);

const ifValue: ValueNode = ifArgument.value;

// means it has to be a variable value if this is a valid @skip or @include directive
invariant(
ifValue &&
(ifValue.kind === 'Variable' || ifValue.kind === 'BooleanValue'),
`Argument for the @${directiveName} directive must be a variable or a boolean value.`,
);

result.push({ directive, ifArgument });
});
}

return result;
}

0 comments on commit db1a73d

Please sign in to comment.