Migration to Cypher Builder 2
This page describes necessary steps and things to consider when migrating from Cypher® Builder 1.x to 2.0, as well as breaking changes that may affect projects using Cypher Builder.
The full, up to date changelog can be found in the Cypher® Builder changelog.
Patterns
Patterns have been reworked in version 1.x, and the old behavior have been removed in version 2.0.
Node shorthand removed from clauses
Clauses using patterns no longer accept a Cypher®.Node as a shorthand.
An explicit pattern must be provided:
Before:
const movieNode = new Cypher.Node();
const matchQuery = new Cypher.Match(movieNode)
Now:
const movieNode = new Cypher.Node();
const matchQuery = new Cypher.Match(
new Cypher.Pattern(movieNode)
);
This affects all clauses using patterns:
-
Cypher®.Match -
Cypher®.Create -
Cypher®.Merge
This also affects pattern comprehensions Cypher®.PatternComprehension.
Patterns no longer create a variable by default
Creating a pattern without options no longer adds variables to the generated Cypher®:
const pattern = new Cypher.Pattern()
Before:
(this0)
Now:
()
To add a variable, it must be passed when creating the pattern:
const movieNode = new Cypher.Node();
const pattern = new Cypher.Pattern(movieNode)
Patterns configuration
The following methods to configure the resulting pattern have been removed from Pattern:
-
.withoutLabels -
.withoutVariable -
.withProperties -
.withVariables -
.withoutType -
.withDirection -
.withLength
Instead, Patterns are now configured through objects in the constructor, as well as the related and to methods:
Before:
const a = new Cypher.Node({
labels: ["Person", "Actor"],
});
const aProperties = {
name: new Cypher.Param("Arthur"),
surname: new Cypher.Param("Dent"),
};
const b = new Cypher.Node();
const rel = new Cypher.Relationship({
type: "ACTED_IN",
});
new Cypher.Pattern(a)
.withProperties({a: new Cypher.Param("Example")})
.withoutVariable()
.related(rel)
.to(b)
Now:
const aProperties = {
name: new Cypher.Param("Arthur"),
surname: new Cypher.Param("Dent"),
};
const b = new Cypher.Node();
const rel = new Cypher.Relationship();
new Cypher.Pattern({ properties: aProperties, labels: ["Person", "Actor"] })
.related(rel, { type: "ACTED_IN"})
.to(b)
The generated Cypher®:
(:Person:Actor { name: $param0, surname: $param1 })-[this1:ACTED_IN]->(this2)
Note that labels and types are now defined in the pattern, not in the Node and Relationship classes.
Assign to path variable
The method assignToPath has been removed in the following clauses:
-
Match -
Merge -
Create
Instead, the method assignTo in Patterns must be used:
Before:
const pathVariable = new Cypher.Cypher.PathVariable()
new Cypher.Match(pattern).assignToPath(pathVariable).return(pathVariable);
Now:
const pathVariable = new Cypher.Cypher.PathVariable()
new Cypher.Match(pattern.assignTo(pathVariable)).return(pathVariable);
The generated Cypher®:
MATCH p = ()-[]-()
RETURN p
Node and relationship variables
Cypher®.Node and Cypher.Relationship no longer hold any data about labels, or types, making them more similar to Cypher.Variable.
To add labels or types, they must be passed to the Cypher®.Pattern instead of relying on Cypher.Node and Cypher.Relationship.
Before:
const a = new Cypher.Node({
labels: ["Person", "Actor"],
});
const b = new Cypher.Node();
const rel = new Cypher.Relationship({
type: "ACTED_IN",
});
new Cypher.Pattern(a)
.related(rel)
.to(b)
Now:
const a = new Cypher.Node();
const b = new Cypher.Node();
const rel = new Cypher.Relationship();
new Cypher.Pattern(a, { labels: ["Person", "Actor"] })
.related(rel, { type: "ACTED_IN"})
.to(b)
Renamed features
The following features where deprecated in favor of a different name with the same functionality. The deprecated features have been removed in version 2.0:
-
Cypher®.concatin favor ofCypher.utils.concat -
pointDistancein favor ofpoint.distance -
Merge.onCreatein favor ofMerge.onCreateSet -
Call.innerWithin favor ofCall.importWith -
cdcnamespace in favor ofdb.cdc-
db.cdc.current -
db.cdc.earliest -
db.cdc.query
-
-
rTrimandlTrimin favor ofrtrimandltrimrespectively
.build()
The options for .build() are now passed as a single object rather than parameters:
Before:
myClause.build(
"another-this",
{ myParam: "hello"},
{
labelOperator: "&"
}
);
Now:
myClause.build({
prefix: "another-this",
extraParams: {
myParam: "hello",
},
labelOperator: "&",
});
All parameters are optional, and build can still be called without parameters.
Remove support for fine-grained prefix
The first parameter "prefix" for the .build method in 1.x supports passing an object with the parameters params and variables for fine-grained control of what prefix to use in different kinds of variables.
This has been removed in 2.x, supporting only a string as global prefix:
No longer supported:
myClause.build({
variable: "var_prefix_",
params: "param_prefix_"
});
Instead, a single string can be used as prefix for both variables and parameters:
Now:
myClause.build({
prefix: "my-custom-prefix"
});
With
The method .with no longer adds new columns to the existing clause.
It always creates a new WITH statement instead.
Use the method .addColumns to add extra columns.
Before:
const withQuery = new Cypher.With(node);
withQuery.with(node);
withQuery.with("*");
Now:
const withQuery = new Cypher.With(node);
withQuery.with(node)
withQuery.addColumns("*");
The generated Cypher®:
WITH this0
WITH *, this0
RawCypher
Cypher®.RawCypher has been removed in favor of Cypher.Raw.
Update callback parameter
Cypher®.Raw no longer exposes a Cypher.Environment variable.
Instead, it provides an instance of Cypher®RawContext with a compile method to compile nested elements in custom cypher.
Before:
const releasedParam = new Cypher.Param(1999);
const rawCypher = new Cypher.Raw((env: Cypher.Environment) => {
const releasedParamId = env.compile(releasedParam); // Gets the raw Cypher for the param
const customCypher = `MATCH(n) WHERE n.title=$title_param AND n.released=${releasedParamId}`;
return customCypher;
});
Now:
const releasedParam = new Cypher.Param(1999);
const rawCypher = new Cypher.Raw((ctx: Cypher.RawCypherContext) => {
const releasedParamId = ctx.compile(releasedParam); // Gets the raw Cypher for the param
const customCypher = `MATCH(n) WHERE n.title=$title_param AND n.released=${releasedParamId}`;
return customCypher;
});
Note that the code itself has not changed, and just the type passed to Cypher®.Raw callback has been changed from Cypher.Environment to Cypher.RawCypherContext.
PatternComprehension
PatternComprehension no longer accept a node as an argument in the constructor.
Instead, use a pattern:
Before:
const node = new Cypher.Node();
const comprehension = new Cypher.PatternComprehension(node);
Now:
const node = new Cypher.Node();
const comprehension = new Cypher.PatternComprehension(new Cypher.Pattern(node));
.map
PatternComprehension no longer accepts a second argument for the map expression.
Instead, use the .map method:
Before:
const andExpr = Cypher.eq(node.property("released"), new Cypher.Param(1999));
https://github.com/neo4j/cypher-builder/blob/main/CHANGELOG.md
const comprehension = new Cypher.PatternComprehension(new Cypher.Pattern(node), andExpr)
Now:
const andExpr = Cypher.eq(node.property("released"), new Cypher.Param(1999));
const comprehension = new Cypher.PatternComprehension(new Cypher.Pattern(node)).map(andExpr);
Other breaking changes
These are breaking changes that may affect the behavior of projects when updating to Cypher® Builder 2.0.
Fix TypeScript typings for boolean operators
The typings for the following boolean operators have been fixed to better reflect the result of these functions when spread parameters are used:
-
Cypher®.and -
Cypher®.or -
Cypher®.xor
The following now returns the correct type Cypher®.Predicate | undefined.:
const predicates: Cypher.Predicate[] = [];
const andPredicate = Cypher.and(...predicates);
This change means that additional checks may be needed when using boolean operators:
const predicates = [Cypher.true, Cypher.false];
const andPredicate = Cypher.and(...predicates); // type Cypher.Predicate | undefined
Passing parameters without spread still returns a defined type.