npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

fluent-cypher

v0.9.2

Published

Builds parametrized Cypher queries, with a fluent API

Downloads

65

Readme

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 | Other properties for the node |

{
	$: '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