fluent-cypher

0.9.2 • Public • Published

Fluent Cypher

This package allows you to build any cypher query you like and get both the query string and the parameters as an object to be used with the official neo4j driver.

If you want to be able to connect seamlessy to your Neo4j instance have a look at fluent-neo4j otherwise you can always use this package with your own driver/connector.

What is Cypher

This guide explains the basic concepts of Cypher, Neo4j’s query language.

Following the official documentation it is always better to avoid literals so everything is treated as a parameter.

Table of Contents

Usage

const CypherQuery = require('fluent-cypher');
//or
import CypherQuery from 'fluent-cypher'
 
var query = new CypherQuery();
 
query.match({$: 'node'}, ['code', {type: 'KNOWS', direction: 'left'}, {}])
.where({$: 'node', value: {'<=': 25}}, 'OR', {$: 'node', value: 28})
.return({$: 'node', as: 'myValue')
.orderBy('myValue')
.limit(5)
 
/*
query.log() =>
MATCH (node), (code)<-[]-()
WHERE node.value <= 25 OR node.value = 28
RETURN node AS myValue
ORDER BY myValue
LIMIT 5
 
 
query.queryString => "MATCH (node), (code)<-[]-() WHERE node.value <= {value1} OR node.value = {value2} RETURN node AS myValue ORDER BY myValue LIMIT 5"
 
query.queryParams => {value1: 25, value2: 28}
*/

constuctor([config])

Option Type Description
onCreateSetTimestamp Boolean timestamps will be added for you like node.createdAt = timestamp()
onUpdateSetTimestamp Boolean timestamps will be added for you like node.updatedAt = timestamp()
userId String Property will be set like node.createdBy = {userId} and node.updatedBy = {userId}
defaultNodeProps Object default props for every node
forcetNodeProps Object force props for every node
defaultRelProps Object default props for every relationship
forcetRelProps Object force props for every relationship

Building the query

.create(Pattern[, Pattern])

See Pattern for accepted arguments

query.create("(node)", "()->[rel]->()") //CREATE (node), ()->[rel]->()
query.create({$: 'node1', prop: false}, {$: 'node2', val: 12}) //CREATE (node1{prop:false}), (node2{val:12})
query.create([{$: 'parent'}, {type: 'has'}, {$: 'child'}]) // 'CREATE (parent)-[:has]->(child)'

.match(Pattern[, Pattern])

See Pattern for accepted arguments

query.match("(node)") // MATCH (node)
query.match("(node)", "()->[rel]->()") // MATCH (node), ()->[rel]->()
query.match({$: 'node1', prop: false}, {$: 'node2', val: 12}) //MATCH (node1{prop:false}), (node2{val:12})
query.match([{$: 'parent'}, {type: 'has'}, {$: 'child'}]) // 'MATCH (parent)-[:has]->(child)'

.optionalMatch(Pattern[, Pattern])

See Pattern for accepted arguments

query.optionalMatch("(node:Stuff)") // MATCH OPTIONAL (node:Stuff)

.where(WhereItem[, WhereItem])

query.where({$: 'user', fullName: {'=~': `(?i).*tom.*`}})
// WHERE user.fullName =~ (?i).*tom.*

.merge(Pattern[, Pattern])

See Pattern for accepted arguments

query.merge("(node)") // MERGE (node)
query.merge("(node)", "()->[rel:`type`]->()") // MERGE (node), ()->[rel:`type`]->()

.set(PropItem[, PropItem])

query.set('friend.rating = 5') // SET friend.rating = 5
query.set({
    $: 'friend', 
    labels: ['lol', 'lel'], 
    wow: '$rating' // <= access the variable with $
}) // SET friend:lol:lel, friend.wow = rating

.onCreateSet(PropItem[, PropItem])

query.onCreateSet('friend.rating = 5') // ON CREATE SET friend.rating = 5

.onMatchSet(PropItem[, PropItem])

query.onCreateSet('friend.rating = 5') // ON MATCH SET friend.rating = 5

.remove(PropItem[, PropItem])

query.remove({
    $: 'p', 
    prop: 't', 
    props: ['lel', 'lol'],
    label: 'one',
    labels: ['may', 'april']
})
// REMOVE p:one:may:april, p.t, p.lel, p.lol

.delete(DeleteItem[, DeleteItem])

query
    .match({$: 'lonely'})
    .where('NOT', ['lonely', {type: 'has'}, {label: 'Friend'}])
    .delete({$: 'lonely'}) 
/*
MATCH (lonely)
WHERE NOT (lonely)-[:has]->(:Friend)
DELETE friend
*/

.detachDelete(DeleteItem[, DeleteItem])

query
    .match(['me', ':knows', {$: 'friend'})
    .detachDelete('friend') 
/*
MATCH (me)-[:knows]->(friend)
DETACH DELETE friend
*/

.return(ReturnItem[, ReturnItem])

query.return('*') // RETURN *
query.return('node') // RETURN node
query.return('node.prop') // RETURN node.prop
query.return({$: 'node', prop: 'p', as: 'that'}) // RETURN node.p as that

.returnDistinct(ReturnItem[, ReturnItem])

query.returnDistinct('*') // RETURN DISTINCT *

.limit(Integer)

query.limit(1) // LIMIT 1

.skip(Integer)

query.skip(1) // LIMIT 1

.orderBy(Integer)

query.orderBy({$: 'node', key: 'ASC'}) // ORDER BY node.key ASC

.unwind(UnwindItem)

query.unwind(['[1,2,3] as number') //UNWIND [1,2,3] as number
query.unwind({$: [1,2,3], as: 'number'}) //UNWIND [1,2,3] as number (parameterized)
query.unwind({$: 'collection', as: 'list'}) //UNWIND collection as list
query.unwind({$: '$param', as: 'entry'}) //UNWIND $param as entry

.with(AliasedItem[, AliasedItem])

query.with('this as that', {$: 'node', as: 'something'}) 
//WITH this as that, node AS something

.union()

query.union()
//UNION

.unionAll()

query.unionAll()
//UNION ALL

.loadCsv(url, options)

q.loadCsv('https://neo4j.com/docs/cypher-refcard/3.2/csv/artists.csv', {as: 'row', withHeaders: false})
//LOAD CSV FROM "https://neo4j.com/docs/cypher-refcard/3.2/csv/artists.csv" AS row

.call(string)

q.call('dbms.procedures()')
//CALL dbms.procedures()

.yield(string)

q.yield('name, signature')
//YIELD name, signature

Argument Types

Pattern

As String see Cypher

As Object see Node

As Array see Path

Cypher

String only

This is not manipulated at all and gets inserted in the context as is

'node' //(node) if in node context
'rel:type' //...-[rel:type]->... if in rel context
'CASE WHEN 1=1 THEN this ELSE that END as what' //CASE WHEN 1=1 THEN this ELSE that END as what

Node

As String

see Cypher

As Object

Key Required Type Description
$ no String Variable name for node (must be valid variable name)
label no String Label for node
labels no Array Label for node
...rest no String Arrray
{
    $: 'node', 
    label: 'Cat', 
    labels: ['Animal', 'Living'], 
    this: 'that',
    something: ['li', 'la']
} //(node:Cat:Animal:Living)

Rel

As String

Interpreted as Cypher

As Object

Props

Key Required Type Description
$ no String Variable name for rel (must be valid variable name)
type yes (in merge) String Type of rel
depth no Integer|String Eiter * or 4 or 1..2
direction no String Eiter left or right (default) or both
...rest no String|Arrray Actual properties of the rel

Example

{
    $: 'rel', 
    type: 'Follows', 
    depth: '..5',
    direction: 'both',
    something: ['amigo']
} //...)-(rel:Follows*..5{something:['amigo']})-(...

Path

As Array

If the number of elements is even, the first Object is used for Path options

Props

Key Required Type Description
$ no String Variable name for path (must be valid variable name)
shotestPath no Bool Whether to use the shortestPath or not

Example

[
    { $: 'myPath', shotestPath: true },
    { $: 'start' },
    {},
    'final'
] // myPath = shortestPath((start)-[]->(final))

.log()

As query.queryString is a parametrised string you may want to print a string that you can copy and paste in the browser console.

 
query
    .match('(node)')
    .log()     // => MATCH (node)
    .match('()-[rel]->()')
    .log()    // => MATCH (node) MATCH ()-[rel]->()
 

Test

Tests are written in ava, run the following command

npm t

Package Sidebar

Install

npm i fluent-cypher

Weekly Downloads

11

Version

0.9.2

License

UNLICENCED

Unpacked Size

47.2 kB

Total Files

40

Last publish

Collaborators

  • orlandogroppo