Customize Cypher
This page describes how to customize Cypher® queries using Cypher Builder. Such a scenario could occur if you:
-
Need to embed Cypher strings into existing Cypher queries.
-
Use Cypher Builder within a larger Cypher query.
-
Need to use features that are not supported in the current version of the Cypher Builder.
-
Use custom functions or procedures.
Embedding custom Cypher in a query may lead to Code Injection and other security issues. |
Custom variable names
In most cases, Cypher Builder makes sure variable names are unique and do not collide.
However, in case you need to explicitly set names, you can use the Named*
variables:
new Cypher.NamedVariable("myVarName")
For more information, see Named variables.
Build Prefix
Though not recommended, you may need to mix multiple queries built with Cypher Builder into a single string. For example, this query:
const match1=new Cypher.Match(new Cypher.Pattern(new Cypher.Node(), { labels: ["Movie"] }))
const match2=new Cypher.Match(new Cypher.Pattern(new Cypher.Node(), { labels: ["Person"] }))
const cypher=`
${match1.build()}
${match2.build()}
`
Generates the following Cypher:
MATCH(this0:Movie)
MATCH(this1:Person)
In this query, the variable this0
is used for both MATCH
statements, thus causing variable name collision.
This happens because both queries (match1
and match2
) are built separately.
If merging these queries before executing .build()
(e.g. using Cypher.concat
) is not a viable solution, a "prefix" string can be passed to .build()
to avoid name collision:
const cypher=`
${match1.build("movie")}
${match2.build("person")}
`
In this case, the resulting Cypher looks like:
MATCH(movie_this0:Movie)
MATCH(person_this0:Person)
The prefix parameter in .build()
prepends the provided string to every variable, except named variables.
Custom parameters
Parameters are only generated if they are used in the query.
To add custom parameters, regardless of these being used or not, an object can be passed as a second parameter to .build
:
const clause = new Cypher.Return(new Cypher.Param("Hello"))
clause.build("", {
myParameter: "Hello World"
});
This generates the Cypher:
RETURN $param1
And the parameters:
{
"param1": "Hello",
"myParameter": "Hello World"
}
Custom parameter name
Similarly to variables, when defining a parameter this can be explicitly named by using the class NamedParam
instead of Param
.
For example, this query:
const movie = new Cypher.Node();
const matchQuery = new Cypher.Match(movie, { labels: ["Movie"]}).where(movie, { name: new Cypher.NamedParam("myParam") }).return(movie);
Generates the following query:
MATCH (this0:Movie)
WHERE this0.name = $myParam
RETURN this0
Note that $myParam
does not return as a param by .build()
.
To generate the parameter, pass a value in the same way as normal parameters:
const movie = new Cypher.Node();
const matchQuery = new Cypher.Match({movie, labels: ["Movie"] }).where(movie, { name: new Cypher.NamedParam("myParam", "Keanu Reeves") }).return(movie);
The resulting parameter is:
{
"myParam": "Keanu Reeves"
}
Custom functions and procedures
Cypher Builder provides some built-in functions and procedures, but it also supports custom ones, for instance when using plugins or creating User-defined functions.
Functions
Arbitrary function calls can be built using the Cypher.Function
class, for example:
new Cypher.Function("myFunc");
To learn more about creating custom functions go to here.
Procedures
In the case of arbitrary procedures, they can be defined with the class Cypher.Procedure
:
const myProcedure = new Cypher.Procedure("my-procedure");
The generated Cypher automatically adds the CALL
clause:
CALL my-procedure()
Parameters can then be passed as an argument to the constructor:
const myProcedure = new Cypher.Procedure("my-procedure", [new Cypher.Literal("Keanu"), new Cypher.Variable()])
CALL my-procedure("Keanu", var0)
Yield
Custom procedures may be followed by a YIELD
statement with the .yield
method:
const myProcedure = new Cypher.Procedure("my-procedure").yield("value");
CALL my-procedure() YIELD value
Unlike built-in procedures, however, this method doesn’t have TypeScript typings for the column names, so .yield
accepts any string.
More specific typings can be set in the Procedure
class:
new Cypher.Procedure<"columnA" | "columnB">("my-procedure")
Trying to use |
Void procedures
Some procedures cannot be used along with YIELD
as they do not return any values.
These can be defined with Cypher.VoidProcedure
:
const myProcedure = new Cypher.VoidProcedure("my-proc");
This can be used as any other procedure, except that the .yield
method is not available.
Reusing custom procedures
Custom procedures can be reused by wrapping them with a JavaScript function:
function myCustomProcedure(param1) {
return new Cypher.Procedure("my-custom-procedure", [param1])
}
This function can then be used in the same fashion as built-in procedures:
myCustomProcedure(new Cypher.Variable()).yield("column")
CALL my-custom-procedure(var0) YIELD "column"
Raw
The class Cypher.Raw
allows embedding a Cypher string within a larger query built with Cypher Builder.
It acts as a wildcard that can be used anywhere.
For instance, this query:
const customReturn = new Cypher.Raw(`10 as myVal`);
const returnClause = new Cypher.Return(customReturn);
const { cypher, params } = returnClause.build();
Returns the following Cypher:
RETURN 10 as myVal
In this case, the RETURN
clause is being generated by Cypher Builder, but the actual value 10 as myVal
has been injected with Raw
.
This string can be anything, including other clauses or invalid Cypher, and can be generated dynamically:
const returnVar="myVal"
const customReturn = new Cypher.Raw(`10 as ${returnVar}`);
const returnClause = new Cypher.Return(customReturn);
Additionally, Raw
can also be used in Cypher.concat
to attach an arbitrary string to any Cypher Builder element.
Using a callback
In more complex scenarios, you may need to access variables created with the Cypher Builder in your custom Cypher string.
However, these values are not available before executing .build
.
To achieve this, Raw
supports a callback that is executed while the query is being built, and has access to the variables.
This callback receives a parameter env
that can be used to manually compile Cypher Builder clauses and translate variable names.
It returns the following values:
-
string
: Cypher string to be used for this element. -
[string, object]
: a tuple with the first element being the Cypher string, and the second an object with the parameters to be injected in the query. -
undefined
: if undefined,Raw
will be translated as an empty string.
In this example, a MATCH…RETURN
statement is being created with Cypher Builder in the usual way.
However, a custom Raw
is being injected as part of the WHERE
subclause:
const movie = new Cypher.Node();
const match = new Cypher.Match(movie, { labels: ["Movie"] })
.where(
new Cypher.Raw((env) => {
const movieStr = env.compile(movie);
const cypher = `${movieStr}.prop = $myParam`;
const params = {
myParam: "Hello World",
};
return [cypher, params];
})
)
.return(movie);
const { cypher, params } = match.build();
This returns the following Cypher:
MATCH (this0:`Movie`)
WHERE this0.prop = $myParam
RETURN this0
And the following parameters:
{
"myParam": "Hello World"
}
The callback passed into Raw
is producing the string this0.prop = $myParam
.
To achieve this, it uses the utility method utils.compileCypher
and passes the variable movie
and the env
parameter, which then returns the string this0
.
Finally, the custom parameter $myParam
is returned in the tuple [cypher, params]
, ensuring that it is available when executing match.build()
.