Skip to content

Commit

Permalink
Chained methods for foreach
Browse files Browse the repository at this point in the history
  • Loading branch information
angrykoala committed Oct 24, 2023
1 parent f03e5b7 commit 9388048
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 9 deletions.
11 changes: 11 additions & 0 deletions .changeset/stale-tips-tell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@neo4j/cypher-builder": minor
---

Add chained subclauses for foreach:

- `Foreach.return`
- `Foreach.remove`
- `Foreach.set`
- `Foreach.delete`
- `Foreach.detachDelete`
49 changes: 49 additions & 0 deletions src/clauses/Foreach.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,53 @@ describe("Foreach", () => {

expect(queryResult.params).toMatchInlineSnapshot(`{}`);
});

test("Foreach create with set, remove and delete", () => {
const list = new Cypher.Literal([1, 2, 3]);
const variable = new Cypher.Variable();

const movieNode = new Cypher.Node({ labels: ["Movie"] });
const createMovie = new Cypher.Create(movieNode);

const foreachClause = new Cypher.Foreach(variable, list, createMovie)
.remove(movieNode.property("title"))
.set([movieNode.property("id"), variable])
.delete(movieNode)
.with("*");

const queryResult = foreachClause.build();
expect(queryResult.cypher).toMatchInlineSnapshot(`
"FOREACH (var0 IN [1, 2, 3] |
CREATE (this1:Movie)
)
SET
this1.id = var0
REMOVE this1.title
DELETE this1
WITH *"
`);

expect(queryResult.params).toMatchInlineSnapshot(`{}`);
});

test("Foreach create detachDelete", () => {
const list = new Cypher.Literal([1, 2, 3]);
const variable = new Cypher.Variable();

const movieNode = new Cypher.Node({ labels: ["Movie"] });
const createMovie = new Cypher.Create(movieNode);

const foreachClause = new Cypher.Foreach(variable, list, createMovie).detachDelete(movieNode).with("*");

const queryResult = foreachClause.build();
expect(queryResult.cypher).toMatchInlineSnapshot(`
"FOREACH (var0 IN [1, 2, 3] |
CREATE (this1:Movie)
)
DETACH DELETE this1
WITH *"
`);

expect(queryResult.params).toMatchInlineSnapshot(`{}`);
});
});
17 changes: 13 additions & 4 deletions src/clauses/Foreach.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,30 @@
import type { CypherEnvironment } from "../Environment";
import type { Variable } from "../references/Variable";
import type { Expr } from "../types";
import { compileCypherIfExists } from "../utils/compile-cypher-if-exists";
import { padBlock } from "../utils/pad-block";
import { Clause } from "./Clause";
import type { Create } from "./Create";
import type { Merge } from "./Merge";
import { WithReturn } from "./mixins/clauses/WithReturn";
import { WithWith } from "./mixins/clauses/WithWith";
import { WithDelete } from "./mixins/sub-clauses/WithDelete";
import { WithRemove } from "./mixins/sub-clauses/WithRemove";
import { WithSet } from "./mixins/sub-clauses/WithSet";
import type { DeleteClause } from "./sub-clauses/Delete";
import type { RemoveClause } from "./sub-clauses/Remove";
import type { SetClause } from "./sub-clauses/Set";
import { mixin } from "./utils/mixin";

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface Foreach extends WithWith {}
export interface Foreach extends WithWith, WithReturn, WithRemove, WithSet, WithDelete {}

type ForeachClauses = Foreach | SetClause | RemoveClause | Create | Merge | DeleteClause;

/**
* @see [Cypher Documentation](https://neo4j.com/docs/cypher-manual/current/clauses/foreach/)
* @group Clauses
*/
@mixin(WithWith)
@mixin(WithWith, WithReturn, WithRemove, WithSet, WithDelete)
export class Foreach extends Clause {
private variable: Variable;
private listExpr: Expr;
Expand All @@ -58,8 +62,13 @@ export class Foreach extends Clause {
const listExpr = this.listExpr.getCypher(env);
const mapClauseStr = this.mapClause.getCypher(env);
const nextClause = this.compileNextClause(env);

const foreachStr = [`FOREACH (${variableStr} IN ${listExpr} |`, padBlock(mapClauseStr), `)`].join("\n");

return `${foreachStr}${nextClause}`;
const setCypher = compileCypherIfExists(this.setSubClause, env, { prefix: "\n" });
const deleteCypher = compileCypherIfExists(this.deleteClause, env, { prefix: "\n" });
const removeCypher = compileCypherIfExists(this.removeClause, env, { prefix: "\n" });

return `${foreachStr}${setCypher}${removeCypher}${deleteCypher}${nextClause}`;
}
}
10 changes: 5 additions & 5 deletions tests/clause-concatenation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,11 @@ describe("Clause chaining", () => {
const clause = new Cypher.Foreach(variable, list, createMovie);

it.each([
// "return",
// "remove",
// "set",
// "delete",
// "detachDelete",
"return",
"remove",
"set",
"delete",
"detachDelete",
"with",
// "merge",
// "create",
Expand Down

0 comments on commit 9388048

Please sign in to comment.