Skip to content

Commit 1480f7a

Browse files
Merge pull request #4867 from MacondoExpress/fix-4831
Bug-fix 4831
2 parents 44c6f7c + 05a34ea commit 1480f7a

File tree

4 files changed

+496
-3
lines changed

4 files changed

+496
-3
lines changed

.changeset/six-snails-sell.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@neo4j/graphql": patch
3+
---
4+
5+
Fixed bug that caused an empty string and false boolean argument being evaluated as `NULL` when passed as an argument of a `@cypher` field.

packages/graphql/src/translate/queryAST/utils/replace-arguments-in-statement.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ export function replaceArgumentsInStatement({
3333
let cypherStatement = statement;
3434
definedArguments.forEach((arg) => {
3535
const value = rawArguments[arg.name];
36-
if (value) {
36+
if (value === undefined || value === null) {
37+
cypherStatement = cypherStatement.replaceAll(`$${arg.name}`, "NULL");
38+
} else {
3739
const paramName = new Cypher.Param(value).getCypher(env);
3840
cypherStatement = cypherStatement.replaceAll(`$${arg.name}`, paramName);
39-
} else {
40-
cypherStatement = cypherStatement.replaceAll(`$${arg.name}`, "NULL");
4141
}
4242
});
4343

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
import type { GraphQLSchema } from "graphql";
21+
import { graphql } from "graphql";
22+
import type { Driver } from "neo4j-driver";
23+
import { Neo4jGraphQL } from "../../../src";
24+
import { cleanNodesUsingSession } from "../../utils/clean-nodes";
25+
import { UniqueType } from "../../utils/graphql-types";
26+
import Neo4jHelper from "../neo4j";
27+
28+
describe("https://github.com/neo4j/graphql/issues/4831", () => {
29+
let schema: GraphQLSchema;
30+
let driver: Driver;
31+
let neo4j: Neo4jHelper;
32+
let Test: UniqueType;
33+
34+
async function graphqlQuery(query: string) {
35+
return graphql({
36+
schema,
37+
source: query,
38+
contextValue: neo4j.getContextValues(),
39+
});
40+
}
41+
42+
beforeAll(async () => {
43+
neo4j = new Neo4jHelper();
44+
driver = await neo4j.getDriver();
45+
46+
Test = new UniqueType("Test");
47+
const typeDefs = /* GraphQL */ `
48+
type ${Test} {
49+
testBoolean(value: Boolean): Boolean @cypher(statement: "RETURN $value as value", columnName: "value")
50+
testString(value: String): String @cypher(statement: "RETURN $value as value", columnName: "value")
51+
}
52+
`;
53+
54+
const neo4jGraphQL = new Neo4jGraphQL({
55+
typeDefs,
56+
features: {},
57+
});
58+
schema = await neo4jGraphQL.getSchema();
59+
await neo4j.run(`CREATE (:${Test.name})`);
60+
});
61+
62+
afterAll(async () => {
63+
const session = await neo4j.getSession();
64+
await cleanNodesUsingSession(session, [Test]);
65+
await driver.close();
66+
});
67+
68+
describe("Boolean", () => {
69+
test("the parameter should be false when the cypher argument is false", async () => {
70+
const query = /* GraphQL */ `
71+
query ExampleQuery {
72+
${Test.plural} {
73+
testBoolean(value: false)
74+
}
75+
}
76+
`;
77+
78+
const queryResults = await graphqlQuery(query);
79+
expect(queryResults.errors).toBeUndefined();
80+
expect(queryResults.data).toEqual({
81+
[Test.plural]: [{ testBoolean: false }],
82+
});
83+
});
84+
85+
test("the parameter should be true when the cypher argument is true", async () => {
86+
const query = /* GraphQL */ `
87+
query ExampleQuery {
88+
${Test.plural} {
89+
testBoolean(value: true)
90+
}
91+
}
92+
`;
93+
94+
const queryResults = await graphqlQuery(query);
95+
expect(queryResults.errors).toBeUndefined();
96+
expect(queryResults.data).toEqual({
97+
[Test.plural]: [{ testBoolean: true }],
98+
});
99+
});
100+
101+
test("the parameter should be NULL when the cypher argument is not passed", async () => {
102+
const query = /* GraphQL */ `
103+
query ExampleQuery {
104+
${Test.plural} {
105+
testBoolean
106+
}
107+
}
108+
`;
109+
110+
const queryResults = await graphqlQuery(query);
111+
expect(queryResults.errors).toBeUndefined();
112+
expect(queryResults.data).toEqual({
113+
[Test.plural]: [{ testBoolean: null }],
114+
});
115+
});
116+
117+
test("the parameter should be NULL when the cypher argument passed is NULL", async () => {
118+
const query = /* GraphQL */ `
119+
query ExampleQuery {
120+
${Test.plural} {
121+
testBoolean(value: null)
122+
}
123+
}
124+
`;
125+
126+
const queryResults = await graphqlQuery(query);
127+
expect(queryResults.errors).toBeUndefined();
128+
expect(queryResults.data).toEqual({
129+
[Test.plural]: [{ testBoolean: null }],
130+
});
131+
});
132+
});
133+
134+
describe("String", () => {
135+
test("the parameter should be an empty string when the cypher argument is an empty string", async () => {
136+
const query = /* GraphQL */ `
137+
query ExampleQuery {
138+
${Test.plural} {
139+
testString(value: "")
140+
}
141+
}
142+
`;
143+
144+
const queryResults = await graphqlQuery(query);
145+
expect(queryResults.errors).toBeUndefined();
146+
expect(queryResults.data).toEqual({
147+
[Test.plural]: [{ testString: "" }],
148+
});
149+
});
150+
151+
test("the parameter should be 'some-string' when the cypher argument is 'some-string'", async () => {
152+
const query = /* GraphQL */ `
153+
query ExampleQuery {
154+
${Test.plural} {
155+
testString(value: "some-string")
156+
}
157+
}
158+
`;
159+
const queryResults = await graphqlQuery(query);
160+
expect(queryResults.errors).toBeUndefined();
161+
expect(queryResults.data).toEqual({
162+
[Test.plural]: [{ testString: "some-string" }],
163+
});
164+
});
165+
166+
test("the parameter should be NULL when the cypher argument is not passed", async () => {
167+
const query = /* GraphQL */ `
168+
query ExampleQuery {
169+
${Test.plural} {
170+
testString
171+
}
172+
}
173+
`;
174+
const queryResults = await graphqlQuery(query);
175+
expect(queryResults.errors).toBeUndefined();
176+
expect(queryResults.data).toEqual({
177+
[Test.plural]: [{ testString: null }],
178+
});
179+
});
180+
181+
test("the parameter should be NULL when the cypher argument passed is NULL", async () => {
182+
const query = /* GraphQL */ `
183+
query ExampleQuery {
184+
${Test.plural} {
185+
testString(value: null)
186+
}
187+
}
188+
`;
189+
const queryResults = await graphqlQuery(query);
190+
expect(queryResults.errors).toBeUndefined();
191+
expect(queryResults.data).toEqual({
192+
[Test.plural]: [{ testString: null }],
193+
});
194+
});
195+
});
196+
});

0 commit comments

Comments
 (0)