Skip to content

Commit

Permalink
chore: Disable @defer support (#122)
Browse files Browse the repository at this point in the history
  • Loading branch information
calvincestari authored Nov 2, 2023
1 parent f854ccf commit eb70a4a
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 270 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
import {
compileDocument,
// compileDocument,
parseOperationDocument,
loadSchemaFromSources,
validateDocument,
} from "../index"
import {
CompilationResult
} from "../compiler/index"
import {
Field,
FragmentSpread,
InlineFragment
} from "../compiler/ir"
import {
Source,
GraphQLSchema,
Expand Down Expand Up @@ -39,135 +31,13 @@ describe("given schema", () => {

const schema: GraphQLSchema = loadSchemaFromSources([new Source(schemaSDL, "Test Schema", { line: 1, column: 1 })]);

// Compilation Tests
// Disabling Tests

describe("query has inline fragment with @defer directive", () => {
const documentString: string = `
query Test($a: Boolean!) {
allAnimals {
... on Animal @defer {
species
}
}
}
`;

const document: DocumentNode = parseOperationDocument(
new Source(documentString, "Test Query", { line: 1, column: 1 })
);

it("should compile inline fragment with directive", () => {
const compilationResult: CompilationResult = compileDocument(schema, document, false, emptyValidationOptions);
const operation = compilationResult.operations[0];
const allAnimals = operation.selectionSet.selections[0] as Field;
const inlineFragment = allAnimals?.selectionSet?.selections?.[0] as InlineFragment;

expect(inlineFragment.directives).toHaveLength(1);

expect(inlineFragment.directives?.[0].name).toEqual("defer");
});
});

describe("query has inline fragment with @defer directive with arguments", () => {
const documentString: string = `
query Test($a: Boolean!) {
allAnimals {
... on Animal @defer(if: true, label: "species") {
species
}
}
}
`;

const document: DocumentNode = parseOperationDocument(
new Source(documentString, "Test Query", { line: 1, column: 1 })
);

it("should compile inline fragment with directive and arguments", () => {
const compilationResult: CompilationResult = compileDocument(schema, document, false, emptyValidationOptions);
const operation = compilationResult.operations[0];
const allAnimals = operation.selectionSet.selections[0] as Field;
const inlineFragment = allAnimals?.selectionSet?.selections?.[0] as InlineFragment;

expect(inlineFragment.directives).toHaveLength(1);

expect(inlineFragment.directives?.[0].name).toEqual("defer");

expect(inlineFragment.directives?.[0].arguments).toHaveLength(2);
expect(inlineFragment.directives?.[0].arguments?.[0].name).toEqual("if");
expect(inlineFragment.directives?.[0].arguments?.[1].name).toEqual("label");
});
});

describe("query has fragment spread with @defer directive", () => {
const documentString: string = `
query Test($a: Boolean!) {
allAnimals {
... SpeciesFragment @defer
}
}
fragment SpeciesFragment on Animal {
species
}
`;

const document: DocumentNode = parseOperationDocument(
new Source(documentString, "Test Query", { line: 1, column: 1 })
);

it("should compile fragment spread with directive", () => {
const compilationResult: CompilationResult = compileDocument(schema, document, false, emptyValidationOptions);
const operation = compilationResult.operations[0];
const allAnimals = operation.selectionSet.selections[0] as Field;
const inlineFragment = allAnimals?.selectionSet?.selections?.[0] as FragmentSpread;

expect(inlineFragment.directives).toHaveLength(1);

expect(inlineFragment.directives?.[0].name).toEqual("defer");
});
});

describe("query has fragment spread with @defer directive with arguments", () => {
const documentString: string = `
query Test($a: Boolean!) {
allAnimals {
... SpeciesFragment @defer(if: true, label: "species")
}
}
fragment SpeciesFragment on Animal {
species
}
`;

const document: DocumentNode = parseOperationDocument(
new Source(documentString, "Test Query", { line: 1, column: 1 })
);

it("should compile fragment spread with directive and arguments", () => {
const compilationResult: CompilationResult = compileDocument(schema, document, false, emptyValidationOptions);
const operation = compilationResult.operations[0];
const allAnimals = operation.selectionSet.selections[0] as Field;
const inlineFragment = allAnimals?.selectionSet?.selections?.[0] as FragmentSpread;

expect(inlineFragment.directives).toHaveLength(1);

expect(inlineFragment.directives?.[0].name).toEqual("defer");

expect(inlineFragment.directives?.[0].arguments).toHaveLength(2);
expect(inlineFragment.directives?.[0].arguments?.[0].name).toEqual("if");
expect(inlineFragment.directives?.[0].arguments?.[1].name).toEqual("label");
});
});

// Validation Tests

describe("query has inline fragment with @defer directive and no type condition", () => {
const documentString: string = `
query Test {
allAnimals {
... @defer(label: "custom") {
... on Animal @defer {
species
}
}
Expand All @@ -183,133 +53,36 @@ describe("given schema", () => {

expect(validationErrors).toHaveLength(1)
expect(validationErrors[0].message).toEqual(
"Apollo does not support deferred inline fragments without a type condition. Please add a type condition to this inline fragment."
"@defer support is disabled until the implementation is complete."
)
});
});

describe("query has inline fragment with @defer directive and no label argument", () => {
const documentString: string = `
query Test {
allAnimals {
... on Dog @defer {
species
}
}
}
`;

const document: DocumentNode = parseOperationDocument(
new Source(documentString, "Test Query", { line: 1, column: 1 })
);

it("should fail validation", () => {
const validationErrors: readonly GraphQLError[] = validateDocument(schema, document, emptyValidationOptions)

expect(validationErrors).toHaveLength(1)
expect(validationErrors[0].message).toEqual(
"Apollo does not support deferred inline fragments without a 'label' argument. Please add a 'label' argument to the @defer directive on this inline fragment."
)
})
})

describe("query has fragment spread with @defer directive and no label argument", () => {
const documentString: string = `
query Test {
allAnimals {
...DogFragment @defer
}
}
fragment DogFragment on Dog {
species
}
`;

const document: DocumentNode = parseOperationDocument(
new Source(documentString, "Test Query", { line: 1, column: 1 })
);

it("should pass validation", () => {
const validationErrors: readonly GraphQLError[] = validateDocument(schema, document, emptyValidationOptions)

expect(validationErrors).toHaveLength(0)
})
})

describe("query has fragment spread, with @defer directive and if argument and no label argument on fragment inner type condition", () => {
const documentString: string = `
query Test {
allAnimals {
...AnimalFragment
}
}
fragment AnimalFragment on Animal {
... on Dog @defer(if: true) {
species
}
}
`;

const document: DocumentNode = parseOperationDocument(
new Source(documentString, "Test Query", { line: 1, column: 1 })
);

it("should fail validation", () => {
const validationErrors: readonly GraphQLError[] = validateDocument(schema, document, emptyValidationOptions)

expect(validationErrors).toHaveLength(1)
expect(validationErrors[0].message).toEqual(
"Apollo does not support deferred inline fragments without a 'label' argument. Please add a 'label' argument to the @defer directive on this inline fragment."
)
})
})

describe("query has inline fragment with @defer directive and label argument", () => {
const documentString: string = `
query Test {
allAnimals {
... on Dog @defer(label: "custom") {
species
}
}
}
`;

const document: DocumentNode = parseOperationDocument(
new Source(documentString, "Test Query", { line: 1, column: 1 })
);

it("should pass validation", () => {
const validationErrors: readonly GraphQLError[] = validateDocument(schema, document, emptyValidationOptions)

expect(validationErrors).toHaveLength(0)
})
})

describe("query has fragment spread with @defer directive and label argument", () => {
const documentString: string = `
query Test {
allAnimals {
...AnimalFragment @defer(label: "custom")
}
describe("query has fragment spread with @defer directive", () => {
const documentString: string = `
query Test {
allAnimals {
... SpeciesFragment @defer
}
}
fragment AnimalFragment on Animal {
species
}
`;
fragment SpeciesFragment on Animal {
species
}
`;

const document: DocumentNode = parseOperationDocument(
new Source(documentString, "Test Query", { line: 1, column: 1 })
);
const document: DocumentNode = parseOperationDocument(
new Source(documentString, "Test Query", { line: 1, column: 1 })
);

it("should pass validation", () => {
const validationErrors: readonly GraphQLError[] = validateDocument(schema, document, emptyValidationOptions)
it("should fail validation", () => {
const validationErrors: readonly GraphQLError[] = validateDocument(schema, document, emptyValidationOptions)

expect(validationErrors).toHaveLength(0)
})
})
expect(validationErrors).toHaveLength(1)
expect(validationErrors[0].message).toEqual(
"@defer support is disabled until the implementation is complete."
)
});
});

});
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
VariableDefinitionNode,
InlineFragmentNode,
GraphQLDeferDirective,
FragmentSpreadNode,
} from "graphql";

const specifiedRulesToBeRemoved: [ValidationRule] = [NoUnusedFragmentsRule];
Expand All @@ -31,8 +32,7 @@ export function defaultValidationRules(options: ValidationOptions): ValidationRu
return [
NoAnonymousQueries,
NoTypenameAlias,
DeferredInlineFragmentNoTypeCondition,
DeferredInlineFragmentMissingLabelArgument,
DisallowDeferDirective,
...(disallowedFieldNamesRule ? [disallowedFieldNamesRule] : []),
...(disallowedInputParameterNamesRule ? [disallowedInputParameterNamesRule] : []),
...specifiedRules.filter((rule) => !specifiedRulesToBeRemoved.includes(rule)),
Expand Down Expand Up @@ -69,36 +69,29 @@ export function NoTypenameAlias(context: ValidationContext) {
};
}

export function DeferredInlineFragmentNoTypeCondition(context: ValidationContext) {
export function DisallowDeferDirective(context: ValidationContext) {
return {
InlineFragment(node: InlineFragmentNode) {
if (node.directives) {
for (const directive of node.directives) {
if (directive.name.value == GraphQLDeferDirective.name && node.typeCondition == undefined) {
if (directive.name.value == GraphQLDeferDirective.name) {
context.reportError(
new GraphQLError(
"Apollo does not support deferred inline fragments without a type condition. Please add a type condition to this inline fragment.",
"@defer support is disabled until the implementation is complete.",
{ nodes: node }
)
)
}
}
}
},
};
}

export function DeferredInlineFragmentMissingLabelArgument(context: ValidationContext) {
return {
InlineFragment(node: InlineFragmentNode) {
FragmentSpread(node: FragmentSpreadNode) {
if (node.directives) {
for (const directive of node.directives) {
if (directive.name.value == GraphQLDeferDirective.name && !(directive.arguments?.find((element) =>
element.name.value == 'label'
))) {
if (directive.name.value == GraphQLDeferDirective.name) {
context.reportError(
new GraphQLError(
"Apollo does not support deferred inline fragments without a 'label' argument. Please add a 'label' argument to the @defer directive on this inline fragment.",
"@defer support is disabled until the implementation is complete.",
{ nodes: node }
)
)
Expand Down
3 changes: 1 addition & 2 deletions docs/source/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@
"Error Handling": "/fetching/error-handling",
"Type Conditions": "/fetching/type-conditions",
"Custom Scalars": "/custom-scalars",
"Persisted Queries": "/fetching/persisted-queries",
"@defer support (experimental)": "/fetching/defer"
"Persisted Queries": "/fetching/persisted-queries"
},
true
],
Expand Down

0 comments on commit eb70a4a

Please sign in to comment.