Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
@neo4j/cypher-builder
Advanced tools
This is an internal utility to build Cypher queries, part of @neo4j/graphql
. This is only intended for internal usage and it is not feature complete.
Note that this is still under development.
const idParam = new Cypher.Param("my-id"); // Defines a new parameter to be passed to the query
const movieNode = new Cypher.Node({
// Defines a reference to a node
labels: ["Movie"],
});
// CREATE statement to create the given node, and set some properties
const createQuery = new Cypher.Create(movieNode).set({ id: idParam }).return(movieNode);
const { cypher, params } = createQuery.build(); // Compiles the cypher and parameters
In this example, cypher
will be a string containing the following:
CREATE (this0:\`Movie\`) # Create statement, this0 is an autogenerated variable for the node
SET this0.id = $param0 # Sets parameter
RETURN this0
params
will contain the parameters used in that query as an object:
{
"param0": "my-id",
}
You can find usage examples in the examples
folder.
CypherBuilder uses a subset of Cypher Syntax.
Clauses are the main entry point to create a new Cypher query. A clause will expose the build() method, that will trigger the Cypher string and parameters generation.
Each clause will take care of generating its own Cypher, as well as composing its children components Cypher. Most clauses support the use of a builder pattern to attach other clauses and sub-clauses.
The available Clauses are:
Most clauses support subclauses, these can be used after the main clause, but not by itself. SubClauses behave exactly like clauses, but do not have the build method and cannot be instantiated directly.
CALL
block. Not to be confused with top-level WITH clause.Top level clauses can be concatenated, one after the other, to make a new composite clause from multiple clauses.
For instance:
const compositeClause = Cypher.concat(matchClause, matchClause2, returnClause);
Could be used to generate a query with 3 top-level clauses like:
MATCH(this0:Movie)
MATCH(this1:Movie)
RETURN this0, this1
The following procedures can be used as clauses:
In some cases, it may be necessary to integrate a custom string inside the cypher query. Instead of composing the AST result and the custom string. The class RawCypher
can be used to create a custom clause of the AST that will take care of transforming the raw string into a valid AST node. Another advantage is that this RawCypher will have access to the environment, allowing to inject variables and cypher generated by the CypherBuilder into the raw string. A RawCypher instance accepts a single callback, that will be executed when .build()
is called in the AST. This callback accepts the Environment and returns a pair of the cypher string to be composed and all the parameters that need to be added to the Environment.
const rawCypher = new Cypher.RawCypher((env: CypherEnvironment) => {
return ["MATCH (n {title: $my_title})", {my_title: "Matrix}];
});
Variables will hold references to Cypher variables, parameters and literal values. Variables can be reused in different parts of the query and the instance reference will be maintained when translated into different ids in the query.
All clauses, operations and functions are elements of the Abstract Syntax Tree, variables, however, can be reused and as such live separately of the AST. Whenever a variable is used when generating the Cypher, the Environment will keep track of it, and turn it into an appropriate id to be injected into the Cypher. Variable ids are usually arbitrary values and are generated when the Cypher query is being built.
The are different types of variables:
new Cypher.Node({labels: ["Movie"]})
.
new Cypher.NamedNode("this_movie", {labels: ["Movie"]})
.new Cypher.Relationship({type: "ACTED_IN", source: actorNode, target: movieNode})
.params
result, and an arbitrary id will be used in the cypher query.
WITH $param as var1
).
count(*) > 1
).
null
value, that needs to be rendered differently.All variables may contain properties (e.g. this.name
). These properties can be referenced with .property
and allows for unique reference of a variable property within a statement, like a WHERE
statement regardless of the variable id:
const movieNode = new Cypher.Node(labels: ["Movie"]);
movieNode.property("title"); // Will be translated to this0.title
Expressions are a conglomeration of entities that can be used in several places, an expression can be an operation, function, variable or some clauses such as exists. Most operators and functions support expressions as their input. The Expression type can be accessed with Cypher.Expr
. These include functions, variables, comprehensions among others.
Expressions can be used in RETURN
WITH
and SET
statements among other places.
Some expressions are predicates, these expressions return a boolean value, and can be used in where filters, the type Cypher.Predicate
contains all of these. These include:
Exists behaves similarly to a top-level clause, however it cannot be built directly and can only be used in certain subclauses or as part of some operations.
Expressions can contain either a ListComprehension
or a PatternComprehension
CASE ... WHEN
can be used.
Some clauses support the use of operators. For example, the where statement:
const movieNode = new Cypher.Node(labels: ["Movie"]);
const title1Param = new Cypher.Param("The Matrix");
const title2Param = new Cypher.Param("John Wick");
const movieTitle = movieNode.property("title");
// Match all movies with title the Matrix or JohnWick
new Cypher.Match(movieNode).where(
Cypher.or(
Cypher.eq(movieTitle, titleParam),
Cypher.eq(movieTitle, title2Param)
)
)
The are different kind of operations, and only certain kind of operators can be used in each place, all operators can be used in an Expression:
Comparison operators can be used in the top level of a where
clause (e.g. WHERE this.name="The Matrix"
) or inside a boolean operator (e.g. WHERE (this.name="The Matrix" AND this.released=1999)
). All comparison operators accept expressions.
Binary Operators
Unary operators
Note that some operators (in, contains ...) are not comparison operators in Cypher, but can be treated as such.
Boolean operators can be used in the top level of a where
clause (e.g. WHERE ... AND ...
), as part of a comparison operation or inside another Boolean operator. Boolean operators only accept other boolean operators, comparison operators, or an Exists
clause.
Binary Operators
Note that binary boolean operators will wrap themselves in parenthesis (foo AND bar)
). These operators also support more than 2 parameters (foo AND bar AND fizz)
Unary Operators
Can be used inside an Expression and accept other expressions:
Functions can be used in expressions, each function has a name and a certain number of arguments:
List functions take a list as input
These are functions that can be used as predicates:
This section describes some of the mechanism on how the CypherBuilder works under the hood.
The CypherASTNode is an internal abstract class that it is extended by all the elements that compose a Cypher query, with the exception of variables. This class implements the AST tree as an spaghetti stack, in which all nodes point to the parent. Children need to be handled by each subclass (like Clauses or Functions) as each class will need a different set of children. This class also implements the mechanism for tree traversal and modification.
Each concrete implementation of a CypherASTNode
needs to implement the method getCypher
, that handles the Cypher generation of that node, and calls the children getCypher
if needed.
The abstract class Clause
extends a CypherASTNode, and provides the method build
, which generates a new CypherEnvironment
and triggers the root node getCypher
method.
A new environment will be created each time an AST node calls the build
method. The environment keeps track of the variable references and their id. The environment needs to be passed to every getCypher
method, only the variables (and some edge cases, such as RawCypher) actually need to access the environment. Variables can be compiled to cypher with getCypher
as well.
Behind the scenes, Match, Create and Merge statements use the Pattern
class to compile the node or relationship reference. Patterns describe exactly how a certain node or relationship must be rendered (e.g. (this0:Movie)
vs (this0)
). Usually Patterns do not need to be used directly, but if needed these can be manually instanced and passed to the clauses instead of nodes and relationships.
Cypher grammar is complex, this is a simplified definition, used as a template of the CypherBuilder architecture. This grammar is not complete nor formal, but can give a good overview:
Clause: <Match> | <Return> | <Call> | <With> | <Merge>
-- Match: MATCH <Pattern> (<Where>? | <Set>?)
-- Return: RETURN <Projection> <OrderBy>?
-- Call: CALL { <ImportWith> <Clause> }
-- With: WITH <Projection>
-- Merge: MERGE <Pattern> (<OnMatch>? | <onCreate>?)
# Subclauses
-- Where: WHERE (<BooleanOp> | <ComparisonOp>)
-- Set: SET <PropertyRef> = <Expr>
-- OnCreate: ON CREATE <PropertyRef> = <Expr>
-- OnMatch: ON MATCH <PropertyRef> = <Expr>
-- OrderBy: ORDER BY <PropertyRef> (ASC | DESC)?
-- ImportWith: WITH <Projection> # Different to top-level WITH
Variable: <Param> | <NodeRef> | <RelationshipRef> | <Literal>
-- NodeRef: [NodeId] # A variable created from a node reference
-- RelationshipRef: [RelId] # A variable created from a Relationship reference
-- Literal: [LiteralValue]
-- Param: $[paramId]
PropertyRef: <Variable>.[path] # Example: this.name, this.node.potato
Operations
-- BooleanOp: (<BooleanOp> | <ComparisonOp>)? + (AND | OR | NOT) (<BooleanOp> | <ComparisonOp>)
-- ComparisonOp: <Expr> (IS NOT, =, <, IS NULL, STARTS WITH...) <Expr>
-- MathOp: <Expr> (+|-|/|*) <Expr>
Pattern
-- NodePattern: (<NodeRef>?:<Labels>? <Map>?)
-- RelationshipPattern: <NodePattern>-[RelationshipRef?:Type? <Map>]-<NodePattern>
Projection: (Expr (as <Variable>)?)+
Function: <name>(Expr)
List: [1,2..] | <ListComprehension> | <PatternComprehension>
-- ListComprehension: [<Variable> IN <List | Function> WHERE (<BooleanOp> | <ComparisonOp>) | <Expr> ] # [x IN range(0,10) WHERE x % 2 = 0 | x^3 ]
-- PatternComprehension: [<Pattern> WHERE (<BooleanOp> | <ComparisonOp>) | <Expr>] # [(a)-->(b:Movie) WHERE b.title CONTAINS 'Matrix' | b.released]
Map: {[key]: [Expr]}
Expr: PropertyRef | Variable | Function | Operations | Literals | List | Map
FAQs
A programmatic API for building Cypher queries for Neo4j
The npm package @neo4j/cypher-builder receives a total of 18,556 weekly downloads. As such, @neo4j/cypher-builder popularity was classified as popular.
We found that @neo4j/cypher-builder demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.