diff --git a/.changeset/hungry-weeks-shout.md b/.changeset/hungry-weeks-shout.md new file mode 100644 index 00000000..ab266fe3 --- /dev/null +++ b/.changeset/hungry-weeks-shout.md @@ -0,0 +1,5 @@ +--- +"@neo4j/cypher-builder": patch +--- + +Output Cypher now follows the official styleguide diff --git a/docs/modules/ROOT/pages/migration-guide-3.adoc b/docs/modules/ROOT/pages/migration-guide-3.adoc index 99f6c230..48d926fd 100644 --- a/docs/modules/ROOT/pages/migration-guide-3.adoc +++ b/docs/modules/ROOT/pages/migration-guide-3.adoc @@ -280,3 +280,36 @@ _After_ const myOperation: Cypher.Expr = Cypher.and() ---- +== Other changes + +=== Change Cypher formatting + +The generated Cypher now follow the best practices recommended by the link:https://neo4j.com/docs/cypher-manual/current/styleguide/[Cypher Styleguide]. + +For example: + +_Before_ +[source, Cypher] +---- +CALL { + CREATE (this0:Movie) + SET + this0.id = "The Matrix" + RETURN this0 +} +RETURN this0 +---- + +_After_ +[source, Cypher] +---- +CALL { + CREATE (this0:Movie) + SET this0.id = 'The Matrix' + RETURN this0 +} +RETURN this0 +---- + +This doesn't have any impact on the behaviour itself, and should not cause any breaking changes on normal usage, but may affect projects +that modify or test the Cypher generated with Cypher Builder. diff --git a/src/clauses/Call.test.ts b/src/clauses/Call.test.ts index c935f4f9..172f7c5b 100644 --- a/src/clauses/Call.test.ts +++ b/src/clauses/Call.test.ts @@ -29,13 +29,12 @@ describe("CypherBuilder Call", () => { .return(movieNode); const queryResult = new Cypher.Call(createQuery).build(); expect(queryResult.cypher).toMatchInlineSnapshot(` - "CALL { - CREATE (this0:Movie) - SET - this0.id = $param0 - RETURN this0 - }" - `); +"CALL { + CREATE (this0:Movie) + SET this0.id = $param0 + RETURN this0 +}" +`); expect(queryResult.params).toMatchInlineSnapshot(` { "param0": "my-id", @@ -55,15 +54,14 @@ describe("CypherBuilder Call", () => { const queryResult = call.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` - "CALL { - CALL { - CREATE (this0:Movie) - SET - this0.id = $param0 - RETURN this0 - } - }" - `); +"CALL { + CALL { + CREATE (this0:Movie) + SET this0.id = $param0 + RETURN this0 + } +}" +`); expect(queryResult.params).toMatchInlineSnapshot(` { "param0": "my-id", @@ -81,13 +79,13 @@ describe("CypherBuilder Call", () => { const clause = new Cypher.Call(matchClause).with("*"); const queryResult = clause.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` - "CALL { - MATCH (this0:Movie) - WHERE $param0 = $param1 - RETURN this0.title AS movie - } - WITH *" - `); +"CALL { + MATCH (this0:Movie) + WHERE $param0 = $param1 + RETURN this0.title AS movie +} +WITH *" +`); expect(queryResult.params).toMatchInlineSnapshot(` { @@ -111,12 +109,11 @@ describe("CypherBuilder Call", () => { const queryResult = clause.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` "CALL { - MATCH (this0:Movie) - WHERE $param0 = $param1 - RETURN this0 + MATCH (this0:Movie) + WHERE $param0 = $param1 + RETURN this0 } -SET - this0.title = $param2 +SET this0.title = $param2 REMOVE this0.title WITH *" `); @@ -140,13 +137,13 @@ WITH *" const clause = new Cypher.Call(matchClause).with(new Cypher.With("*")); const queryResult = clause.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` - "CALL { - MATCH (this0:Movie) - WHERE $param0 = $param1 - RETURN this0.title AS movie - } - WITH *" - `); +"CALL { + MATCH (this0:Movie) + WHERE $param0 = $param1 + RETURN this0.title AS movie +} +WITH *" +`); expect(queryResult.params).toMatchInlineSnapshot(` { @@ -168,13 +165,13 @@ WITH *" const queryResult = clause.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` - "CALL { - MATCH (this0:Movie) - WHERE $param0 = $param1 - RETURN this0.title AS var1 - } - UNWIND var1 AS m" - `); +"CALL { + MATCH (this0:Movie) + WHERE $param0 = $param1 + RETURN this0.title AS var1 +} +UNWIND var1 AS m" +`); expect(queryResult.params).toMatchInlineSnapshot(` { @@ -198,13 +195,13 @@ WITH *" const queryResult = clause.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` - "CALL { - MATCH (this0:Movie) - WHERE $param0 = $param1 - RETURN this0.title AS var1 - } - UNWIND var1 AS m" - `); +"CALL { + MATCH (this0:Movie) + WHERE $param0 = $param1 + RETURN this0.title AS var1 +} +UNWIND var1 AS m" +`); expect(queryResult.params).toMatchInlineSnapshot(` { @@ -226,9 +223,9 @@ WITH *" expect(queryResult.cypher).toMatchInlineSnapshot(` "CALL { - MATCH (this0:Movie) - WHERE this0.title = $param0 - RETURN this0 + MATCH (this0:Movie) + WHERE this0.title = $param0 + RETURN this0 } DELETE this0" `); @@ -251,10 +248,9 @@ DELETE this0" const queryResult = new Cypher.Call(createQuery).return(variable).build(); expect(queryResult.cypher).toMatchInlineSnapshot(` "CALL { - CREATE (this0:Movie) - SET - this0.id = $param0 - RETURN var1 + CREATE (this0:Movie) + SET this0.id = $param0 + RETURN var1 } RETURN var1" `); @@ -284,8 +280,8 @@ RETURN var1" expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0) CALL { - WITH this0 - DETACH DELETE this0 + WITH this0 + DETACH DELETE this0 } IN TRANSACTIONS" `); }); @@ -302,8 +298,8 @@ CALL { expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0) CALL { - WITH this0 - DETACH DELETE this0 + WITH this0 + DETACH DELETE this0 } IN TRANSACTIONS OF 10 ROWS" `); }); @@ -320,8 +316,8 @@ CALL { expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0) CALL { - WITH this0 - DETACH DELETE this0 + WITH this0 + DETACH DELETE this0 } IN TRANSACTIONS ON ERROR FAIL" `); }); @@ -339,8 +335,8 @@ CALL { expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0) CALL { - WITH this0 - DETACH DELETE this0 + WITH this0 + DETACH DELETE this0 } IN TRANSACTIONS ON ERROR RETRY" `); }); @@ -357,8 +353,8 @@ CALL { expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0) CALL { - WITH this0 - DETACH DELETE this0 + WITH this0 + DETACH DELETE this0 } IN TRANSACTIONS ON ERROR RETRY FOR 10 SECONDS" `); }); @@ -375,8 +371,8 @@ CALL { expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0) CALL { - WITH this0 - DETACH DELETE this0 + WITH this0 + DETACH DELETE this0 } IN TRANSACTIONS ON ERROR RETRY THEN CONTINUE" `); }); @@ -394,8 +390,8 @@ CALL { expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0) CALL { - WITH this0 - DETACH DELETE this0 + WITH this0 + DETACH DELETE this0 } IN TRANSACTIONS ON ERROR RETRY FOR 10 SECONDS THEN BREAK" `); }); @@ -412,8 +408,8 @@ CALL { expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0) CALL { - WITH this0 - DETACH DELETE this0 + WITH this0 + DETACH DELETE this0 } IN TRANSACTIONS" `); }); @@ -430,8 +426,8 @@ CALL { expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0) CALL { - WITH this0 - DETACH DELETE this0 + WITH this0 + DETACH DELETE this0 } IN TRANSACTIONS ON ERROR RETRY FOR 0 SECONDS" `); }); @@ -449,8 +445,8 @@ CALL { expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0) CALL { - WITH this0 - DETACH DELETE this0 + WITH this0 + DETACH DELETE this0 } IN TRANSACTIONS ON ERROR CONTINUE" `); }); @@ -471,8 +467,8 @@ CALL { expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0) CALL { - WITH this0 - DETACH DELETE this0 + WITH this0 + DETACH DELETE this0 } IN TRANSACTIONS OF 10 ROWS ON ERROR FAIL" `); }); @@ -492,8 +488,8 @@ CALL { expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0) CALL { - WITH this0 - DETACH DELETE this0 + WITH this0 + DETACH DELETE this0 } IN 3 CONCURRENT TRANSACTIONS" `); }); @@ -515,8 +511,8 @@ CALL { expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0) CALL { - WITH this0 - DETACH DELETE this0 + WITH this0 + DETACH DELETE this0 } IN 5 CONCURRENT TRANSACTIONS OF 10 ROWS ON ERROR FAIL" `); }); @@ -536,8 +532,8 @@ CALL { expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0) CALL { - WITH this0 - DETACH DELETE this0 + WITH this0 + DETACH DELETE this0 } IN 2 CONCURRENT TRANSACTIONS OF 10 ROWS ON ERROR RETRY FOR 5 SECONDS THEN BREAK" `); }); @@ -561,7 +557,7 @@ CALL { "MATCH (this0:Movie) MATCH (this1:Actor) CALL (this0, this1) { - CREATE (this0)-[]->(this1) + CREATE (this0)-[]->(this1) } RETURN this0" `); @@ -580,7 +576,7 @@ RETURN this0" const queryResult = clause.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` "CALL () { - CREATE (this0)-[]->(this1) + CREATE (this0)-[]->(this1) } RETURN this0" `); @@ -604,7 +600,7 @@ RETURN this0" "MATCH (this0:Movie) MATCH (this1:Actor) CALL (*) { - CREATE (this0)-[]->(this1) + CREATE (this0)-[]->(this1) } RETURN this0" `); @@ -622,10 +618,9 @@ RETURN this0" const queryResult = new Cypher.Call(createQuery).optional().build(); expect(queryResult.cypher).toMatchInlineSnapshot(` "OPTIONAL CALL { - CREATE (this0:Movie) - SET - this0.id = $param0 - RETURN this0 + CREATE (this0:Movie) + SET this0.id = $param0 + RETURN this0 }" `); expect(queryResult.params).toMatchInlineSnapshot(` @@ -645,10 +640,9 @@ RETURN this0" const queryResult = new Cypher.OptionalCall(createQuery).build(); expect(queryResult.cypher).toMatchInlineSnapshot(` "OPTIONAL CALL { - CREATE (this0:Movie) - SET - this0.id = $param0 - RETURN this0 + CREATE (this0:Movie) + SET this0.id = $param0 + RETURN this0 }" `); expect(queryResult.params).toMatchInlineSnapshot(` @@ -670,10 +664,9 @@ RETURN this0" const queryResult = new Cypher.Call(createQuery).orderBy(movieNode).skip(10).build(); expect(queryResult.cypher).toMatchInlineSnapshot(` "CALL { - CREATE (this0:Movie) - SET - this0.id = $param0 - RETURN this0 + CREATE (this0:Movie) + SET this0.id = $param0 + RETURN this0 } ORDER BY this0 ASC SKIP 10" diff --git a/src/clauses/Create.test.ts b/src/clauses/Create.test.ts index 1531e300..2e901a44 100644 --- a/src/clauses/Create.test.ts +++ b/src/clauses/Create.test.ts @@ -41,12 +41,12 @@ describe("CypherBuilder Create", () => { const queryResult = createQuery.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` - "CREATE (this0:Movie { test: $param0, id: $param1 }) - SET - this0.title = $param2, - this0.runtime = $param3 - RETURN this0" - `); +"CREATE (this0:Movie { test: $param0, id: $param1 }) +SET + this0.title = $param2, + this0.runtime = $param3 +RETURN this0" +`); expect(queryResult.params).toMatchInlineSnapshot(` { @@ -80,12 +80,12 @@ describe("CypherBuilder Create", () => { const queryResult = createQuery.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` - "CREATE (this0:Movie { id: NULL }) - SET - this0.test = NULL, - this0.nullStr = $param0 - RETURN this0" - `); +"CREATE (this0:Movie { id: NULL }) +SET + this0.test = NULL, + this0.nullStr = $param0 +RETURN this0" +`); expect(queryResult.params).toMatchInlineSnapshot(` { @@ -122,8 +122,8 @@ describe("CypherBuilder Create", () => { expect(queryResult.cypher).toMatchInlineSnapshot(` "CREATE p1 = (this0:Movie { id: NULL }) SET - this0.test = NULL, - this0.nullStr = $param0 + this0.test = NULL, + this0.nullStr = $param0 RETURN this0" `); @@ -187,8 +187,8 @@ RETURN this0" expect(queryResult.cypher).toMatchInlineSnapshot(` "CREATE (this0:Movie { test: $param0, id: $param1 }) SET - this0.title = $param2, - this0.runtime = $param3 + this0.title = $param2, + this0.runtime = $param3 DELETE this0" `); @@ -225,8 +225,8 @@ DELETE this0" expect(queryResult.cypher).toMatchInlineSnapshot(` "CREATE (this0:Movie { test: $param0, id: $param1 }) SET - this0.title = $param2, - this0.runtime = $param3 + this0.title = $param2, + this0.runtime = $param3 DETACH DELETE this0" `); @@ -263,8 +263,8 @@ DETACH DELETE this0" expect(queryResult.cypher).toMatchInlineSnapshot(` "CREATE (this0:Movie { test: $param0, id: $param1 }) SET - this0.title = $param2, - this0.runtime = $param3 + this0.title = $param2, + this0.runtime = $param3 NODETACH DELETE this0" `); @@ -301,8 +301,8 @@ NODETACH DELETE this0" expect(queryResult.cypher).toMatchInlineSnapshot(` "CREATE (this0:Movie { test: $param0, id: $param1 }) SET - this0.title = $param2, - this0.runtime = $param3 + this0.title = $param2, + this0.runtime = $param3 REMOVE this0.title" `); @@ -340,8 +340,8 @@ REMOVE this0.title" expect(queryResult.cypher).toMatchInlineSnapshot(` "CREATE (this0:Movie { test: $param0, id: $param1 }) SET - this0.title = $param2, - this0.runtime = $param3 + this0.title = $param2, + this0.runtime = $param3 CREATE (this1:Actor) RETURN this0" `); @@ -383,8 +383,8 @@ RETURN this0" expect(queryResult.cypher).toMatchInlineSnapshot(` "CREATE (this0:Movie { test: $param0, id: $param1 }) SET - this0.title = $param2, - this0.runtime = $param3 + this0.title = $param2, + this0.runtime = $param3 CREATE (this1:Actor) RETURN this0" `); @@ -425,8 +425,8 @@ RETURN this0" expect(queryResult.cypher).toMatchInlineSnapshot(` "CREATE (this0:Movie { test: $param0, id: $param1 }) SET - this0.title = $param2, - this0.runtime = $param3 + this0.title = $param2, + this0.runtime = $param3 ORDER BY this0.title DESC SKIP 10 LIMIT 1 diff --git a/src/clauses/Finish.test.ts b/src/clauses/Finish.test.ts index 0e93dafb..1964741a 100644 --- a/src/clauses/Finish.test.ts +++ b/src/clauses/Finish.test.ts @@ -38,8 +38,7 @@ describe("CypherBuilder Finish", () => { const queryResult = createQuery.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` "CREATE (this0) -SET - this1.test = $param0 +SET this1.test = $param0 FINISH" `); expect(queryResult.params).toMatchInlineSnapshot(` diff --git a/src/clauses/Foreach.test.ts b/src/clauses/Foreach.test.ts index 416b0ee5..1ef83df9 100644 --- a/src/clauses/Foreach.test.ts +++ b/src/clauses/Foreach.test.ts @@ -34,13 +34,12 @@ describe("Foreach", () => { const queryResult = foreachClause.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` - "FOREACH (var0 IN [1, 2, 3] | - CREATE (this1:Movie) - SET - this1.id = var0 - ) - WITH *" - `); +"FOREACH (var0 IN [1, 2, 3] | + CREATE (this1:Movie) + SET this1.id = var0 +) +WITH *" +`); expect(queryResult.params).toMatchInlineSnapshot(`{}`); }); @@ -63,11 +62,10 @@ describe("Foreach", () => { const queryResult = foreachClause.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` "FOREACH (var0 IN [1, 2, 3] | - CREATE (this1:Movie) + CREATE (this1:Movie) ) REMOVE this1.title -SET - this1.id = var0 +SET this1.id = var0 DELETE this1 WITH *" `); @@ -87,7 +85,7 @@ WITH *" const queryResult = foreachClause.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` "FOREACH (var0 IN [1, 2, 3] | - CREATE (this1:Movie) + CREATE (this1:Movie) ) DETACH DELETE this1 WITH *" diff --git a/src/clauses/LoadCSV.test.ts b/src/clauses/LoadCSV.test.ts index 81949222..d6add772 100644 --- a/src/clauses/LoadCSV.test.ts +++ b/src/clauses/LoadCSV.test.ts @@ -50,7 +50,7 @@ RETURN var0" const queryResult = loadClause.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` "LOAD CSV WITH HEADERS FROM \\"https://data.neo4j.com/bands/artists.csv\\" AS var0 -MERGE (this1 { name: var0.Name }) +MERGE (this1 { name: var0.Name }) RETURN var0" `); diff --git a/src/clauses/Match.test.ts b/src/clauses/Match.test.ts index eade152c..e79970ce 100644 --- a/src/clauses/Match.test.ts +++ b/src/clauses/Match.test.ts @@ -135,7 +135,7 @@ RETURN this0.id" expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH p2 = (this0)-[*]->(this1) FOREACH (var3 IN nodes(p2) | - MERGE (var3)-[]->(this1) + MERGE (var3)-[]->(this1) )" `); @@ -324,10 +324,10 @@ RETURN p3" const queryResult = matchQuery.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` - "MATCH (this0:Movie { test: $param0 }) - WHERE (((this0.id = $param1 AND this0.name = $param2) AND this0.age = $param3) AND this0.value = \\"Another value\\") - RETURN this0" - `); +"MATCH (this0:Movie { test: $param0 }) +WHERE (((this0.id = $param1 AND this0.name = $param2) AND this0.age = $param3) AND this0.value = 'Another value') +RETURN this0" +`); expect(queryResult.params).toMatchInlineSnapshot(` { @@ -576,12 +576,11 @@ RETURN this0" const queryResult = matchQuery.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` - "MATCH (this0:Person) - WHERE this0.name = $param0 - SET - this0.name = $param1 - RETURN this0" - `); +"MATCH (this0:Person) +WHERE this0.name = $param0 +SET this0.name = $param1 +RETURN this0" +`); expect(queryResult.params).toMatchInlineSnapshot(` { @@ -812,7 +811,7 @@ RETURN var1" "MATCH (this0:Movie) MATCH (this1:Actor) CALL (this0, this1) { - CREATE (this0)-[]->(this1) + CREATE (this0)-[]->(this1) } RETURN this0" `); @@ -836,7 +835,7 @@ RETURN this0" "MATCH (this0:Movie) MATCH (this1:Actor) OPTIONAL CALL (this0, this1) { - CREATE (this0)-[]->(this1) + CREATE (this0)-[]->(this1) } RETURN this0" `); diff --git a/src/clauses/Merge.test.ts b/src/clauses/Merge.test.ts index c9a947d9..7cc130ed 100644 --- a/src/clauses/Merge.test.ts +++ b/src/clauses/Merge.test.ts @@ -31,10 +31,9 @@ describe("CypherBuilder Merge", () => { const queryResult = query.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` - "MERGE (this0:MyLabel) - ON CREATE SET - this0.age = $param0" - `); +"MERGE (this0:MyLabel) + ON CREATE SET this0.age = $param0 " +`); expect(queryResult.params).toMatchInlineSnapshot(` { "param0": 23, @@ -55,11 +54,9 @@ describe("CypherBuilder Merge", () => { const queryResult = query.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` -"MERGE (this0:MyLabel) -ON CREATE SET - this0.age = $param1 -SET - this0.age = $param0" +"MERGE (this0:MyLabel) + ON CREATE SET this0.age = $param1 +SET this0.age = $param0" `); expect(queryResult.params).toMatchInlineSnapshot(` { @@ -80,10 +77,9 @@ SET const queryResult = query.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` - "MERGE (this0:MyLabel) - ON CREATE SET - this0.\`$age\` = $param0" - `); +"MERGE (this0:MyLabel) + ON CREATE SET this0.\`$age\` = $param0 " +`); expect(queryResult.params).toMatchInlineSnapshot(` { "param0": 23, @@ -107,10 +103,9 @@ SET const queryResult = query.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` - "MERGE (this0:MyLabel { test: $param0 }) - ON CREATE SET - this0.age = $param1" - `); +"MERGE (this0:MyLabel { test: $param0 }) + ON CREATE SET this0.age = $param1 " +`); expect(queryResult.params).toMatchInlineSnapshot(` { "param0": "test", @@ -135,13 +130,13 @@ SET const queryResult = query.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` - "MERGE (this0)-[this1]->(this2) - ON CREATE SET - this0.age = $param0, - this0.name = $param1, - this1.screentime = $param2 - RETURN this0.title AS movie" - `); +"MERGE (this0)-[this1]->(this2) + ON CREATE SET + this0.age = $param0, + this0.name = $param1, + this1.screentime = $param2 +RETURN this0.title AS movie" +`); expect(queryResult.params).toMatchInlineSnapshot(` { "param0": 23, @@ -168,11 +163,11 @@ SET const queryResult = query.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` -"MERGE p3 = (this0)-[this1]->(this2) -ON CREATE SET +"MERGE p3 = (this0)-[this1]->(this2) + ON CREATE SET this0.age = $param0, this0.name = $param1, - this1.screentime = $param2 + this1.screentime = $param2 RETURN this0.title AS movie" `); expect(queryResult.params).toMatchInlineSnapshot(` @@ -197,7 +192,7 @@ RETURN this0.title AS movie" const queryResult = query.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` -"MERGE (this0:MyLabel) +"MERGE (this0:MyLabel) REMOVE this0.title DELETE this0" `); @@ -220,8 +215,8 @@ DELETE this0" const queryResult = query.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` -"MERGE (this0:MyLabel) -MERGE (this1:MyOtherLabel)" +"MERGE (this0:MyLabel) +MERGE (this1:MyOtherLabel) " `); expect(queryResult.params).toMatchInlineSnapshot(`{}`); }); @@ -244,8 +239,8 @@ MERGE (this1:MyOtherLabel)" const queryResult = query.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` -"MERGE (this0:MyLabel) -MERGE (this1:MyOtherLabel)" +"MERGE (this0:MyLabel) +MERGE (this1:MyOtherLabel) " `); expect(queryResult.params).toMatchInlineSnapshot(`{}`); }); @@ -261,10 +256,9 @@ MERGE (this1:MyOtherLabel)" const queryResult = query.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` - "MERGE (this0:MyLabel) - ON MATCH SET - this0.age = $param0" - `); +"MERGE (this0:MyLabel) + ON MATCH SET this0.age = $param0" +`); expect(queryResult.params).toMatchInlineSnapshot(` { "param0": 23, @@ -286,11 +280,9 @@ MERGE (this1:MyOtherLabel)" const queryResult = query.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` -"MERGE (this0:MyLabel) -ON MATCH SET - this0.count = (this0.count + 1) -ON CREATE SET - this0.count = 1" +"MERGE (this0:MyLabel) + ON CREATE SET this0.count = 1 + ON MATCH SET this0.count = (this0.count + 1)" `); expect(queryResult.params).toMatchInlineSnapshot(`{}`); }); @@ -308,9 +300,8 @@ ON CREATE SET const queryResult = query.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` -"MERGE (this0:MyLabel) -ON CREATE SET - this0.age = $param0 +"MERGE (this0:MyLabel) + ON CREATE SET this0.age = $param0 FINISH" `); expect(queryResult.params).toMatchInlineSnapshot(` @@ -333,9 +324,8 @@ FINISH" const queryResult = query.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` -"MERGE (this0:MyLabel) -ON CREATE SET - this0.age = $param0 +"MERGE (this0:MyLabel) + ON CREATE SET this0.age = $param0 ORDER BY this0.age ASC" `); expect(queryResult.params).toMatchInlineSnapshot(` diff --git a/src/clauses/Merge.ts b/src/clauses/Merge.ts index f36af287..0e434c9f 100644 --- a/src/clauses/Merge.ts +++ b/src/clauses/Merge.ts @@ -21,6 +21,7 @@ import type { Pattern } from ".."; import type { CypherEnvironment } from "../Environment"; import type { PathAssign } from "../pattern/PathAssign"; import { compileCypherIfExists } from "../utils/compile-cypher-if-exists"; +import { padBlock } from "../utils/pad-block"; import { Clause } from "./Clause"; import { WithCreate } from "./mixins/clauses/WithCreate"; import { WithFinish } from "./mixins/clauses/WithFinish"; @@ -89,6 +90,6 @@ export class Merge extends Clause { const orderCypher = compileCypherIfExists(this.orderByStatement, env, { prefix: "\n" }); const nextClause = this.compileNextClause(env); - return `${mergeStr}${onMatchCypher}${onCreateCypher}${setCypher}${deleteCypher}${orderCypher}${nextClause}`; + return `${mergeStr}${padBlock(onCreateCypher)}${padBlock(onMatchCypher)}${setCypher}${deleteCypher}${orderCypher}${nextClause}`; } } diff --git a/src/clauses/Unwind.test.ts b/src/clauses/Unwind.test.ts index 3c94595b..0b376992 100644 --- a/src/clauses/Unwind.test.ts +++ b/src/clauses/Unwind.test.ts @@ -26,9 +26,7 @@ describe("CypherBuilder Unwind", () => { const moviesList = new Cypher.List([matrix, matrix2]); const unwindQuery = new Cypher.Unwind([moviesList, "batch"]); const queryResult = unwindQuery.build(); - expect(queryResult.cypher).toMatchInlineSnapshot( - `"UNWIND [{ title: \\"Matrix\\" }, { title: \\"Matrix 2\\" }] AS batch"` - ); + expect(queryResult.cypher).toMatchInlineSnapshot(`"UNWIND [{title: 'Matrix'}, {title: 'Matrix 2'}] AS batch"`); expect(queryResult.params).toMatchInlineSnapshot(`{}`); }); @@ -52,8 +50,7 @@ describe("CypherBuilder Unwind", () => { const queryResult = unwindQuery.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` "UNWIND var0 AS var1 -SET - var1.title = $param0 +SET var1.title = $param0 REMOVE var1.title DELETE var1" `); @@ -111,7 +108,7 @@ UNWIND var1 AS var2" const unwindQuery = new Cypher.Unwind([moviesList, batch]).orderBy([batch.property("title", "DESC")]).limit(10); const queryResult = unwindQuery.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` -"UNWIND [{ title: \\"Matrix\\" }, { title: \\"Matrix 2\\" }] AS var0 +"UNWIND [{title: 'Matrix'}, {title: 'Matrix 2'}] AS var0 ORDER BY var0.title.DESC ASC LIMIT 10" `); diff --git a/src/clauses/Use.test.ts b/src/clauses/Use.test.ts index aeae66bb..20e98f49 100644 --- a/src/clauses/Use.test.ts +++ b/src/clauses/Use.test.ts @@ -41,12 +41,12 @@ describe("CypherBuilder USE", () => { const callQuery = new Cypher.Call(new Cypher.Use("mydb", query1)); const queryResult = callQuery.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` - "CALL { - USE mydb - MATCH (this0:Movie) - RETURN this0 - }" - `); +"CALL { + USE mydb + MATCH (this0:Movie) + RETURN this0 +}" +`); expect(queryResult.params).toMatchInlineSnapshot(`{}`); }); diff --git a/src/clauses/With.test.ts b/src/clauses/With.test.ts index ce7e2eb9..1ff3be9a 100644 --- a/src/clauses/With.test.ts +++ b/src/clauses/With.test.ts @@ -255,7 +255,7 @@ CREATE (this0:Movie)" const queryResult = withQuery.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` "WITH * -MERGE (this0:Movie)" +MERGE (this0:Movie) " `); expect(queryResult.params).toMatchInlineSnapshot(`{}`); }); @@ -267,7 +267,7 @@ MERGE (this0:Movie)" const queryResult = withQuery.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` "WITH * -MERGE (this0:Movie)" +MERGE (this0:Movie) " `); expect(queryResult.params).toMatchInlineSnapshot(`{}`); }); @@ -313,7 +313,7 @@ CALL customProcedure(this0)" expect(cypher).toMatchInlineSnapshot(` "WITH this0 CALL (this0) { - CREATE (this0)-[]->(this1) + CREATE (this0)-[]->(this1) } RETURN this1" `); @@ -339,8 +339,7 @@ RETURN this1" "MATCH (this0:Person) WITH this0 WHERE this0.name = $param0 -SET - this0.name = $param1 +SET this0.name = $param1 RETURN this0" `); diff --git a/src/clauses/sub-clauses/Set.test.ts b/src/clauses/sub-clauses/Set.test.ts index bd7ec288..f3ac60b6 100644 --- a/src/clauses/sub-clauses/Set.test.ts +++ b/src/clauses/sub-clauses/Set.test.ts @@ -27,8 +27,7 @@ describe("Set", () => { const queryResult = clause.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0) -SET - this0:NewLabel" +SET this0:NewLabel" `); expect(queryResult.params).toMatchInlineSnapshot(`{}`); @@ -45,8 +44,8 @@ SET expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0) SET - this0:NewLabel, - this0:\`Another Label\`" + this0:NewLabel, + this0:\`Another Label\`" `); expect(queryResult.params).toMatchInlineSnapshot(`{}`); @@ -64,8 +63,8 @@ SET expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0)-[]->(this1) SET - this0:NewLabel, - this1:\`Another Label\`" + this0:NewLabel, + this1:\`Another Label\`" `); expect(queryResult.params).toMatchInlineSnapshot(`{}`); @@ -82,8 +81,8 @@ SET expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0) SET - this0:$($param0), - this0:$(this0.genre)" + this0:$($param0), + this0:$(this0.genre)" `); expect(queryResult.params).toMatchInlineSnapshot(` @@ -102,8 +101,7 @@ SET const queryResult = clause.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0) -SET - this0[$param0] = $param1" +SET this0[$param0] = $param1" `); expect(queryResult.params).toMatchInlineSnapshot(` @@ -127,8 +125,7 @@ SET const queryResult = clause.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0) -SET - this0 = { title: $param0, year: $param1 }" +SET this0 = {title: $param0, year: $param1}" `); expect(queryResult.params).toMatchInlineSnapshot(` { @@ -149,8 +146,7 @@ SET expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0:Movie) MATCH (this1:Actor) -SET - this0 = this1" +SET this0 = this1" `); expect(queryResult.params).toMatchInlineSnapshot(`{}`); }); @@ -169,8 +165,7 @@ SET const queryResult = clause.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0) -SET - this0 += { title: $param0, year: $param1 }" +SET this0 += {title: $param0, year: $param1}" `); expect(queryResult.params).toMatchInlineSnapshot(` { @@ -191,8 +186,7 @@ SET expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0:Movie) MATCH (this1:Actor) -SET - this0 += this1" +SET this0 += this1" `); expect(queryResult.params).toMatchInlineSnapshot(`{}`); }); diff --git a/src/clauses/sub-clauses/Set.ts b/src/clauses/sub-clauses/Set.ts index 908ae0f2..c97609cc 100644 --- a/src/clauses/sub-clauses/Set.ts +++ b/src/clauses/sub-clauses/Set.ts @@ -55,7 +55,11 @@ export class SetClause extends CypherASTNode { }) .join(",\n"); - return `SET\n${padBlock(paramsStr)}`; + if (this.params.length == 1) { + return `SET ${paramsStr}`; + } else { + return `SET\n${padBlock(paramsStr)}`; + } } private composeParam(env: CypherEnvironment, setParam: SetParam): string { diff --git a/src/expressions/Case.test.ts b/src/expressions/Case.test.ts index 254ab8fa..2621613c 100644 --- a/src/expressions/Case.test.ts +++ b/src/expressions/Case.test.ts @@ -36,9 +36,9 @@ describe("Case", () => { expect(queryResult.cypher).toMatchInlineSnapshot(` "CASE $param0 - WHEN \\"Hello\\" THEN true - WHEN \\"Bye\\" THEN false - ELSE false + WHEN 'Hello' THEN true + WHEN 'Bye' THEN false + ELSE false END" `); @@ -61,11 +61,11 @@ END" const queryResult = new TestClause(caseClause).build(); expect(queryResult.cypher).toMatchInlineSnapshot(` - "CASE - WHEN \\"Hello\\" = $param0 THEN true - ELSE false - END" - `); +"CASE + WHEN 'Hello' = $param0 THEN true + ELSE false +END" +`); expect(queryResult.params).toMatchInlineSnapshot(` { @@ -106,9 +106,9 @@ END" expect(cypher).toMatchInlineSnapshot(` "MATCH (this0:Person) RETURN CASE this0.eyes - WHEN \\"blue\\" THEN 1 - WHEN \\"brown\\", \\"hazel\\" THEN 2 - ELSE 3 + WHEN 'blue' THEN 1 + WHEN 'brown', 'hazel' THEN 2 + ELSE 3 END AS result, this0.eyes AS eyes" `); }); @@ -135,9 +135,9 @@ END AS result, this0.eyes AS eyes" expect(cypher).toMatchInlineSnapshot(` "MATCH (this0:Person) RETURN CASE - WHEN this0.eyes = \\"blue\\" THEN 1 - WHEN this0.age < 40 THEN 2 - ELSE 3 + WHEN this0.eyes = 'blue' THEN 1 + WHEN this0.age < 40 THEN 2 + ELSE 3 END AS result, this0.eyes AS eyes" `); }); diff --git a/src/expressions/IsType.test.ts b/src/expressions/IsType.test.ts index 3044fda6..052c8712 100644 --- a/src/expressions/IsType.test.ts +++ b/src/expressions/IsType.test.ts @@ -30,7 +30,7 @@ describe("IsType", () => { const { cypher, params } = unwindClause.build(); expect(cypher).toMatchInlineSnapshot(` -"UNWIND [42, true, \\"abc\\", NULL] AS var0 +"UNWIND [42, true, 'abc', NULL] AS var0 RETURN var0, var0 IS :: INTEGER" `); expect(params).toMatchInlineSnapshot(`{}`); diff --git a/src/expressions/functions/CypherFunctions.test.ts b/src/expressions/functions/CypherFunctions.test.ts index c8dd501d..963bb740 100644 --- a/src/expressions/functions/CypherFunctions.test.ts +++ b/src/expressions/functions/CypherFunctions.test.ts @@ -25,7 +25,7 @@ describe("Cypher Functions", () => { const myFunction = new Cypher.Function("myFunction", [new Cypher.Literal("test"), new Cypher.Param("test2")]); const queryResult = new TestClause(myFunction).build(); - expect(queryResult.cypher).toMatchInlineSnapshot(`"myFunction(\\"test\\", $param0)"`); + expect(queryResult.cypher).toMatchInlineSnapshot(`"myFunction('test', $param0)"`); expect(queryResult.params).toMatchInlineSnapshot(` { diff --git a/src/expressions/functions/math.test.ts b/src/expressions/functions/math.test.ts index e3e09b15..6572d000 100644 --- a/src/expressions/functions/math.test.ts +++ b/src/expressions/functions/math.test.ts @@ -17,8 +17,8 @@ * limitations under the License. */ -import { TestClause } from "../../utils/TestClause"; import Cypher from "../.."; +import { TestClause } from "../../utils/TestClause"; describe("Math Functions", () => { // Functions with no argument @@ -85,7 +85,7 @@ describe("Math Functions", () => { const roundFunc = Cypher.round(roundNumber, 3, "HALF_DOWN"); const { cypher } = new TestClause(roundFunc).build(); - expect(cypher).toBe(`round(10.23, 3, "HALF_DOWN")`); + expect(cypher).toBe(`round(10.23, 3, 'HALF_DOWN')`); }); }); }); diff --git a/src/expressions/functions/scalar.test.ts b/src/expressions/functions/scalar.test.ts index b1d6535c..630cc698 100644 --- a/src/expressions/functions/scalar.test.ts +++ b/src/expressions/functions/scalar.test.ts @@ -77,7 +77,7 @@ describe("Scalar Functions", () => { const coalesceFunction = Cypher.coalesce(nullParam, testParam, literal); const queryResult = new TestClause(coalesceFunction).build(); - expect(queryResult.cypher).toMatchInlineSnapshot(`"coalesce(NULL, $param0, \\"arthur\\")"`); + expect(queryResult.cypher).toMatchInlineSnapshot(`"coalesce(NULL, $param0, 'arthur')"`); expect(queryResult.params).toMatchInlineSnapshot(` { @@ -100,6 +100,6 @@ describe("Scalar Functions", () => { const cypherFunction = Cypher.size(new Cypher.Literal("Hello")); const queryResult = new TestClause(cypherFunction).build(); - expect(queryResult.cypher).toMatchInlineSnapshot(`"size(\\"Hello\\")"`); + expect(queryResult.cypher).toMatchInlineSnapshot(`"size('Hello')"`); }); }); diff --git a/src/expressions/functions/string.test.ts b/src/expressions/functions/string.test.ts index 957b8bd6..2389ec8d 100644 --- a/src/expressions/functions/string.test.ts +++ b/src/expressions/functions/string.test.ts @@ -50,7 +50,7 @@ describe("String Functions", () => { const testFunction = Cypher[value](new Cypher.Param("Hello"), new Cypher.Literal("Hello")); const { cypher, params } = new TestClause(testFunction).build(); - expect(cypher).toBe(`${value}($param0, "Hello")`); + expect(cypher).toBe(`${value}($param0, 'Hello')`); expect(params).toEqual({ param0: "Hello", @@ -61,7 +61,7 @@ describe("String Functions", () => { const testFunction = Cypher[value]("Hello"); const { cypher, params } = new TestClause(testFunction).build(); - expect(cypher).toBe(`${value}("Hello")`); + expect(cypher).toBe(`${value}('Hello')`); expect(params).toEqual({}); }); @@ -74,7 +74,7 @@ describe("String Functions", () => { ); const { cypher, params } = new TestClause(replaceFunction).build(); - expect(cypher).toMatchInlineSnapshot(`"replace($param0, \\"lo\\", \\"llo\\")"`); + expect(cypher).toMatchInlineSnapshot(`"replace($param0, 'lo', 'llo')"`); expect(params).toMatchInlineSnapshot(` { @@ -87,7 +87,7 @@ describe("String Functions", () => { const substringFunction = Cypher.substring(new Cypher.Param("Hello"), new Cypher.Literal("lo")); const { cypher, params } = new TestClause(substringFunction).build(); - expect(cypher).toMatchInlineSnapshot(`"substring($param0, \\"lo\\")"`); + expect(cypher).toMatchInlineSnapshot(`"substring($param0, 'lo')"`); expect(params).toMatchInlineSnapshot(` { @@ -100,7 +100,7 @@ describe("String Functions", () => { const substring = Cypher.substring(new Cypher.Param("Hello"), new Cypher.Literal("lo"), new Cypher.Literal(2)); const { cypher, params } = new TestClause(substring).build(); - expect(cypher).toMatchInlineSnapshot(`"substring($param0, \\"lo\\", 2)"`); + expect(cypher).toMatchInlineSnapshot(`"substring($param0, 'lo', 2)"`); expect(params).toMatchInlineSnapshot(` { @@ -113,7 +113,7 @@ describe("String Functions", () => { const normalizeFunction = Cypher.normalize(new Cypher.Param("Hello"), normalForm); const { cypher, params } = new TestClause(normalizeFunction).build(); - expect(cypher).toBe(`normalize($param0, "${normalForm}")`); + expect(cypher).toBe(`normalize($param0, '${normalForm}')`); expect(params).toEqual({ param0: "Hello", @@ -137,6 +137,6 @@ describe("String Functions", () => { Cypher.trim("BOTH", new Cypher.Literal("x"), new Cypher.Literal("xxxhelloxxx")) ).build(); - expect(cypher).toMatchInlineSnapshot(`"trim(BOTH \\"x\\" FROM \\"xxxhelloxxx\\")"`); + expect(cypher).toMatchInlineSnapshot(`"trim(BOTH 'x' FROM 'xxxhelloxxx')"`); }); }); diff --git a/src/expressions/functions/temporal.test.ts b/src/expressions/functions/temporal.test.ts index 45e5e1bc..bcc27f5a 100644 --- a/src/expressions/functions/temporal.test.ts +++ b/src/expressions/functions/temporal.test.ts @@ -17,8 +17,8 @@ * limitations under the License. */ -import { TestClause } from "../../utils/TestClause"; import Cypher from "../.."; +import { TestClause } from "../../utils/TestClause"; describe("Temporal Functions", () => { describe.each(["date", "datetime", "localtime", "time", "localdatetime"] as const)("%s()", (fn) => { @@ -47,7 +47,7 @@ describe("Temporal Functions", () => { const cypherFn = temporalFn(new Cypher.Literal("9999-01-01")); const queryResult = new TestClause(cypherFn).build(); - expect(queryResult.cypher).toBe(`${fn}("9999-01-01")`); + expect(queryResult.cypher).toBe(`${fn}('9999-01-01')`); expect(queryResult.params).toEqual({}); }); @@ -56,7 +56,7 @@ describe("Temporal Functions", () => { const cypherFn = temporalFn(new Cypher.Map({ timezone: new Cypher.Literal("America/Los Angeles") })); const queryResult = new TestClause(cypherFn).build(); - expect(queryResult.cypher).toBe(`${fn}({ timezone: "America/Los Angeles" })`); + expect(queryResult.cypher).toBe(`${fn}({timezone: 'America/Los Angeles'})`); expect(queryResult.params).toEqual({}); }); @@ -87,7 +87,7 @@ describe("Temporal Functions", () => { const cypherFn = temporalFn(new Cypher.Literal("9999-01-01")); const queryResult = new TestClause(cypherFn).build(); - expect(queryResult.cypher).toBe(`${fn}.${value}("9999-01-01")`); + expect(queryResult.cypher).toBe(`${fn}.${value}('9999-01-01')`); expect(queryResult.params).toEqual({}); }); @@ -96,7 +96,7 @@ describe("Temporal Functions", () => { const cypherFn = temporalFn(new Cypher.Map({ timezone: new Cypher.Literal("America/Los Angeles") })); const queryResult = new TestClause(cypherFn).build(); - expect(queryResult.cypher).toBe(`${fn}.${value}({ timezone: "America/Los Angeles" })`); + expect(queryResult.cypher).toBe(`${fn}.${value}({timezone: 'America/Los Angeles'})`); expect(queryResult.params).toEqual({}); }); @@ -107,7 +107,7 @@ describe("Temporal Functions", () => { const queryResult = new TestClause(truncate).build(); - expect(queryResult.cypher).toBe(`${fn}.truncate("millennium", var0)`); + expect(queryResult.cypher).toBe(`${fn}.truncate('millennium', var0)`); expect(queryResult.params).toEqual({}); }); @@ -120,7 +120,7 @@ describe("Temporal Functions", () => { const queryResult = new TestClause(truncate).build(); - expect(queryResult.cypher).toBe(`${fn}.truncate("century", var0, { day: 5 })`); + expect(queryResult.cypher).toBe(`${fn}.truncate('century', var0, {day: 5})`); expect(queryResult.params).toEqual({}); }); @@ -159,7 +159,7 @@ describe("Temporal Functions", () => { const queryResult = new TestClause(durationFunc).build(); - expect(queryResult.cypher).toMatchInlineSnapshot(`"duration({ days: 2, hours: $param0 })"`); + expect(queryResult.cypher).toMatchInlineSnapshot(`"duration({days: 2, hours: $param0})"`); expect(queryResult.params).toMatchInlineSnapshot(` { diff --git a/src/expressions/list/ListExpr.test.ts b/src/expressions/list/ListExpr.test.ts index 3999c80a..df485ac3 100644 --- a/src/expressions/list/ListExpr.test.ts +++ b/src/expressions/list/ListExpr.test.ts @@ -26,7 +26,7 @@ describe("List", () => { const queryResult = new TestClause(cypherList).build(); - expect(queryResult.cypher).toMatchInlineSnapshot(`"[\\"1\\", \\"2\\", \\"3\\"]"`); + expect(queryResult.cypher).toMatchInlineSnapshot(`"['1', '2', '3']"`); expect(queryResult.params).toMatchInlineSnapshot(`{}`); }); @@ -35,7 +35,7 @@ describe("List", () => { const listIndex = cypherList.index(0); const queryResult = new TestClause(listIndex).build(); - expect(queryResult.cypher).toMatchInlineSnapshot(`"[\\"1\\", \\"2\\", \\"3\\"][0]"`); + expect(queryResult.cypher).toMatchInlineSnapshot(`"['1', '2', '3'][0]"`); expect(queryResult.params).toMatchInlineSnapshot(`{}`); }); @@ -44,7 +44,7 @@ describe("List", () => { const listIndex = cypherList.range(1, -1); const queryResult = new TestClause(listIndex).build(); - expect(queryResult.cypher).toMatchInlineSnapshot(`"[\\"1\\", \\"2\\", \\"3\\"][1..-1]"`); + expect(queryResult.cypher).toMatchInlineSnapshot(`"['1', '2', '3'][1..-1]"`); expect(queryResult.params).toMatchInlineSnapshot(`{}`); }); }); diff --git a/src/expressions/list/ListIndex.test.ts b/src/expressions/list/ListIndex.test.ts index 34a31e04..87197a37 100644 --- a/src/expressions/list/ListIndex.test.ts +++ b/src/expressions/list/ListIndex.test.ts @@ -26,7 +26,7 @@ describe("ListIndex", () => { const listIndex = Cypher.listIndex(list, 0); const queryResult = new TestClause(listIndex).build(); - expect(queryResult.cypher).toMatchInlineSnapshot(`"[\\"1\\", \\"2\\", \\"3\\"][0]"`); + expect(queryResult.cypher).toMatchInlineSnapshot(`"['1', '2', '3'][0]"`); expect(queryResult.params).toMatchInlineSnapshot(`{}`); }); diff --git a/src/expressions/list/ListRange.test.ts b/src/expressions/list/ListRange.test.ts index 07d4d1e9..16682d1d 100644 --- a/src/expressions/list/ListRange.test.ts +++ b/src/expressions/list/ListRange.test.ts @@ -26,7 +26,7 @@ describe("ListRange", () => { const listIndex = Cypher.listRange(list, 0, 2); const queryResult = new TestClause(listIndex).build(); - expect(queryResult.cypher).toMatchInlineSnapshot(`"[\\"1\\", \\"2\\", \\"3\\"][0..2]"`); + expect(queryResult.cypher).toMatchInlineSnapshot(`"['1', '2', '3'][0..2]"`); expect(queryResult.params).toMatchInlineSnapshot(`{}`); }); @@ -35,7 +35,7 @@ describe("ListRange", () => { const listIndex = Cypher.listRange(list, 2, -1); const queryResult = new TestClause(listIndex).build(); - expect(queryResult.cypher).toMatchInlineSnapshot(`"[\\"1\\", \\"2\\", \\"3\\"][2..-1]"`); + expect(queryResult.cypher).toMatchInlineSnapshot(`"['1', '2', '3'][2..-1]"`); expect(queryResult.params).toMatchInlineSnapshot(`{}`); }); diff --git a/src/expressions/list/PatternComprehension.test.ts b/src/expressions/list/PatternComprehension.test.ts index 8e3858a7..abb575a3 100644 --- a/src/expressions/list/PatternComprehension.test.ts +++ b/src/expressions/list/PatternComprehension.test.ts @@ -97,9 +97,7 @@ describe("Pattern comprehension", () => { const queryResult = new TestClause(comprehension).build(); - expect(queryResult.cypher).toMatchInlineSnapshot( - `"[(this0:Movie)-[this2:ACTED_IN]->(this1:Actor) WHERE this0.title CONTAINS \\"Matrix\\" | this1.name]"` - ); + expect(queryResult.cypher).toMatchInlineSnapshot(`"[(this0:Movie)-[this2:ACTED_IN]->(this1:Actor) WHERE this0.title CONTAINS 'Matrix' | this1.name]"`); expect(queryResult.params).toMatchInlineSnapshot(`{}`); }); diff --git a/src/expressions/map/MapExpr.test.ts b/src/expressions/map/MapExpr.test.ts index fa3432e1..9d44801f 100644 --- a/src/expressions/map/MapExpr.test.ts +++ b/src/expressions/map/MapExpr.test.ts @@ -30,7 +30,7 @@ describe("Map Expression", () => { const queryResult = new TestClause(map).build(); - expect(queryResult.cypher).toMatchInlineSnapshot(`"{ foo: \\"barr\\", var: var0, param: $param0 }"`); + expect(queryResult.cypher).toMatchInlineSnapshot(`"{foo: 'barr', var: var0, param: $param0}"`); expect(queryResult.params).toMatchInlineSnapshot(` { @@ -52,9 +52,7 @@ describe("Map Expression", () => { const queryResult = new TestClause(map).build(); - expect(queryResult.cypher).toMatchInlineSnapshot( - `"{ key: $param0, value2: \\"Override\\", value3: \\"another value\\" }"` - ); + expect(queryResult.cypher).toMatchInlineSnapshot(`"{key: $param0, value2: 'Override', value3: 'another value'}"`); expect(queryResult.params).toMatchInlineSnapshot(` { diff --git a/src/expressions/map/MapProjection.test.ts b/src/expressions/map/MapProjection.test.ts index aa620e04..9cd2c486 100644 --- a/src/expressions/map/MapProjection.test.ts +++ b/src/expressions/map/MapProjection.test.ts @@ -85,9 +85,7 @@ describe("Map Projection", () => { }); const queryResult = new TestClause(mapProjection.toMap()).build(); - expect(queryResult.cypher).toMatchInlineSnapshot( - `"{ title: var0.title, name: var0.name, namedValue: count(this1) }"` - ); + expect(queryResult.cypher).toMatchInlineSnapshot(`"{title: var0.title, name: var0.name, namedValue: count(this1)}"`); expect(queryResult.params).toMatchInlineSnapshot(`{}`); }); @@ -132,7 +130,7 @@ describe("Map Projection", () => { const queryResult = new TestClause(mapProjection).build(); - expect(queryResult.cypher).toMatchInlineSnapshot(`"var0 { .*, title: \\"Test\\" }"`); + expect(queryResult.cypher).toMatchInlineSnapshot(`"var0 { .*, title: 'Test' }"`); }); test("Passing * as a field escapes it", () => { diff --git a/src/expressions/operations/comparison.test.ts b/src/expressions/operations/comparison.test.ts index 85c62727..4ee64eec 100644 --- a/src/expressions/operations/comparison.test.ts +++ b/src/expressions/operations/comparison.test.ts @@ -59,7 +59,7 @@ describe("comparison operations", () => { const stringLiteral = new Cypher.Literal(String.raw`the \u212B char`); const query = new Cypher.Return([Cypher.isNormalized(stringLiteral), "normalized"]); const { cypher } = query.build(); - expect(cypher).toMatchInlineSnapshot(`"RETURN \\"the \\\\u212B char\\" IS NORMALIZED AS normalized"`); + expect(cypher).toMatchInlineSnapshot(`"RETURN 'the \\\\u212B char' IS NORMALIZED AS normalized"`); }); test.each(["NFC", "NFD", "NFKC", "NFKD"] as const)( @@ -68,7 +68,7 @@ describe("comparison operations", () => { const stringLiteral = new Cypher.Literal(String.raw`the \u212B char`); const query = new Cypher.Return([Cypher.isNormalized(stringLiteral, type), "normalized"]); const { cypher } = query.build(); - expect(cypher).toBe(`RETURN "the \\u212B char" IS ${type} NORMALIZED AS normalized`); + expect(cypher).toBe(`RETURN 'the \\u212B char' IS ${type} NORMALIZED AS normalized`); } ); @@ -76,9 +76,7 @@ describe("comparison operations", () => { const stringLiteral = new Cypher.Literal(String.raw`the \u212B char`); const query = new Cypher.Return([Cypher.isNotNormalized(stringLiteral), "notNormalized"]); const { cypher } = query.build(); - expect(cypher).toMatchInlineSnapshot( - `"RETURN \\"the \\\\u212B char\\" IS NOT NORMALIZED AS notNormalized"` - ); + expect(cypher).toMatchInlineSnapshot(`"RETURN 'the \\\\u212B char' IS NOT NORMALIZED AS notNormalized"`); }); test.each(["NFC", "NFD", "NFKC", "NFKD"] as const)( @@ -87,7 +85,7 @@ describe("comparison operations", () => { const stringLiteral = new Cypher.Literal(String.raw`the \u212B char`); const query = new Cypher.Return([Cypher.isNotNormalized(stringLiteral, type), "notNormalized"]); const { cypher } = query.build(); - expect(cypher).toBe(`RETURN "the \\u212B char" IS NOT ${type} NORMALIZED AS notNormalized`); + expect(cypher).toBe(`RETURN 'the \\u212B char' IS NOT ${type} NORMALIZED AS notNormalized`); } ); }); diff --git a/src/expressions/operations/concat.test.ts b/src/expressions/operations/concat.test.ts index f546cc4a..c4dd50c3 100644 --- a/src/expressions/operations/concat.test.ts +++ b/src/expressions/operations/concat.test.ts @@ -24,7 +24,7 @@ describe("concat operators", () => { test("concatenating strings", () => { const concat = Cypher.concat(new Cypher.Literal("Hello"), new Cypher.Literal("World!")); const { cypher } = new TestClause(concat).build(); - expect(cypher).toMatchInlineSnapshot(`"(\\"Hello\\" || \\"World!\\")"`); + expect(cypher).toMatchInlineSnapshot(`"('Hello' || 'World!')"`); }); test("concatenating multiple strings with params", () => { const concat = Cypher.concat( @@ -33,7 +33,7 @@ describe("concat operators", () => { new Cypher.Param("Thanks for all the fish") ); const { cypher, params } = new TestClause(concat).build(); - expect(cypher).toMatchInlineSnapshot(`"(\\"Hello\\" || \\"World!\\" || $param0)"`); + expect(cypher).toMatchInlineSnapshot(`"('Hello' || 'World!' || $param0)"`); expect(params).toMatchInlineSnapshot(` { "param0": "Thanks for all the fish", @@ -50,8 +50,7 @@ describe("concat operators", () => { const { cypher } = new TestClause(matchSet).build(); expect(cypher).toMatchInlineSnapshot(` "MATCH (this0) -SET - this0.greeting = (\\"Hello \\" || this0.name)" +SET this0.greeting = ('Hello ' || this0.name)" `); }); }); diff --git a/src/expressions/operations/math.test.ts b/src/expressions/operations/math.test.ts index 141869a5..3d065ac9 100644 --- a/src/expressions/operations/math.test.ts +++ b/src/expressions/operations/math.test.ts @@ -55,7 +55,7 @@ describe("math operators", () => { test("plus for concatenating strings", () => { const concatPlus = Cypher.plus(new Cypher.Literal("Hello"), new Cypher.Literal("World!")); const { cypher } = new TestClause(concatPlus).build(); - expect(cypher).toMatchInlineSnapshot(`"(\\"Hello\\" + \\"World!\\")"`); + expect(cypher).toMatchInlineSnapshot(`"('Hello' + 'World!')"`); }); test("minus", () => { diff --git a/src/expressions/subquery/Collect.test.ts b/src/expressions/subquery/Collect.test.ts index afed2de7..771f89d2 100644 --- a/src/expressions/subquery/Collect.test.ts +++ b/src/expressions/subquery/Collect.test.ts @@ -38,9 +38,9 @@ describe("Collect Subquery", () => { expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0:Person) -WHERE \\"Ozzy\\" IN COLLECT { - MATCH (this0:Person)-[this1:HAS_DOG]->(this2:Dog) - RETURN this2.name +WHERE 'Ozzy' IN COLLECT { + MATCH (this0:Person)-[this1:HAS_DOG]->(this2:Dog) + RETURN this2.name } RETURN this0" `); @@ -76,11 +76,11 @@ RETURN this0" expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0:Person) RETURN this0, COLLECT { - MATCH (this0:Person)-[this1:HAS_DOG]->(this2:Dog) - RETURN this2.name AS petName - UNION - MATCH (this0:Person)-[this3:HAS_CAT]->(this4:Cat) - RETURN this4.name AS petName + MATCH (this0:Person)-[this1:HAS_DOG]->(this2:Dog) + RETURN this2.name AS petName + UNION + MATCH (this0:Person)-[this3:HAS_CAT]->(this4:Cat) + RETURN this4.name AS petName } AS petNames" `); diff --git a/src/expressions/subquery/Count.test.ts b/src/expressions/subquery/Count.test.ts index e4414c3b..c00c11f3 100644 --- a/src/expressions/subquery/Count.test.ts +++ b/src/expressions/subquery/Count.test.ts @@ -31,13 +31,13 @@ describe("Count Subquery", () => { const queryResult = match.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` - "MATCH (this0) - WHERE COUNT { - MATCH (this1:Movie) - RETURN * - } > 10 - RETURN *" - `); +"MATCH (this0) +WHERE COUNT { + MATCH (this1:Movie) + RETURN * +} > 10 +RETURN *" +`); expect(queryResult.params).toMatchInlineSnapshot(`{}`); }); diff --git a/src/expressions/subquery/Exists.test.ts b/src/expressions/subquery/Exists.test.ts index 667bf484..e34360ea 100644 --- a/src/expressions/subquery/Exists.test.ts +++ b/src/expressions/subquery/Exists.test.ts @@ -29,13 +29,13 @@ describe("Exists subquery", () => { const queryResult = match.build(); expect(queryResult.cypher).toMatchInlineSnapshot(` - "MATCH (this0) - WHERE EXISTS { - MATCH (this1:Movie) - RETURN * - } - RETURN *" - `); +"MATCH (this0) +WHERE EXISTS { + MATCH (this1:Movie) + RETURN * +} +RETURN *" +`); expect(queryResult.params).toMatchInlineSnapshot(`{}`); }); diff --git a/src/namespaces/db/cdc.test.ts b/src/namespaces/db/cdc.test.ts index 25c7cd59..f929a9d0 100644 --- a/src/namespaces/db/cdc.test.ts +++ b/src/namespaces/db/cdc.test.ts @@ -58,14 +58,14 @@ describe("db.cdc procedures", () => { const query = Cypher.db.cdc.query("my-cursor"); const { cypher } = query.build(); - expect(cypher).toMatchInlineSnapshot(`"CALL db.cdc.query(\\"my-cursor\\", [])"`); + expect(cypher).toMatchInlineSnapshot(`"CALL db.cdc.query('my-cursor', [])"`); }); test("with literal", () => { const query = Cypher.db.cdc.query(new Cypher.Literal("my-cursor")); const { cypher } = query.build(); - expect(cypher).toMatchInlineSnapshot(`"CALL db.cdc.query(\\"my-cursor\\", [])"`); + expect(cypher).toMatchInlineSnapshot(`"CALL db.cdc.query('my-cursor', [])"`); }); test("with selectors in array", () => { @@ -73,9 +73,7 @@ describe("db.cdc procedures", () => { const { cypher } = query.build(); - expect(cypher).toMatchInlineSnapshot( - `"CALL db.cdc.query(\\"my-cursor\\", [{ select: \\"e\\", operation: \\"c\\", changesTo: [\\"name\\", \\"title\\"] }])"` - ); + expect(cypher).toMatchInlineSnapshot(`"CALL db.cdc.query('my-cursor', [{select: 'e', operation: 'c', changesTo: ['name', 'title']}])"`); }); }); }); diff --git a/src/namespaces/db/db.test.ts b/src/namespaces/db/db.test.ts index 39e3822f..0cbed064 100644 --- a/src/namespaces/db/db.test.ts +++ b/src/namespaces/db/db.test.ts @@ -26,7 +26,7 @@ describe("db procedures", () => { const { cypher } = procedure.build(); - expect(cypher).toMatchInlineSnapshot(`"CALL db.awaitIndex(\\"name\\", 123)"`); + expect(cypher).toMatchInlineSnapshot(`"CALL db.awaitIndex('name', 123)"`); }); test("db.awaitIndexes", () => { const procedure = Cypher.db.awaitIndexes(123); @@ -43,7 +43,7 @@ describe("db procedures", () => { const { cypher } = procedure.build(); - expect(cypher).toEqual(`CALL db.${procedureName}("param")`); + expect(cypher).toEqual(`CALL db.${procedureName}('param')`); } ); @@ -54,7 +54,7 @@ describe("db procedures", () => { const { cypher } = procedure.build(); - expect(cypher).toEqual(`CALL db.${procedureName}("param")`); + expect(cypher).toEqual(`CALL db.${procedureName}('param')`); } ); @@ -147,7 +147,7 @@ describe("db functions", () => { const dbNameFromElementId = Cypher.db.nameFromElementId("1234"); const { cypher, params } = new TestClause(dbNameFromElementId).build(); - expect(cypher).toMatchInlineSnapshot(`"db.nameFromElementId(\\"1234\\")"`); + expect(cypher).toMatchInlineSnapshot(`"db.nameFromElementId('1234')"`); expect(params).toMatchInlineSnapshot(`{}`); }); diff --git a/src/namespaces/db/index/fulltext.test.ts b/src/namespaces/db/index/fulltext.test.ts index c58733b2..1ebbfffa 100644 --- a/src/namespaces/db/index/fulltext.test.ts +++ b/src/namespaces/db/index/fulltext.test.ts @@ -29,9 +29,7 @@ describe("db.index.fulltext", () => { const { cypher, params } = fulltextProcedure.build(); - expect(cypher).toMatchInlineSnapshot( - `"CALL db.index.fulltext.queryNodes(\\"my-text-index\\", $param0) YIELD node AS this0"` - ); + expect(cypher).toMatchInlineSnapshot(`"CALL db.index.fulltext.queryNodes('my-text-index', $param0) YIELD node AS this0"`); expect(params).toMatchInlineSnapshot(` { "param0": "This is a lovely phrase", @@ -50,10 +48,10 @@ describe("db.index.fulltext", () => { const { cypher, params } = fulltextProcedure.build(); expect(cypher).toMatchInlineSnapshot(` - "CALL db.index.fulltext.queryNodes(\\"my-text-index\\", $param0) YIELD node AS this0 - WHERE this0.title = $param1 - RETURN this0" - `); +"CALL db.index.fulltext.queryNodes('my-text-index', $param0) YIELD node AS this0 +WHERE this0.title = $param1 +RETURN this0" +`); expect(params).toMatchInlineSnapshot(` { "param0": "This is a lovely phrase", @@ -74,9 +72,7 @@ describe("db.index.fulltext", () => { const { cypher, params } = fulltextProcedure.build(); - expect(cypher).toMatchInlineSnapshot( - `"CALL db.index.fulltext.queryNodes(\\"my-text-index\\", $param0, { skip: 5, analyser: $param1 })"` - ); + expect(cypher).toMatchInlineSnapshot(`"CALL db.index.fulltext.queryNodes('my-text-index', $param0, {skip: 5, analyser: $param1})"`); expect(params).toMatchInlineSnapshot(` { "param0": "This is a lovely phrase", @@ -95,9 +91,7 @@ describe("db.index.fulltext", () => { const { cypher, params } = fulltextProcedure.build(); - expect(cypher).toMatchInlineSnapshot( - `"CALL db.index.fulltext.queryRelationships(\\"my-text-index\\", $param0) YIELD relationship AS this0"` - ); + expect(cypher).toMatchInlineSnapshot(`"CALL db.index.fulltext.queryRelationships('my-text-index', $param0) YIELD relationship AS this0"`); expect(params).toMatchInlineSnapshot(` { "param0": "This is a lovely phrase", @@ -117,9 +111,7 @@ describe("db.index.fulltext", () => { const { cypher, params } = fulltextProcedure.build(); - expect(cypher).toMatchInlineSnapshot( - `"CALL db.index.fulltext.queryRelationships(\\"my-text-index\\", $param0, { skip: 5, analyser: $param1 })"` - ); + expect(cypher).toMatchInlineSnapshot(`"CALL db.index.fulltext.queryRelationships('my-text-index', $param0, {skip: 5, analyser: $param1})"`); expect(params).toMatchInlineSnapshot(` { "param0": "This is a lovely phrase", diff --git a/src/namespaces/db/index/vector.test.ts b/src/namespaces/db/index/vector.test.ts index 207dce69..874f8574 100644 --- a/src/namespaces/db/index/vector.test.ts +++ b/src/namespaces/db/index/vector.test.ts @@ -29,9 +29,7 @@ describe("db.index.vector.queryNodes", () => { const { cypher, params } = vectorProcedure.build(); - expect(cypher).toMatchInlineSnapshot( - `"CALL db.index.vector.queryNodes(\\"my-vector-index\\", 10, $param0) YIELD node AS this0"` - ); + expect(cypher).toMatchInlineSnapshot(`"CALL db.index.vector.queryNodes('my-vector-index', 10, $param0) YIELD node AS this0"`); expect(params).toMatchInlineSnapshot(` { "param0": "This is a lovely phrase", @@ -47,9 +45,7 @@ describe("db.index.vector.queryNodes", () => { const { cypher, params } = vectorProcedure.build(); - expect(cypher).toMatchInlineSnapshot( - `"CALL db.index.vector.queryNodes(\\"my-vector-index\\", 5, \\"This is a lovely phrase literal\\") YIELD node AS this0"` - ); + expect(cypher).toMatchInlineSnapshot(`"CALL db.index.vector.queryNodes('my-vector-index', 5, 'This is a lovely phrase literal') YIELD node AS this0"`); expect(params).toMatchInlineSnapshot(`{}`); }); test("vector with where and return", () => { @@ -64,10 +60,10 @@ describe("db.index.vector.queryNodes", () => { const { cypher, params } = vectorProcedure.build(); expect(cypher).toMatchInlineSnapshot(` - "CALL db.index.vector.queryNodes(\\"my-vector-index\\", 15, $param0) YIELD node AS this0 - WHERE this0.title = $param1 - RETURN this0" - `); +"CALL db.index.vector.queryNodes('my-vector-index', 15, $param0) YIELD node AS this0 +WHERE this0.title = $param1 +RETURN this0" +`); expect(params).toMatchInlineSnapshot(` { "param0": "This is a lovely phrase", @@ -86,9 +82,7 @@ describe("db.index.vector.queryRelationships", () => { const { cypher, params } = vectorProcedure.build(); - expect(cypher).toMatchInlineSnapshot( - `"CALL db.index.vector.queryRelationships(\\"my-vector-index\\", 10, $param0) YIELD relationship AS this0"` - ); + expect(cypher).toMatchInlineSnapshot(`"CALL db.index.vector.queryRelationships('my-vector-index', 10, $param0) YIELD relationship AS this0"`); expect(params).toMatchInlineSnapshot(` { "param0": "This is a lovely phrase", @@ -108,9 +102,7 @@ describe("db.index.vector.queryRelationships", () => { const { cypher, params } = vectorProcedure.build(); - expect(cypher).toMatchInlineSnapshot( - `"CALL db.index.vector.queryRelationships(\\"my-vector-index\\", 10, \\"This is a lovely phrase literal\\") YIELD relationship AS this0"` - ); + expect(cypher).toMatchInlineSnapshot(`"CALL db.index.vector.queryRelationships('my-vector-index', 10, 'This is a lovely phrase literal') YIELD relationship AS this0"`); expect(params).toMatchInlineSnapshot(`{}`); }); test("vector with where and return", () => { @@ -125,10 +117,10 @@ describe("db.index.vector.queryRelationships", () => { const { cypher, params } = vectorProcedure.build(); expect(cypher).toMatchInlineSnapshot(` - "CALL db.index.vector.queryRelationships(\\"my-vector-index\\", 5, $param0) YIELD relationship AS this0 - WHERE this0.title = $param1 - RETURN this0" - `); +"CALL db.index.vector.queryRelationships('my-vector-index', 5, $param0) YIELD relationship AS this0 +WHERE this0.title = $param1 +RETURN this0" +`); expect(params).toMatchInlineSnapshot(` { "param0": "This is a lovely phrase", diff --git a/src/namespaces/genai/genai.test.ts b/src/namespaces/genai/genai.test.ts index 186f5675..768eeb26 100644 --- a/src/namespaces/genai/genai.test.ts +++ b/src/namespaces/genai/genai.test.ts @@ -31,9 +31,7 @@ describe("genai functions", () => { const { cypher, params } = result.build(); - expect(cypher).toMatchInlineSnapshot( - `"WITH genai.vector.encode(\\"embeddings are cool\\", \\"VertexAI\\", { token: \\"my-token\\", projectId: \\"my-project\\" }) AS var0"` - ); + expect(cypher).toMatchInlineSnapshot(`"WITH genai.vector.encode('embeddings are cool', 'VertexAI', {token: 'my-token', projectId: 'my-project'}) AS var0"`); expect(params).toMatchInlineSnapshot(`{}`); }); test("Encode with query and return", () => { @@ -62,11 +60,11 @@ describe("genai functions", () => { const { cypher, params } = result.build(); expect(cypher).toMatchInlineSnapshot(` - "WITH \\"embeddings are cool\\" AS var0 - WITH genai.vector.encode(var0, \\"OpenAI\\", { token: $param0, model: \\"my-model\\", dimensions: 512 }) AS var1 - CALL db.index.vector.queryNodes(\\"my_index\\", 10, var1) YIELD node AS var2, score AS var3 - RETURN var2, var3" - `); +"WITH 'embeddings are cool' AS var0 +WITH genai.vector.encode(var0, 'OpenAI', {token: $param0, model: 'my-model', dimensions: 512}) AS var1 +CALL db.index.vector.queryNodes('my_index', 10, var1) YIELD node AS var2, score AS var3 +RETURN var2, var3" +`); expect(params).toMatchInlineSnapshot(` { "param0": "my-token", @@ -91,9 +89,7 @@ describe("genai procedures", () => { const { cypher, params } = genAiEncodeFunction.build(); - expect(cypher).toMatchInlineSnapshot( - `"CALL genai.vector.encodeBatch([\\"embeddings are cool\\", \\"I love embeddings\\"], \\"OpenAI\\", { token: \\"my-token\\", projectId: \\"my-project\\" })"` - ); + expect(cypher).toMatchInlineSnapshot(`"CALL genai.vector.encodeBatch(['embeddings are cool', 'I love embeddings'], 'OpenAI', {token: 'my-token', projectId: 'my-project'})"`); expect(params).toMatchInlineSnapshot(`{}`); }); test("Cypher.Literal provider value", () => { @@ -104,9 +100,7 @@ describe("genai procedures", () => { const { cypher, params } = genAiEncodeFunction.build(); - expect(cypher).toMatchInlineSnapshot( - `"CALL genai.vector.encodeBatch([\\"embeddings are cool\\", \\"I love embeddings\\"], \\"OpenAI\\", { token: \\"my-token\\", projectId: \\"my-project\\" })"` - ); + expect(cypher).toMatchInlineSnapshot(`"CALL genai.vector.encodeBatch(['embeddings are cool', 'I love embeddings'], 'OpenAI', {token: 'my-token', projectId: 'my-project'})"`); expect(params).toMatchInlineSnapshot(`{}`); }); test("Cypher.Param provider value", () => { @@ -117,9 +111,7 @@ describe("genai procedures", () => { const { cypher, params } = genAiEncodeFunction.build(); - expect(cypher).toMatchInlineSnapshot( - `"CALL genai.vector.encodeBatch([\\"embeddings are cool\\", \\"I love embeddings\\"], $param0, { token: \\"my-token\\", projectId: \\"my-project\\" })"` - ); + expect(cypher).toMatchInlineSnapshot(`"CALL genai.vector.encodeBatch(['embeddings are cool', 'I love embeddings'], $param0, {token: 'my-token', projectId: 'my-project'})"`); expect(params).toMatchInlineSnapshot(` { "param0": "OpenAI", @@ -138,9 +130,7 @@ describe("genai procedures", () => { const { cypher, params } = genAiEncodeFunction.build(); - expect(cypher).toMatchInlineSnapshot( - `"CALL genai.vector.encodeBatch([\\"embeddings are cool\\", \\"I love embeddings\\"], \\"AzureOpenAI\\", { token: \\"my-token\\", resource: \\"my-resource-name\\", deployment: $param0, dimensions: 512 })"` - ); + expect(cypher).toMatchInlineSnapshot(`"CALL genai.vector.encodeBatch(['embeddings are cool', 'I love embeddings'], 'AzureOpenAI', {token: 'my-token', resource: 'my-resource-name', deployment: $param0, dimensions: 512})"`); expect(params).toMatchInlineSnapshot(` { "param0": "my-deployment", @@ -164,9 +154,9 @@ describe("genai procedures", () => { const { cypher, params } = encodeBatchProcedure.build(); expect(cypher).toMatchInlineSnapshot(` - "CALL genai.vector.encodeBatch([\\"embeddings are cool\\", \\"I love embeddings\\"], \\"OpenAI\\", { token: $param0, model: \\"my-model\\", dimensions: 512 }) YIELD index AS var0, vector AS var1, resource AS var2 - RETURN var0, var1, var2" - `); +"CALL genai.vector.encodeBatch(['embeddings are cool', 'I love embeddings'], 'OpenAI', {token: $param0, model: 'my-model', dimensions: 512}) YIELD index AS var0, vector AS var1, resource AS var2 +RETURN var0, var1, var2" +`); expect(params).toMatchInlineSnapshot(` { "param0": "my-token", diff --git a/src/namespaces/tx.test.ts b/src/namespaces/tx.test.ts index acfcb351..22c3c998 100644 --- a/src/namespaces/tx.test.ts +++ b/src/namespaces/tx.test.ts @@ -33,6 +33,6 @@ describe("tx procedures", () => { }); const { cypher } = query.build(); - expect(cypher).toMatchInlineSnapshot(`"CALL tx.setMetaData({ test: \\"dsa\\", test2: $param0 })"`); + expect(cypher).toMatchInlineSnapshot(`"CALL tx.setMetaData({test: 'dsa', test2: $param0})"`); }); }); diff --git a/src/pattern/Pattern.test.ts b/src/pattern/Pattern.test.ts index e7db0bff..01c19e92 100644 --- a/src/pattern/Pattern.test.ts +++ b/src/pattern/Pattern.test.ts @@ -75,9 +75,7 @@ describe("Patterns", () => { }, }); const queryResult = new TestClause(pattern).build(); - expect(queryResult.cypher).toMatchInlineSnapshot( - `"(this0:TestLabel { name: (\\"The \\" + \\"Matrix\\") })"` - ); + expect(queryResult.cypher).toMatchInlineSnapshot(`"(this0:TestLabel { name: ('The ' + 'Matrix') })"`); expect(queryResult.params).toMatchInlineSnapshot(`{}`); }); @@ -225,9 +223,7 @@ describe("Patterns", () => { .to(b) ); const queryResult = query.build(); - expect(queryResult.cypher).toMatchInlineSnapshot( - `"(this0:Person&Actor)-[this1:ACTED_IN { roles: (\\"The \\" + \\"Matrix\\") }]->(this2)"` - ); + expect(queryResult.cypher).toMatchInlineSnapshot(`"(this0:Person&Actor)-[this1:ACTED_IN { roles: ('The ' + 'Matrix') }]->(this2)"`); expect(queryResult.params).toMatchInlineSnapshot(`{}`); }); @@ -434,7 +430,7 @@ describe("Patterns", () => { Cypher.eq(node.property("name"), new Cypher.Literal("Keanu")) ); const queryResult = new TestClause(pattern).build(); - expect(queryResult.cypher).toMatchInlineSnapshot(`"(this0:TestLabel WHERE this0.name = \\"Keanu\\")"`); + expect(queryResult.cypher).toMatchInlineSnapshot(`"(this0:TestLabel WHERE this0.name = 'Keanu')"`); }); test("Node pattern with where predicate and properties", () => { @@ -450,9 +446,7 @@ describe("Patterns", () => { .related({}) .to(new Cypher.Node()); const queryResult = new TestClause(pattern).build(); - expect(queryResult.cypher).toMatchInlineSnapshot( - `"(this0:TestLabel { released: 1999 } WHERE this0.name = \\"Keanu\\")-[]->(this1)"` - ); + expect(queryResult.cypher).toMatchInlineSnapshot(`"(this0:TestLabel { released: 1999 } WHERE this0.name = 'Keanu')-[]->(this1)"`); }); test("Node pattern with where predicate in target node", () => { @@ -463,9 +457,7 @@ describe("Patterns", () => { .to(new Cypher.Variable()) .where(Cypher.eq(node.property("name"), new Cypher.Literal("Keanu"))); const queryResult = new TestClause(pattern).build(); - expect(queryResult.cypher).toMatchInlineSnapshot( - `"(this0:TestLabel)-[]->(var1 WHERE this0.name = \\"Keanu\\")"` - ); + expect(queryResult.cypher).toMatchInlineSnapshot(`"(this0:TestLabel)-[]->(var1 WHERE this0.name = 'Keanu')"`); }); test("Relationship pattern with where predicate", () => { @@ -477,9 +469,7 @@ describe("Patterns", () => { .where(Cypher.eq(relationship.property("role"), new Cypher.Literal("Neo"))) .to(new Cypher.Node()); const queryResult = new TestClause(pattern).build(); - expect(queryResult.cypher).toMatchInlineSnapshot( - `"(this0:TestLabel)-[this1:ACTED_IN WHERE this1.role = \\"Neo\\"]->(this2)"` - ); + expect(queryResult.cypher).toMatchInlineSnapshot(`"(this0:TestLabel)-[this1:ACTED_IN WHERE this1.role = 'Neo']->(this2)"`); }); test("Relationship pattern with where predicate and properties", () => { @@ -496,9 +486,7 @@ describe("Patterns", () => { .where(Cypher.eq(relationship.property("role"), new Cypher.Literal("Neo"))) .to(new Cypher.Node()); const queryResult = new TestClause(pattern).build(); - expect(queryResult.cypher).toMatchInlineSnapshot( - `"(this0:TestLabel)-[this1:ACTED_IN WHERE this1.role = \\"Neo\\" { test: \\"hello\\" }]->(this2)"` - ); + expect(queryResult.cypher).toMatchInlineSnapshot(`"(this0:TestLabel)-[this1:ACTED_IN WHERE this1.role = 'Neo' { test: 'hello' }]->(this2)"`); }); }); diff --git a/src/procedures/CypherProcedure.test.ts b/src/procedures/CypherProcedure.test.ts index b6d5039d..78e8e67f 100644 --- a/src/procedures/CypherProcedure.test.ts +++ b/src/procedures/CypherProcedure.test.ts @@ -60,9 +60,7 @@ describe("Procedures", () => { const { cypher, params } = customProcedure.build(); - expect(cypher).toMatchInlineSnapshot( - `"CALL customProcedure(this0) YIELD result1, result2 AS \\"aliased\\", result3 AS string-alias"` - ); + expect(cypher).toMatchInlineSnapshot(`"CALL customProcedure(this0) YIELD result1, result2 AS 'aliased', result3 AS string-alias"`); expect(params).toMatchInlineSnapshot(`{}`); }); @@ -195,8 +193,7 @@ REMOVE this0.test" expect(cypher).toMatchInlineSnapshot(` "CALL custom-procedure() YIELD test -SET - var0.test = \\"hello\\"" +SET var0.test = 'hello'" `); expect(params).toMatchInlineSnapshot(`{}`); }); @@ -223,7 +220,7 @@ UNWIND var0 AS var1" expect(cypher).toMatchInlineSnapshot(` "CALL custom-procedure() YIELD test -MERGE (this0)" +MERGE (this0) " `); expect(params).toMatchInlineSnapshot(`{}`); }); diff --git a/src/references/Literal.test.ts b/src/references/Literal.test.ts index af1f9135..d6850972 100644 --- a/src/references/Literal.test.ts +++ b/src/references/Literal.test.ts @@ -27,16 +27,25 @@ describe("Literal", () => { const testClause = new TestClause(stringLiteral); const queryResult = testClause.build(); - expect(queryResult.cypher).toBe(`"hello"`); + expect(queryResult.cypher).toBe(`'hello'`); }); - test("Serialize string value escaping it", () => { + test("Serialize string value with quotes", () => { const stringLiteral = new Cypher.Literal(`he"llo`); const testClause = new TestClause(stringLiteral); const queryResult = testClause.build(); - expect(queryResult.cypher).toBe(`"he\\"llo"`); + expect(queryResult.cypher).toBe(`'he"llo'`); + }); + + test("Serialize string value escaping it", () => { + const stringLiteral = new Cypher.Literal(`he'llo`); + + const testClause = new TestClause(stringLiteral); + + const queryResult = testClause.build(); + expect(queryResult.cypher).toBe(`'he\\'llo'`); }); test("Serialize boolean value", () => { @@ -63,16 +72,25 @@ describe("Literal", () => { const testClause = new TestClause(literal); const queryResult = testClause.build(); - expect(queryResult.cypher).toBe(`["hello", 5, "hello"]`); + expect(queryResult.cypher).toBe(`['hello', 5, 'hello']`); }); - test("Serialize array escaping values", () => { + test("Serialize array with quotes", () => { const literal = new Cypher.Literal(["hello", 5, 'hel""lo']); const testClause = new TestClause(literal); const queryResult = testClause.build(); - expect(queryResult.cypher).toBe(`["hello", 5, "hel\\"\\"lo"]`); + expect(queryResult.cypher).toBe(`['hello', 5, 'hel""lo']`); + }); + + test("Serialize array escaping values", () => { + const literal = new Cypher.Literal(["hello", 5, "hel''lo"]); + + const testClause = new TestClause(literal); + + const queryResult = testClause.build(); + expect(queryResult.cypher).toBe(`['hello', 5, 'hel\\'\\'lo']`); }); test("Serialize null", () => { diff --git a/src/references/Literal.ts b/src/references/Literal.ts index 741b9ff5..020ef480 100644 --- a/src/references/Literal.ts +++ b/src/references/Literal.ts @@ -43,7 +43,7 @@ export class Literal implements CypherCom private formatLiteralValue(value: LiteralValue): string { if (typeof value === "string") { - return `"${escapeLiteralString(value)}"`; + return `'${escapeLiteralString(value)}'`; } if (value === null) { return "NULL"; diff --git a/src/references/PropertyRef.test.ts b/src/references/PropertyRef.test.ts index 71839930..ffd958c5 100644 --- a/src/references/PropertyRef.test.ts +++ b/src/references/PropertyRef.test.ts @@ -129,7 +129,7 @@ describe("Property", () => { const testClause = new TestClause(property); const queryResult = testClause.build(); - expect(queryResult.cypher).toMatchInlineSnapshot(`"var0[date()][\\"Hello\\"]"`); + expect(queryResult.cypher).toMatchInlineSnapshot(`"var0[date()]['Hello']"`); }); test("Serialize nested string after expression", () => { diff --git a/src/references/Variable.test.ts b/src/references/Variable.test.ts index ada3afe7..7b95fcc1 100644 --- a/src/references/Variable.test.ts +++ b/src/references/Variable.test.ts @@ -51,7 +51,7 @@ describe("Variable", () => { Cypher.plus(new Cypher.Param("foo"), new Cypher.Literal("bar")) ); - expect(new TestClause(variableProp).build().cypher).toMatchInlineSnapshot(`"var0[($param0 + \\"bar\\")]"`); + expect(new TestClause(variableProp).build().cypher).toMatchInlineSnapshot(`"var0[($param0 + 'bar')]"`); }); test("does not escape named variable with valid name", () => { diff --git a/src/utils/concat.test.ts b/src/utils/concat.test.ts index 3876f279..347e141f 100644 --- a/src/utils/concat.test.ts +++ b/src/utils/concat.test.ts @@ -67,13 +67,11 @@ describe("CypherBuilder utils.concat", () => { const queryResult = Cypher.utils.concat(create1, create2).build(); expect(queryResult.cypher).toMatchInlineSnapshot(` - "CREATE (this0:Movie) - SET - this0.title = $param0 - CREATE (this1:Movie) - SET - this1.title = $param0" - `); +"CREATE (this0:Movie) +SET this0.title = $param0 +CREATE (this1:Movie) +SET this1.title = $param0" +`); expect(queryResult.params).toMatchInlineSnapshot(` { diff --git a/src/utils/escape.test.ts b/src/utils/escape.test.ts index 2f39b8d6..d51698f5 100644 --- a/src/utils/escape.test.ts +++ b/src/utils/escape.test.ts @@ -46,8 +46,10 @@ describe("escaping", () => { }); test.each([ - [`my "var"`, `my \\"var\\"`], - [`my \\"var`, `my \\\\"var`], + [`my "var"`, `my "var"`], + [`my \\"var`, `my \\"var`], + [`my 'var'`, `my \\'var\\'`], + [`my \\'var`, `my \\\\'var`], ])("Escape '%s'", (original, expected) => { expect(escapeLiteralString(original)).toBe(expected); }); diff --git a/src/utils/escape.ts b/src/utils/escape.ts index 3e958021..368ebce4 100644 --- a/src/utils/escape.ts +++ b/src/utils/escape.ts @@ -46,7 +46,7 @@ export function escapeVariable(varName: string): string { /** Escapes a literal string */ export function escapeLiteralString(str: string): string { - return str.replaceAll(`"`, `\\"`); + return str.replaceAll(`'`, `\\'`); } function escapeIfNeeded(str: string): string { diff --git a/src/utils/pad-block.ts b/src/utils/pad-block.ts index ffd9fc82..89b3247c 100644 --- a/src/utils/pad-block.ts +++ b/src/utils/pad-block.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -export function padBlock(block: string, spaces = 4): string { +export function padBlock(block: string, spaces = 2): string { const paddingStr = " ".repeat(spaces); const paddedNewLines = block.replaceAll("\n", `\n${paddingStr}`); return `${paddingStr}${paddedNewLines}`; diff --git a/src/utils/serialize-map.test.ts b/src/utils/serialize-map.test.ts index 639c3bfc..a479daea 100644 --- a/src/utils/serialize-map.test.ts +++ b/src/utils/serialize-map.test.ts @@ -31,7 +31,7 @@ describe("serializeMap", () => { test("serialize a map of expressions", () => { const result = serializeMap(env, map); - expect(result).toBe("{ test: 10, `test$`: 10, expr: reverse([1]) }"); + expect(result).toBe("{test: 10, `test$`: 10, expr: reverse([1])}"); }); test("serialize a map of expressions without curly braces", () => { diff --git a/src/utils/serialize-map.ts b/src/utils/serialize-map.ts index 735c93da..6cf27ffa 100644 --- a/src/utils/serialize-map.ts +++ b/src/utils/serialize-map.ts @@ -17,8 +17,8 @@ * limitations under the License. */ -import type { Expr } from "../types"; import type { CypherEnvironment } from "../Environment"; +import type { Expr } from "../types"; import { escapeProperty } from "./escape"; export function serializeMap(env: CypherEnvironment, map: Map, omitCurlyBraces = false): string { @@ -33,5 +33,5 @@ export function serializeMap(env: CypherEnvironment, map: Map, omi const serializedContent = serializedFields.join(", "); if (omitCurlyBraces) return serializedContent; - return `{ ${serializedContent} }`; + return `{${serializedContent}}`; } diff --git a/tests/build-config/unsafe-escape.test.ts b/tests/build-config/unsafe-escape.test.ts index e61804e6..ffd871e1 100644 --- a/tests/build-config/unsafe-escape.test.ts +++ b/tests/build-config/unsafe-escape.test.ts @@ -44,9 +44,8 @@ describe("escapeUnsafeLabels", () => { }, }); expect(queryResult.cypher).toMatchInlineSnapshot(` -"MATCH (this0:Person { \`person name\`: \\"Uneak \\\\\\"Seveer\\" })-[:\`ACTED IN\`]->(this1:\`A Movie\`) -SET - this0.\`person name\` = $param0 +"MATCH (this0:Person { \`person name\`: 'Uneak \\"Seveer' })-[:\`ACTED IN\`]->(this1:\`A Movie\`) +SET this0.\`person name\` = $param0 RETURN this0 AS \`My Result\`" `); @@ -81,9 +80,8 @@ RETURN this0 AS \`My Result\`" }, }); expect(queryResult.cypher).toMatchInlineSnapshot(` -"MATCH (this0:Person { \`person name\`: \\"Uneak \\\\\\"Seveer\\" })-[:ACTED IN]->(this1:A Movie) -SET - this0.\`person name\` = $param0 +"MATCH (this0:Person { \`person name\`: 'Uneak \\"Seveer' })-[:ACTED IN]->(this1:A Movie) +SET this0.\`person name\` = $param0 RETURN this0 AS \`My Result\`" `); @@ -117,9 +115,8 @@ RETURN this0 AS \`My Result\`" }, }); expect(queryResult.cypher).toMatchInlineSnapshot(` -"MATCH (this0:Person { \`person name\`: \\"Uneak \\\\\\"Seveer\\" })-[:\`ACTED IN\`]->(this1:A Movie) -SET - this0.\`person name\` = $param0 +"MATCH (this0:Person { \`person name\`: 'Uneak \\"Seveer' })-[:\`ACTED IN\`]->(this1:A Movie) +SET this0.\`person name\` = $param0 RETURN this0 AS \`My Result\`" `); @@ -152,9 +149,8 @@ RETURN this0 AS \`My Result\`" }, }); expect(queryResult.cypher).toMatchInlineSnapshot(` -"MATCH (this0:Person { \`person name\`: \\"Uneak \\\\\\"Seveer\\" })-[:ACTED IN]->(this1:\`A Movie\`) -SET - this0.\`person name\` = $param0 +"MATCH (this0:Person { \`person name\`: 'Uneak \\"Seveer' })-[:ACTED IN]->(this1:\`A Movie\`) +SET this0.\`person name\` = $param0 RETURN this0 AS \`My Result\`" `); @@ -188,7 +184,7 @@ RETURN this0 AS \`My Result\`" }); expect(queryResult.cypher).toMatchInlineSnapshot(` -"MATCH (this0:Person { \`person name\`: \\"Uneak \\\\\\"Seveer\\" })-[:ACTED IN]->(this1:A Movie) +"MATCH (this0:Person { \`person name\`: 'Uneak \\"Seveer' })-[:ACTED IN]->(this1:A Movie) RETURN this0" `); expect(queryResult.params).toMatchInlineSnapshot(`{}`); @@ -217,7 +213,7 @@ RETURN this0" }); expect(queryResult.cypher).toMatchInlineSnapshot(` -"MATCH (this0:Person { \`person name\`: \\"Uneak \\\\\\"Seveer\\" })-[:\`ACTED IN\`]->(this1:\`A Movie\`) +"MATCH (this0:Person { \`person name\`: 'Uneak \\"Seveer' })-[:\`ACTED IN\`]->(this1:\`A Movie\`) RETURN this0" `); expect(queryResult.params).toMatchInlineSnapshot(`{}`); diff --git a/tests/console-log.test.ts b/tests/console-log.test.ts index 1cdfa31b..ad54d528 100644 --- a/tests/console-log.test.ts +++ b/tests/console-log.test.ts @@ -39,27 +39,24 @@ describe("Console.log", () => { ); expect(`${query}`).toMatchInlineSnapshot(` - " \\"\\"\\" - CREATE (this0:Movie) - SET - this0.released = $param0 - \\"\\"\\"" - `); +" \\"\\"\\" + CREATE (this0:Movie) + SET this0.released = $param0 +\\"\\"\\"" +`); expect(query.toString()).toMatchInlineSnapshot(` - " \\"\\"\\" - CREATE (this0:Movie) - SET - this0.released = $param0 - \\"\\"\\"" - `); +" \\"\\"\\" + CREATE (this0:Movie) + SET this0.released = $param0 +\\"\\"\\"" +`); // eslint-disable-next-line @typescript-eslint/no-explicit-any expect((query as any)[customInspectSymbol]()).toMatchInlineSnapshot(` - " \\"\\"\\" - CREATE (this0:Movie) - SET - this0.released = $param0 - \\"\\"\\"" - `); +" \\"\\"\\" + CREATE (this0:Movie) + SET this0.released = $param0 +\\"\\"\\"" +`); }); test("console.log on a pattern", () => { @@ -69,18 +66,18 @@ describe("Console.log", () => { expect(`${pattern}`).toMatchInlineSnapshot(` " \\"\\"\\" - (this0)-[]->() + (this0)-[]->() \\"\\"\\"" `); expect(pattern.toString()).toMatchInlineSnapshot(` " \\"\\"\\" - (this0)-[]->() + (this0)-[]->() \\"\\"\\"" `); // eslint-disable-next-line @typescript-eslint/no-explicit-any expect((pattern as any)[customInspectSymbol]()).toMatchInlineSnapshot(` " \\"\\"\\" - (this0)-[]->() + (this0)-[]->() \\"\\"\\"" `); }); diff --git a/tests/issues/462.test.ts b/tests/issues/462.test.ts index 7bcc843c..ecc62fb9 100644 --- a/tests/issues/462.test.ts +++ b/tests/issues/462.test.ts @@ -38,12 +38,11 @@ describe("https://github.com/neo4j/cypher-builder/issues/462", () => { expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0:Person) WHERE this0.name = $param0 -SET - this0.name = $param1 +SET this0.name = $param1 REMOVE this0.anotherName SET - this0.anotherName = $param2, - this0.oldName = $param3 + this0.anotherName = $param2, + this0.oldName = $param3 RETURN this0" `); diff --git a/tests/issues/479.test.ts b/tests/issues/479.test.ts index bd9ffd2e..4cab99f1 100644 --- a/tests/issues/479.test.ts +++ b/tests/issues/479.test.ts @@ -95,7 +95,7 @@ RETURN count(this1)" expect(queryResult.cypher).toMatchInlineSnapshot(` "WITH $param0 AS var0 -MATCH (this1:$((var0 || \\"Test\\"))) +MATCH (this1:$((var0 || 'Test'))) RETURN count(this1)" `); }); diff --git a/tests/issues/514.test.ts b/tests/issues/514.test.ts index 65392672..27f59379 100644 --- a/tests/issues/514.test.ts +++ b/tests/issues/514.test.ts @@ -40,8 +40,7 @@ describe("https://github.com/neo4j/cypher-builder/pull/514", () => { expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0:Movie { title: $param0.title }) -SET - this0 = $param0.year" +SET this0 = $param0.year" `); }); @@ -65,8 +64,7 @@ SET expect(queryResult.cypher).toMatchInlineSnapshot(` "MATCH (this0:Movie { title: $param0.title }) -SET - this0 += $param0.year" +SET this0 += $param0.year" `); }); }); diff --git a/tests/issues/547.test.ts b/tests/issues/547.test.ts index acb9a959..16c93d54 100644 --- a/tests/issues/547.test.ts +++ b/tests/issues/547.test.ts @@ -31,7 +31,7 @@ describe("https://github.com/neo4j/cypher-builder/pull/547", () => { expect(queryResult.cypher).toMatchInlineSnapshot(` "CASE $param0 - WHEN \`in\`[1] THEN true + WHEN \`in\`[1] THEN true END" `); @@ -52,7 +52,7 @@ END" expect(queryResult.cypher).toMatchInlineSnapshot(` "CASE $param0 - WHEN \`in\`.a THEN true + WHEN \`in\`.a THEN true END" `); diff --git a/tests/styleguide.test.ts b/tests/styleguide.test.ts new file mode 100644 index 00000000..02a468aa --- /dev/null +++ b/tests/styleguide.test.ts @@ -0,0 +1,190 @@ +/* + * 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 Cypher from "../src"; + +/** + * These test check if cypher builder matches the examples in + * https://neo4j.com/docs/cypher-manual/25/styleguide/ + * + */ +describe("Cypher styleguide", () => { + describe("indentation", () => { + test("Indentation Clauses", () => { + const node = new Cypher.Node(); + const pattern = new Cypher.Pattern(node); + const query = new Cypher.Match(pattern) + .where(Cypher.contains(node.property("name"), new Cypher.Literal("s"))) + .return(node.property("name")); + + const { cypher } = query.build(); + + expect(cypher).toMatchInlineSnapshot(` +"MATCH (this0) +WHERE this0.name CONTAINS 's' +RETURN this0.name" +`); + }); + test("Indentation ON CREATE and ON MERGE and clause order", () => { + const n = new Cypher.Node(); + const a = new Cypher.Node(); + const b = new Cypher.Node(); + + const pattern = new Cypher.Pattern(n); + const query = new Cypher.Merge(pattern) + .onCreateSet([n.property("prop"), new Cypher.Literal(0)]) + .merge(new Cypher.Pattern(a, { labels: ["A"] }).related({ type: "T" }).to(b, { labels: ["B"] })) + .onMatchSet([a.property("name"), new Cypher.Literal("me")]) // This is put before purposefully, to check that the order is maintained as recommended + .onCreateSet([b.property("name"), new Cypher.Literal("you")]) + .return(a.property("prop")); + const { cypher } = query.build(); + + expect(cypher).toMatchInlineSnapshot(` +"MERGE (this0) + ON CREATE SET this0.prop = 0 +MERGE (this1:A)-[:T]->(this2:B) + ON CREATE SET this2.name = 'you' + ON MATCH SET this1.name = 'me' +RETURN this1.prop" +`); + }); + + test("Indentation ON CREATE and ON MERGE with multiple properties", () => { + const a = new Cypher.Node(); + const b = new Cypher.Node(); + + const query = new Cypher.Merge( + new Cypher.Pattern(a, { labels: ["A"] }).related({ type: "T" }).to(b, { labels: ["B"] }) + ) + .onMatchSet([a.property("name"), new Cypher.Literal("me")], [a.property("age"), new Cypher.Literal(30)]) // This is put before purposefully, to check that the order is maintained as recommended + .onCreateSet([b.property("name"), new Cypher.Literal("you")]) + .return(a.property("prop")); + const { cypher } = query.build(); + + expect(cypher).toMatchInlineSnapshot(` +"MERGE (this0:A)-[:T]->(this1:B) + ON CREATE SET this1.name = 'you' + ON MATCH SET + this0.name = 'me', + this0.age = 30 +RETURN this0.prop" +`); + }); + + test("Exists subquery", () => { + const a = new Cypher.Node(); + const b = new Cypher.Node(); + + const query = new Cypher.Match(new Cypher.Pattern(a, { labels: ["A"] })) + .where( + new Cypher.Exists( + new Cypher.Match(new Cypher.Pattern(a).related().to(b, { labels: ["B"] })).where( + Cypher.eq(b.property("prop"), new Cypher.Literal("yellow")) + ) + ) + ) + .return(a.property("foo")); + const { cypher } = query.build(); + + expect(cypher).toMatchInlineSnapshot(` +"MATCH (this0:A) +WHERE EXISTS { + MATCH (this0)-[]->(this1:B) + WHERE this1.prop = 'yellow' +} +RETURN this0.foo" +`); + }); + + // NOT YET SUPPORTED + // MATCH (a:A) + // WHERE EXISTS { (a)-->(b:B) } + // RETURN a.prop + test.todo("Exists subquery with simplified subquery"); + + test("CASE ... WHEN ... ELSE", () => { + const n = new Cypher.Node(); + const query = new Cypher.Match( + new Cypher.Pattern(n, { labels: ["Person"], properties: { name: new Cypher.Literal("Alice") } }) + ).return([ + new Cypher.Case() + .when(Cypher.gt(n.property("age"), new Cypher.Literal(18))) + .then(new Cypher.Literal("Adult")) + .else(new Cypher.Literal("Minor")), + "ageGroup", + ]); + + const { cypher } = query.build(); + + expect(cypher).toMatchInlineSnapshot(` +"MATCH (this0:Person { name: 'Alice' }) +RETURN CASE + WHEN this0.age > 18 THEN 'Adult' + ELSE 'Minor' +END AS ageGroup" +`); + }); + }); + + describe("Spacing", () => { + test("Maps", () => { + const variable = new Cypher.Variable(); + const query = new Cypher.With([ + new Cypher.Map({ + key1: new Cypher.Literal("value"), + key2: new Cypher.Literal(42), + }), + variable, + ]).return(variable); + + const { cypher } = query.build(); + expect(cypher).toMatchInlineSnapshot(` +"WITH {key1: 'value', key2: 42} AS var0 +RETURN var0" +`); + }); + + test("Lists", () => { + const variable = new Cypher.Variable(); + const query = new Cypher.With([ + new Cypher.List([new Cypher.Literal("a"), new Cypher.Literal("b"), new Cypher.Literal(3.14)]), + variable, + ]).return(variable, new Cypher.Literal(2)); + + const { cypher } = query.build(); + expect(cypher).toMatchInlineSnapshot(` +"WITH ['a', 'b', 3.14] AS var0 +RETURN var0, 2" +`); + }); + }); + + describe("Meta characters", () => { + test("String values", () => { + const query = new Cypher.Return( + new Cypher.Literal("Cypher"), + new Cypher.Literal("A 'Quote'"), + new Cypher.Literal('Another "Quote"') + ); + + const { cypher } = query.build(); + expect(cypher).toMatchInlineSnapshot(`"RETURN 'Cypher', 'A \\\\'Quote\\\\'', 'Another \\"Quote\\"'"`); + }); + }); +});