decypher
v0.13.0
Published
A handful of cypher utilities for Node.js
Downloads
167
Maintainers
Readme
Decypher
decypher is a node.js library packing a handful of utilities to deal with cypher queries.
It includes the following:
- A Yesql-like query loader.
- A query builder.
- An expression builder.
- Miscellaneous helpers.
Installation
You can install decypher from npm likewise:
npm install decypher
or from github if you need the latest development version:
npm install git+https://github.com/Yomguithereal/decypher.git
Query loader
Query files
Write one or more cypher queries per file:
File containing a single query
// Any comments...
MATCH (n)-[r]-(t)
RETURN n,r,t LIMIT 100;
File containing multiple named queries
// name: first
// Retrieve book nodes
MATCH (b:Book)
RETURN b;
// name: second
// Retrieve vocabulary nodes
MATCH (v:Vocabulary)
RETURN v;
Decyphering
Just require decypher and use it to load your queries:
var decypher = require('decypher');
// Or to only load the relevant code
var decypher = require('decypher/loader');
// Loading a single query
decypher('./single-query.cypher');
>>> 'MATCH (n)-[r]-(t)\nRETURN n,r,t LIMIT 100;'
// Loading multiple named queries
decypher('./multiple-queries.cypher');
>>> {
first: 'MATCH (b:Book)\nRETURN b;',
second: 'MATCH (v:Vocabulary)\nRETURN v;'
}
// Loading a batch of files at once
decypher({
single: './single-query.cypher',
multiple: './multiple-queries.cypher'
});
>>> {
single: 'MATCH (n)-[r]-(t)\nRETURN n,r,t LIMIT 100;',
multiple: {
first: 'MATCH (b:Book)\nRETURN b;',
second: 'MATCH (v:Vocabulary)\nRETURN v;'
}
}
// Loading the content of a folder
// folder/
// - single.cypher
// - multiple.cypher
decypher('./folder');
>>> {
single: 'MATCH (n)-[r]-(t)\nRETURN n,r,t LIMIT 100;',
multiple: {
first: 'MATCH (b:Book)\nRETURN b;',
second: 'MATCH (v:Vocabulary)\nRETURN v;'
}
}
// Choosing a different extension when loading a folder
decypher('./path-to-queries-folder', 'cql');
Now that if what you want is only to parse cypher strings because you retrieved the files on your, own, you can alternatively use decypher.parse
.
Query builder
Note that this query builder is widely inspired by the query-builder package by @shesek but fixed and updated to support cypher's latest evolutions.
The result object of the builder is also made to match @thingdom node-neo4j specifications for the db.cypher
method.
var Query = require('decypher').Query;
// Or to only load the relevant code
var Query = require('decypher/query');
// Creating a query
var cypher = new Query()
.match('MATCH (n:Node)')
.where('n.title = {title}', {title: 'The best title'})
.return('n');
// Compiling to string
cypher.compile();
// or
cypher.toString();
>>> `MATCH (n:Node)
WHERE n.title = {title}
RETURN n;`
// Retrieving the query's parameters
cypher.params();
>>> {
title: 'The best title'
}
// Retrieving the query's statements as an array
cypher.statements();
>>> [
'MATCH (n:Node)',
'WHERE n.title = {title}',
'RETURN n'
]
// Retrieving all of the above at once
var {query, params, statements} = cypher.build();
// You can also alternatively interpolate the params into the query
// (Useful for debugging but unsafe!!!)
cypher.interpolate();
>>> `MATCH (n:Node)
WHERE n.title = "The best title"
RETURN n;`
// Note that multi words statements like `ORDER BY` have to be written in camel-case:
cypher.orderBy('n.title');
// You can also set a bunch of params at once
cypher.params({whatever: 'is needed'});
cypher.param('whatever', 'is needed');
// If you need to pass multiple query parts at once & separated by a comma
// just pass an array of strings instead of a single string.
cypher.create(['(a:Actor)', '(m:Movie)']);
>>> 'CREATE (a:Actor), (m:Movie)'
// You can also add arbitrary parts to the query if required
cypher.add('anything you want');
cypher.add('with {param}', {param: 'heart'});
// It's possible to directly pass an expression to the query builder:
cypher.where(Expression('a').or('b'));
>>> 'WHERE a OR b'
// It's also possible to pass a descriptive object that will build a
// relationship pattern using the `helpers.relationshipPattern` function:
cypher.match({source: 'a', target: 'b', identifier: 'r', direction: 'out'});
>>> 'MATCH (a)-[r]->(b)'
// Finally, you can segment your query for convenience
var cypher = new Query(),
start = cypher.segment(),
end = cypher.segment();
end.return('a');
start.match('(a:Actor)');
cypher.compile();
>>> `MATCH (a:Actor)
RETURN a;`
Special cases
FOREACH
query.foreach(
'name IN {names}',
'CREATE (c:Person, {name: name})',
{names: ['John', 'Elizabeth']}
);
// Using a sub query (params will be merged into the main query)
var subquery = new Query();
subquery.create('(c:Person, {name: name})');
query.foreach('name IN names', subquery, {names: [...]});
Expression builder
The expression builder lets you build where
expression easily:
var Expression = require('decypher').Expression;
// Or to only load the relevant code
var Expression = require('decypher/expression');
var expr = new Expression('a = b');
expr.and('c = d');
expr.compile();
// or
expr.toString();
>>> 'a = b AND c = d'
// Note that you can nest expressions:
var expr = new Expression('a = b');
expr
.or(Expression('c = d').and('e = f'));
expr.compile();
>>> 'a = b OR (c = d AND e = f)'
expr.isEmpty();
>>> false
Note that expressions can be directly fed to the Query builder.
Helpers
Escaping identifiers
var helpers = require('decypher').helpers;
// Or to only load the relevant code
var helpers = require('decypher/helpers');
helpers.escapeIdentifier('Complex `Identifier`');
>>> '`Complex ``Identifier```'
Escaping literal maps
var helpers = require('decypher').helpers;
// Or to only load the relevant code
var helpers = require('decypher/helpers');
helpers.escapeLiteralMap({
hello: 'world',
'complex key': 3
});
>>> '{hello: "world", `complex key`: 3}'
// Indicating parameter keys
helpers.escapeLiteralMap({
name: 'name',
number: 2
}, ['name']);
>>> '{name: {name}, number: 2}'
Building node patterns
var helpers = require('decypher').helpers;
// Or to only load the relevant code
var helpers = require('decypher/helpers');
// Possible options are:
// * `identifier`: a string
// * `label` or `labels`: a string or an array of strings
// * `data`:
// - if string, will produce a single parameter
// - if object, will stringify it
// * `paramKeys`: will be passed to escapeLiteralMap when stringifying data
helpers.nodePattern();
>>> '()'
helpers.nodePattern('n');
>>> '(n)'
helpers.nodePattern({
identifier: 'n',
label: 'Node'
});
>>> '(n:Node)'
helpers.nodePattern({
label: 'Node',
data: {title: 'Hello'}
});
>>> '(n:Node {title: "Hello"})'
helpers.nodePattern({
identifier: 'n',
data: 'paramName'
});
>>> '(n {paramName})'
helpers.nodePattern({
label: 'Chapter',
data: {title: 'title'},
paramKeys: ['title']
});
>>> '(:Chapter {title: {title}})'
Building relationship patterns
var helpers = require('decypher').helpers;
// Or to only load the relevant code
var helpers = require('decypher/helpers');
// Possible options are:
// * `direction`: "in" or "out"
// * `identifier`: a string
// * `type` or `types`: a string or an array of strings
// * `data`:
// - if string, will produce a single parameter
// - if object, will stringify it
// * `paramKeys`: will be passed to escapeLiteralMap when stringifying data
// * `source`: the source node (passed to the `nodePattern` function)
// * `target`: the target node (passed to the `nodePattern` function)
helpers.relationshipPattern();
>>> '--'
helpers.relationshipPattern('r');
>>> '-[r]-'
helpers.relationshipPattern({
direction: 'out',
identifier: 'r',
type: 'KNOWS'
});
>>> '-[r:KNOWS]->'
helpers.relationshipPattern({
direction: 'in',
types: ['PLAYS_IN', 'KNOWS']
});
>>> '<-[:PLAYS_IN|:KNOWS]-'
helpers.relationshipPattern({
direction: 'in',
identifier: 'r',
data: 'paramName'
});
>>> '<-[r {paramName}]-'
helpers.relationshipPattern({
type: 'KNOWS',
data: {since: 1975}
});
>>> '-[:KNOWS {since: 1975}]-'
helpers.relationshipPattern({
direction: 'out',
type: 'PLAYED_IN',
source: 'a',
target: {
identifier: 'm',
label: 'Movie'
}
});
>>> '(a)-[:PLAYED_IN]->(m:Movie)'
Building search patterns
Note that it will escape for query for regular expression use through the escape-regexp
module.
var helpers = require('decypher').helpers;
// Or to only load the relevant code
var helpers = require('decypher/helpers');
// Possible options are:
// * `flags` [`'ius'`]: Flags for the regular expression.
// * `partial` [`true`]: Should the match be partial (wrapped in `.*query.*`)?
helpers.searchPattern('john');
>>> '(?ius).*john.*'
helpers.searchPattern('john', {flags: 'im'});
>>> '(?im).*john.*'
helpers.searchPattern('john', {flags: null, partial: false});
>>> 'john'
Contribution
Contributions are of course more than welcome. Be sure to add and pass any relevant unit tests before submitting any code.
git clone [email protected]:Yomguithereal/decypher.git
cd decypher
# Installing dependencies
npm install
# Running unit tests
npm test
Roadmap
- Some helpers
- A batch