Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .changeset/easy-horses-repeat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
"@neo4j/cypher-builder": major
---

Remove labelOperator, all labels will now use operator `&`

No longer supported:

```js
const { cypher, params } = matchQuery.build({
labelOperator: "&",
});
```

_Before_

```js
MATCH (this1:Movie:Film)
```

_After_

```cypher
MATCH (this1:Movie&Film)
```
4 changes: 1 addition & 3 deletions examples/patterns/label-expressions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ const matchQuery = new Cypher.Match(
})
).return(movieNode);

const { cypher, params } = matchQuery.build({
labelOperator: "&",
});
const { cypher, params } = matchQuery.build();

console.log("Cypher");
console.log(cypher);
Expand Down
4 changes: 1 addition & 3 deletions examples/patterns/length.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@ const pattern = new Cypher.Pattern(movie).related(actedIn, { type: "ACTED_IN", l

const matchQuery = new Cypher.Match(pattern).return(movie);

const { cypher, params } = matchQuery.build({
labelOperator: "&",
});
const { cypher, params } = matchQuery.build();

console.log("Cypher");
console.log(cypher);
Expand Down
4 changes: 1 addition & 3 deletions examples/patterns/quantified-path-patterns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,7 @@ const quantifiedPath = new Cypher.QuantifiedPath(

const query = new Cypher.Match(quantifiedPath).return(m2);

const { cypher, params } = query.build({
labelOperator: "&",
});
const { cypher, params } = query.build();

console.log("Cypher");
console.log(cypher);
Expand Down
2 changes: 0 additions & 2 deletions src/Environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,11 @@ export type EnvPrefix = {
};

export type EnvConfig = {
labelOperator: NonNullable<BuildConfig["labelOperator"]>;
unsafeEscapeOptions: NonNullable<BuildConfig["unsafeEscapeOptions"]>;
cypherVersion: BuildConfig["cypherVersion"];
};

const defaultConfig: EnvConfig = {
labelOperator: ":",
unsafeEscapeOptions: {},
cypherVersion: undefined,
};
Expand Down
17 changes: 2 additions & 15 deletions src/clauses/Clause.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,6 @@ const customInspectSymbol = Symbol.for("nodejs.util.inspect.custom");
* @group Clauses
*/
export type BuildConfig = Partial<{
/** Defines the default operator for adding multiple labels in a Pattern. Defaults to `":"`
*
* If the target Cypher is version 5 or above, `"&"` is recommended
*
* @example
* `MATCH (this:Movie:Film)`
* `MATCH (this:Movie&Film)`
*
* @deprecated This will be removed in the following major release and the value `"&"` will be used in the generated Cypher
*
*/
labelOperator: ":" | "&";
/** Will prefix generated queries with the Cypher version
* @example `CYPHER 5`
*/
Expand Down Expand Up @@ -85,11 +73,10 @@ export abstract class Clause extends CypherASTNode {

/** Compiles a clause into Cypher and params */
public build(config?: BuildConfig): CypherResult {
const { prefix, extraParams = {}, labelOperator = ":", cypherVersion, unsafeEscapeOptions = {} } = config ?? {};
const { prefix, extraParams = {}, cypherVersion, unsafeEscapeOptions = {} } = config ?? {};

if (this.isRoot) {
const env = this.getEnv(prefix, {
labelOperator,
cypherVersion,
unsafeEscapeOptions,
});
Expand All @@ -104,7 +91,7 @@ export abstract class Clause extends CypherASTNode {
}
const root = this.getRoot();
if (root instanceof Clause) {
return root.build({ prefix, extraParams, labelOperator, cypherVersion, unsafeEscapeOptions });
return root.build({ prefix, extraParams, cypherVersion, unsafeEscapeOptions });
}
throw new Error(`Cannot build root: ${root.constructor.name}`);
}
Expand Down
6 changes: 3 additions & 3 deletions src/expressions/HasLabel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ describe("HasLabel", () => {
const queryResult = new TestClause(query).build();

expect(queryResult.cypher).toMatchInlineSnapshot(`
"MATCH (this0:Movie)
WHERE this0:Movie:Film"
`);
"MATCH (this0:Movie)
WHERE this0:Movie&Film"
`);

expect(queryResult.params).toMatchInlineSnapshot(`{}`);
});
Expand Down
4 changes: 2 additions & 2 deletions src/expressions/HasLabel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ export class HasLabel extends CypherASTNode {
private generateLabelExpressionStr(env: CypherEnvironment): string {
if (Array.isArray(this.expectedLabels)) {
const escapedLabels = this.expectedLabels.map((label) => escapeLabel(label));
return addLabelToken(env.config.labelOperator, ...escapedLabels);
return addLabelToken(...escapedLabels);
} else {
return addLabelToken(env.config.labelOperator, this.expectedLabels.getCypher(env));
return addLabelToken(this.expectedLabels.getCypher(env));
}
}

Expand Down
8 changes: 2 additions & 6 deletions src/pattern/Pattern.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,7 @@ describe("Patterns", () => {
.to(b)
);
const queryResult = query.build();
expect(queryResult.cypher).toMatchInlineSnapshot(
`"(this0:Person:Actor { name: $param0, surname: $param1 })-[this1:ACTED_IN { roles: $param2 }]->(this2)"`
);
expect(queryResult.cypher).toMatchInlineSnapshot(`"(this0:Person&Actor { name: $param0, surname: $param1 })-[this1:ACTED_IN { roles: $param2 }]->(this2)"`);

expect(queryResult.params).toMatchInlineSnapshot(`
{
Expand Down Expand Up @@ -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(`{}`);
});
Expand Down
4 changes: 2 additions & 2 deletions src/pattern/labels-to-string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ function labelOrTypeToString(
escapeFunc: (s: string) => string
): string {
if (elements instanceof LabelExpr) {
return addLabelToken(env.config.labelOperator, elements.getCypher(env));
return addLabelToken(elements.getCypher(env));
} else {
const escapedLabels = asArray(elements).map((label: string | Expr) => {
if (typeof label === "string") {
Expand All @@ -54,6 +54,6 @@ function labelOrTypeToString(
}
});

return addLabelToken(env.config.labelOperator, ...escapedLabels);
return addLabelToken(...escapedLabels);
}
}
4 changes: 2 additions & 2 deletions src/references/Label.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export class Label extends CypherASTNode {
}

private generateLabelExpressionStr(env: CypherEnvironment): string {
return addLabelToken(env.config.labelOperator, escapeLabel(this.label));
return addLabelToken(escapeLabel(this.label));
}
}

Expand All @@ -77,7 +77,7 @@ export class DynamicLabel extends Label {
public getCypher(env: CypherEnvironment): string {
const nodeId = this.node.getCypher(env);
const exprStr = `$(${this.expr.getCypher(env)})`;
const labelStr = addLabelToken(env.config.labelOperator, exprStr);
const labelStr = addLabelToken(exprStr);
return `${nodeId}${labelStr}`;
}
}
22 changes: 11 additions & 11 deletions src/utils/add-label-token.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,24 @@

import { addLabelToken } from "./add-label-token";

describe.each([":", "&"] as const)("addLabelToken", (operator) => {
test("addLabelToken without labels using operator %s", () => {
const result = addLabelToken(operator);
describe("addLabelToken", () => {
test("addLabelToken without labels", () => {
const result = addLabelToken();
expect(result).toBe("");
});

test("addLabelToken with a single label using operator %s", () => {
const result = addLabelToken(operator, "Movie");
test("addLabelToken with a single label", () => {
const result = addLabelToken("Movie");
expect(result).toBe(":Movie");
});

test("addLabelToken with two labels using operator %s", () => {
const result = addLabelToken(operator, "Movie", "Film");
expect(result).toBe(`:Movie${operator}Film`);
test("addLabelToken with two labels", () => {
const result = addLabelToken("Movie", "Film");
expect(result).toBe(`:Movie&Film`);
});

test("addLabelToken with multiple labels using operator %s", () => {
const result = addLabelToken(operator, "Movie", "Film", "Video");
expect(result).toBe(`:Movie${operator}Film${operator}Video`);
test("addLabelToken with multiple labels", () => {
const result = addLabelToken("Movie", "Film", "Video");
expect(result).toBe(`:Movie&Film&Video`);
});
});
4 changes: 2 additions & 2 deletions src/utils/add-label-token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
*/

/** Generates a string with all the labels. For example `:Movie&Film` */
export function addLabelToken(andToken: ":" | "&", ...labels: string[]): string {
export function addLabelToken(...labels: string[]): string {
const firstLabel = labels.shift();
if (!firstLabel) return "";

const extraLabels = labels.map((label) => `${andToken}${label}`).join("");
const extraLabels = labels.map((label) => `&${label}`).join("");

return `:${firstLabel}${extraLabels}`;
}
48 changes: 0 additions & 48 deletions tests/build-config/label-operator.test.ts

This file was deleted.

2 changes: 1 addition & 1 deletion tests/issues/479.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ RETURN count(this1)"

expect(queryResult.cypher).toMatchInlineSnapshot(`
"WITH $param0 AS var0
MATCH (this1:$(var0):\`normal$Label\`:$($param1))
MATCH (this1:$(var0)&\`normal$Label\`&$($param1))
RETURN count(this1)"
`);

Expand Down