Skip to content

Commit

Permalink
Remove _emptyInput from input in resolveTree
Browse files Browse the repository at this point in the history
  • Loading branch information
angrykoala committed Mar 14, 2024
1 parent 359d206 commit 8eb952c
Show file tree
Hide file tree
Showing 4 changed files with 282 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/gorgeous-llamas-hope.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@neo4j/graphql": patch
---

Ignores \_emptyField from input arguments
8 changes: 6 additions & 2 deletions packages/graphql/src/utils/get-neo4j-resolve-tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@

import type {
GraphQLField,
GraphQLInputType,
GraphQLInterfaceType,
GraphQLList,
GraphQLNamedType,
GraphQLNonNull,
GraphQLObjectType,
GraphQLResolveInfo,
GraphQLInputType,
GraphQLList,
GraphQLSchema,
} from "graphql";
import { GraphQLInputObjectType, GraphQLScalarType, Kind } from "graphql";
Expand All @@ -50,6 +50,10 @@ function getNeo4jArgumentValue({ argument, type }: { argument: unknown; type: Gr

if (type instanceof GraphQLInputObjectType) {
return Object.entries(argument as Record<string, unknown>).reduce((res, [key, value]) => {
// Ignore meta field _emptyInput
if (key === "_emptyInput") {
return res;
}
const field = Object.values(type.getFields()).find((f) => f.name === key);

if (!field) {
Expand Down
117 changes: 117 additions & 0 deletions packages/graphql/tests/integration/issues/4838.int.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import type { UniqueType } from "../../utils/graphql-types";
import { TestHelper } from "../utils/tests-helper";

describe("https://github.com/neo4j/graphql/issues/4838", () => {
const testHelper = new TestHelper();

let TestType: UniqueType;
let ParentTest: UniqueType;

beforeEach(async () => {
TestType = testHelper.createUniqueType("TestType");
ParentTest = testHelper.createUniqueType("ParentTest");

const typeDefs = /* GraphQL */ `
type ${TestType} {
test: Boolean! @cypher(statement: "RETURN true AS value", columnName: "value")
}
type ${ParentTest} {
tests: [${TestType}!]! @relationship(type: "REL", direction: OUT,)
}
`;

await testHelper.initNeo4jGraphQL({
typeDefs,
});
});

afterEach(async () => {
await testHelper.close();
});

test("Empty input flag should be ignored on creation", async () => {
const query = /* GraphQL */ `
mutation {
${TestType.operations.create}(input: { _emptyInput: true }) {
${TestType.plural} {
test
}
}
}
`;

const response = await testHelper.executeGraphQL(query);

expect(response.errors).toBeFalsy();

const createdNodeCypherResult = await testHelper.executeCypher(`MATCH(m:${TestType}) RETURN m`);
const createdNode = createdNodeCypherResult.records[0]?.toObject().m;
expect(createdNode.properties).toEqual({});
});

test("Empty input flag should be ignored on nested creation", async () => {
await testHelper.executeCypher(`CREATE(p:${ParentTest})-[:REL]->(:${TestType})`);

const query = /* GraphQL */ `
mutation {
${ParentTest.operations.create}(input: { tests: { create: { node: { _emptyInput: true } } } }) {
${ParentTest.plural} {
tests {
test
}
}
}
}
`;

const response = await testHelper.executeGraphQL(query);

expect(response.errors).toBeFalsy();

const createdNodeCypherResult = await testHelper.executeCypher(`MATCH(m:${TestType}) RETURN m`);
const createdNode = createdNodeCypherResult.records[0]?.toObject().m;
expect(createdNode.properties).toEqual({});
});

test("Empty input flag should be ignored on update", async () => {
await testHelper.executeCypher(`CREATE(p:${TestType})`);

const query = /* GraphQL */ `
mutation {
${TestType.operations.update}(update: { _emptyInput: true }, where: {}) {
${TestType.plural} {
test
}
}
}
`;

const response = await testHelper.executeGraphQL(query);

expect(response.errors).toBeFalsy();

const createdNodeCypherResult = await testHelper.executeCypher(`MATCH(m:${TestType}) RETURN m`);
const createdNode = createdNodeCypherResult.records[0]?.toObject().m;
expect(createdNode.properties).toEqual({});
});
});
154 changes: 154 additions & 0 deletions packages/graphql/tests/tck/issues/4838.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Neo4jGraphQL } from "../../../src";
import { formatCypher, formatParams, translateQuery } from "../utils/tck-test-utils";

describe("https://github.com/neo4j/graphql/issues/4838", () => {
let typeDefs: string;
let neoSchema: Neo4jGraphQL;

beforeAll(() => {
typeDefs = /* GraphQL */ `
type Test {
test: Boolean! @cypher(statement: "RETURN true AS value", columnName: "value")
}
type ParentTest {
tests: [Test!]! @relationship(type: "REL", direction: OUT)
}
`;

neoSchema = new Neo4jGraphQL({
typeDefs,
features: {},
});
});

test("Empty input flag should be ignored on creation", async () => {
const query = /* GraphQL */ `
mutation Mutation {
createTests(input: { _emptyInput: true }) {
tests {
test
}
}
}
`;

const result = await translateQuery(neoSchema, query);

expect(formatCypher(result.cypher)).toMatchInlineSnapshot(`
"UNWIND $create_param0 AS create_var0
CALL {
WITH create_var0
CREATE (create_this1:Test)
RETURN create_this1
}
CALL {
WITH create_this1
CALL {
WITH create_this1
WITH create_this1 AS this
RETURN true AS value
}
WITH value AS create_this2
RETURN create_this2 AS create_var3
}
RETURN collect(create_this1 { test: create_var3 }) AS data"
`);

expect(formatParams(result.params)).toMatchInlineSnapshot(`
"{
\\"create_param0\\": [
{}
],
\\"resolvedCallbacks\\": {}
}"
`);
});

test("Empty input flag should be ignored on nested creation", async () => {
const query = /* GraphQL */ `
mutation {
createParentTests(input: { tests: { create: { node: { _emptyInput: true } } } }) {
parentTests {
tests {
test
}
}
}
}
`;

const result = await translateQuery(neoSchema, query);

expect(formatCypher(result.cypher)).toMatchInlineSnapshot(`
"UNWIND $create_param0 AS create_var0
CALL {
WITH create_var0
CREATE (create_this1:ParentTest)
WITH create_this1, create_var0
CALL {
WITH create_this1, create_var0
UNWIND create_var0.tests.create AS create_var2
WITH create_var2.node AS create_var3, create_var2.edge AS create_var4, create_this1
CREATE (create_this5:Test)
MERGE (create_this1)-[create_this6:REL]->(create_this5)
RETURN collect(NULL) AS create_var7
}
RETURN create_this1
}
CALL {
WITH create_this1
MATCH (create_this1)-[create_this8:REL]->(create_this9:Test)
CALL {
WITH create_this9
CALL {
WITH create_this9
WITH create_this9 AS this
RETURN true AS value
}
WITH value AS create_this10
RETURN create_this10 AS create_var11
}
WITH create_this9 { test: create_var11 } AS create_this9
RETURN collect(create_this9) AS create_var12
}
RETURN collect(create_this1 { tests: create_var12 }) AS data"
`);

expect(formatParams(result.params)).toMatchInlineSnapshot(`
"{
\\"create_param0\\": [
{
\\"tests\\": {
\\"create\\": [
{
\\"node\\": {}
}
]
}
}
],
\\"resolvedCallbacks\\": {}
}"
`);
});
});

0 comments on commit 8eb952c

Please # to comment.