Skip to content

Commit

Permalink
Merge pull request #373 from darrellwarde/bugfix/validation-nested-in…
Browse files Browse the repository at this point in the history
…put-types

Filter out nested input types during validation
  • Loading branch information
darrellwarde authored Aug 4, 2021
2 parents 3e0a774 + db51125 commit 581c679
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 30 deletions.
79 changes: 79 additions & 0 deletions packages/graphql/src/schema/validation/validate-document.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,85 @@ describe("validateDocument", () => {
expect(res).toBeUndefined();
});

test("should not throw error on use of internal input types within input types", () => {
const doc = parse(`
type Salary {
salaryId: ID!
amount: Float
currency: String
frequency: String
eligibleForBonus: Boolean
bonusPercentage: Float
salaryReviewDate: DateTime
pays_salary: EmploymentRecord @relationship(type: "PAYS_SALARY", direction: IN)
}
type EmploymentRecord {
employmentRecordId: ID!
pays_salary: [Salary] @relationship(type: "PAYS_SALARY", direction: OUT)
}
input EmpRecord {
employmentRecordId: ID!
salary: SalaryCreateInput
startDate: Date
endDate: Date
}
type Mutation {
mergeSalaries(salaries: [SalaryCreateInput!]): [Salary]
@cypher(
statement: """
UNWIND $salaries as salary
MERGE (s:Salary {salaryId: salary.salaryId})
ON CREATE SET s.amount = salary.amount,
s.currency = salary.currency,
s.frequency = salary.frequency,
s.eligibleForBonus = salary.eligibleForBonus,
s.bonusPercentage = salary.bonusPercentage,
s.salaryReviewDate = salary.salaryReviewDate
ON MATCH SET s.amount = salary.amount,
s.currency = salary.currency,
s.frequency = salary.frequency,
s.eligibleForBonus = salary.eligibleForBonus,
s.bonusPercentage = salary.bonusPercentage,
s.salaryReviewDate = salary.salaryReviewDate
RETURN s
"""
)
mergeEmploymentRecords(employmentRecords: [EmpRecord]): [EmploymentRecord]
@cypher(
statement: """
UNWIND $employmentRecords as employmentRecord
MERGE (er:EmploymentRecord {
employmentRecordId: employmentRecord.employmentRecordId
})
MERGE (s:Salary {salaryId: employmentRecord.salary.salaryId})
ON CREATE SET s.amount = employmentRecord.salary.amount,
s.currency = employmentRecord.salary.currency,
s.frequency = employmentRecord.salary.frequency,
s.eligibleForBonus = employmentRecord.salary.eligibleForBonus,
s.bonusPercentage = employmentRecord.salary.bonusPercentage,
s.salaryReviewDate = employmentRecord.salary.salaryReviewDate
ON MATCH SET s.amount = employmentRecord.salary.amount,
s.currency = employmentRecord.salary.currency,
s.frequency = employmentRecord.salary.frequency,
s.eligibleForBonus = employmentRecord.salary.eligibleForBonus,
s.bonusPercentage = employmentRecord.salary.bonusPercentage,
s.salaryReviewDate = employmentRecord.salary.salaryReviewDate
MERGE (er)-[:PAYS_SALARY]->(s)
RETURN er
"""
)
}
`);

const res = validateDocument(doc);
expect(res).toBeUndefined();
});

describe("Github Issue 158", () => {
test("should not throw error on validation of schema", () => {
const doc = parse(`
Expand Down
75 changes: 45 additions & 30 deletions packages/graphql/src/schema/validation/validate-document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@ import {
extendSchema,
validateSchema,
ObjectTypeDefinitionNode,
InputValueDefinitionNode,
} from "graphql";
import * as scalars from "../scalars";
import * as enums from "./enums";
import * as directives from "./directives";
import * as point from "../point";

function filterDocument(document: DocumentNode) {
function filterDocument(document: DocumentNode): DocumentNode {
const nodeNames = document.definitions
.filter((definition) => {
if (definition.kind === "ObjectTypeDefinition") {
Expand All @@ -42,40 +43,54 @@ function filterDocument(document: DocumentNode) {
})
.map((definition) => (definition as ObjectTypeDefinitionNode).name.value);

const filterInputTypes = (fields: readonly InputValueDefinitionNode[] | undefined) => {
return fields?.filter((f) => {
const getArgumentType = (type) => {
if (["NonNullType", "ListType"].includes(type.kind)) {
return getArgumentType(type.type);
}
return type.name.value;
};
const type = getArgumentType(f.type);
const match = /(?<nodeName>.+)(?:CreateInput|Sort|UpdateInput|Where)/gm.exec(type);
if (match?.groups?.nodeName) {
if (nodeNames.includes(match.groups.nodeName)) {
return false;
}
}
return true;
});
};

return {
...document,
definitions: document.definitions.reduce((res: DefinitionNode[], def) => {
if (def.kind !== "ObjectTypeDefinition" && def.kind !== "InterfaceTypeDefinition") {
return [...res, def];
if (def.kind === "InputObjectTypeDefinition") {
return [
...res,
{
...def,
fields: filterInputTypes(def.fields),
},
];
}

if (def.kind === "ObjectTypeDefinition" || def.kind === "InterfaceTypeDefinition") {
return [
...res,
{
...def,
directives: def.directives?.filter((x) => !["auth"].includes(x.name.value)),
fields: def.fields?.map((f) => ({
...f,
arguments: filterInputTypes(f.arguments),
directives: f.directives?.filter((x) => !["auth"].includes(x.name.value)),
})),
},
];
}

return [
...res,
{
...def,
directives: def.directives?.filter((x) => !["auth"].includes(x.name.value)),
fields: def.fields?.map((f) => ({
...f,
arguments: f.arguments?.filter((argument) => {
const getArgumentType = (type) => {
if (["NonNullType", "ListType"].includes(type.kind)) {
return getArgumentType(type.type);
}
return type.name.value;
};
const type = getArgumentType(argument.type);
const match = /(?<nodeName>.+)(?:CreateInput|Sort|UpdateInput|Where)/gm.exec(type);
if (match?.groups?.nodeName) {
if (nodeNames.includes(match.groups.nodeName)) {
return false;
}
}
return true;
}),
directives: f.directives?.filter((x) => !["auth"].includes(x.name.value)),
})),
},
];
return [...res, def];
}, []),
};
}
Expand Down

0 comments on commit 581c679

Please sign in to comment.