Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@neo4j/cypher-builder

Package Overview
Dependencies
Maintainers
7
Versions
69
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@neo4j/cypher-builder

Neo4j Cypher query builder

  • 0.1.3
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
19K
increased by15.14%
Maintainers
7
Weekly downloads
 
Created
Source

Cypher Builder - Beta

A programatic API for building Cypher queries for Neo4j.

Note that this is still under development.

Getting Started

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",
}

Examples

You can find usage examples in the examples folder.

API Reference

CypherBuilder uses a subset of Cypher Syntax.

Clauses

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:

  • Match
  • Create
  • Merge
  • Return
  • With
  • Call
  • Unwind
  • Union

SubClauses

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.

  • Set
  • Where
  • OnCreate
  • With: Import with at the beginning of a CALL block. Not to be confused with top-level WITH clause.
  • OrderBy
    • Skip
    • Limit
  • Delete
  • Remove

Concat

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

Procedures

The following procedures can be used as clauses:

  • db.FullTextQueryNodes: Similar to Match, can be used for FullText queries.

RawCypher

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

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:

  • NodeRef: Holds the reference to a node and its labels. Can be created with new Cypher.Node({labels: ["Movie"]}).
    • NamedNode: In some cases, the name of the node needs to be pre-defined, for these cases, it can be done with new Cypher.NamedNode("this_movie", {labels: ["Movie"]}).
  • RelationshipRef: Holds a reference to a relationship: new Cypher.Relationship({type: "ACTED_IN", source: actorNode, target: movieNode}).
  • Param: Params behave like any variable, however, its value will be pushed to the params result, and an arbitrary id will be used in the cypher query.
    • NamedParam Like with nodes, in some cases a param may already exists, and a reference to it needs to be made.
  • Variable: A plain value that does not hold any value at compile time,can be used to reference new variables created in the cypher (e.g. WITH $param as var1).
    • NamedVariable: For keeping track of variables that already exist in the Cypher strings.
  • Literal: Will get translated to a literal value in the Cypher. Useful for static values (e.g. count(*) > 1).
    • Null: A literal holding the null value, that needs to be rendered differently.

Properties

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

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.

Predicates

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

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.

List

Expressions can contain either a ListComprehension or a PatternComprehension

Case

CASE ... WHEN can be used.

Operations

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

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

  • eq
  • gt
  • gte
  • lt
  • lte
  • in,
  • contains
  • startsWith
  • endsWith
  • matches

Unary operators

  • isNull
  • isNotNull

Note that some operators (in, contains ...) are not comparison operators in Cypher, but can be treated as such.

Boolean

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

  • and
  • or

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

  • not

Math

Can be used inside an Expression and accept other expressions:

  • plus
  • minus

Functions

Functions can be used in expressions, each function has a name and a certain number of arguments:

  • coalesce(...exprArgs)
  • point(expr)
  • distance(expr, expr)
  • labels(nodeRef)
  • datetime()
  • count(expr)
  • min(expr)
  • max(expr)
  • avg(expr)
  • sum(expr)

List Functions

List functions take a list as input

  • size(expr)
  • collect(expr)
  • head(expr)
  • last(expr)

Predicate Functions

These are functions that can be used as predicates:

  • any
  • all
  • single
  • exists

Under the hood

This section describes some of the mechanism on how the CypherBuilder works under the hood.

CypherASTNode

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.

Clauses

The abstract class Clause extends a CypherASTNode, and provides the method build, which generates a new CypherEnvironment and triggers the root node getCypher method.

Environment

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.

Patterns

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.

Pseudo Grammar

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

Keywords

FAQs

Package last updated on 01 Nov 2022

Did you know?

Socket

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.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc