Skip to content

Commit

Permalink
fix(utils): prevent race conditions when validating documents (#5795)
Browse files Browse the repository at this point in the history
* fix(utils): prevent race conditions when validating documents

* Changeset

---------

Co-authored-by: Arda TANRIKULU <ardatanrikulu@gmail.com>
  • Loading branch information
shYkiSto and ardatan committed Jan 22, 2024
1 parent 8770be9 commit f85c093
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/twenty-walls-sleep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@graphql-tools/utils': patch
---

prevent race conditions when validating documents
11 changes: 6 additions & 5 deletions packages/utils/src/validate-documents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,20 @@ export function validateGraphQlDocuments(
documents: DocumentNode[],
rules: ValidationRule[] = createDefaultRules(),
) {
const definitionMap = new Map<string, DefinitionNode>();
const definitions = new Set<DefinitionNode>();
const fragmentsDefinitionsMap = new Map<string, DefinitionNode>();
for (const document of documents) {
for (const docDefinition of document.definitions) {
if ('name' in docDefinition && docDefinition.name) {
definitionMap.set(`${docDefinition.kind}_${docDefinition.name.value}`, docDefinition);
if (docDefinition.kind === Kind.FRAGMENT_DEFINITION) {
fragmentsDefinitionsMap.set(docDefinition.name.value, docDefinition);
} else {
definitionMap.set(Date.now().toString(), docDefinition);
definitions.add(docDefinition);
}
}
}
const fullAST: DocumentNode = {
kind: Kind.DOCUMENT,
definitions: Array.from(definitionMap.values()),
definitions: Array.from([...definitions, ...fragmentsDefinitionsMap.values()]),
};
const errors = validate(schema, fullAST, rules);
for (const error of errors) {
Expand Down
56 changes: 56 additions & 0 deletions packages/utils/tests/validate-documents.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,62 @@ describe('validateGraphQlDocuments', () => {
at packages/client/src/pages/search/searchPage.query.graphql:6:15`);
});

it('Should throw a validation error when multiple anonymous queries are present', async () => {
const schema = buildSchema(/* GraphQL */ `
type OtherStuff {
foo: String
}
type Pizzeria {
id: Int
name: String
location: String
}
type Query {
otherStuff: OtherStuff
pizzeria: Pizzeria
}
`);

const result = validateGraphQlDocuments(schema, [
parse(
new Source(
/* GraphQL */ `
query {
pizzeria {
id
name
}
}
`,
'packages/client/src/pages/products/productPage.query.graphql',
),
),
parse(
new Source(
/* GraphQL */ `
query {
otherStuff {
foo
}
}
`,
'packages/client/src/pages/search/searchPage.query.graphql',
),
),
]);

expect(result).toHaveLength(2);
expect(result[0].source?.name).toBe(
'packages/client/src/pages/products/productPage.query.graphql',
);
expect(result[0] instanceof GraphQLError).toBeTruthy();
expect(result[0].message).toBe('This anonymous operation must be the only defined operation.');
expect(result[0].stack).toBe(`This anonymous operation must be the only defined operation.
at packages/client/src/pages/products/productPage.query.graphql:2:13`);
});

it('Should not swallow fragments on operation/fragment name conflict', async () => {
const schema = buildSchema(/* GraphQL */ `
type Query {
Expand Down

0 comments on commit f85c093

Please sign in to comment.