rainbird-neo4j
v0.4.3
Published
Thin wrapper around the Neo4j REST interface
Downloads
1,163
Readme
Rainbird Neo4j
Thin wrapper around the Neo4j Transactional Cypher HTTP REST endpoint that adds the ability to perform client side substitutions in queries. It also returns results in a slightly saner fashion than the raw endpoint.
rainbird-neo4j
makes use of Neo4j 2.x
features and will not provide legacy
support for Neo4j 1.x
.
Note: This driver doesn't provide support to change passwords. You will need to alter the default password using the web console before you can connect to an instance that requires authentication.
Installation
npm install --save rainbird-neo4j
Basic Usage
var Neo4j = require('rainbird-neo4j');
var db = new Neo4j('http://localhost:7474', username, password);
db.query('MATCH (n) RETURN n', function(err, results) {
if (err) {
console.log(err);
} else {
console.log(JSON.stringify(results, null, 4));
}
});
If your Neo4j instance doesn't use authentication then username
and password
can be omitted when creating the Neo4j object:
var db = new Neo4j('http://localhost:7474');
Queries
All functions that can perform queries accept them in the same format. At its most basic a query is just a query string. A query string can also be presented as an array of strings. These will be concatenated into a single query string.
Providing a parameters object with the query string allows for queries with parameters. See the Neo4j documentation on parameters for more details on the parameters object.
Providing a substitutions object with the query string allows for substitutions to be performed on the query string. Note: If only one object is passed to a query it's assumed to be a parameters object.
Multiple queries can be run from a single function call by providing them as
statements. Statements do not support
substitutions. Use the [compose](#compose)
function if you
need a to perform substitutions on elements in a statements object.
Statements
Statements are an array of statement objects which themselves contain a
statement
property and a parameters
property. statement
is any valid
Cypher statement. parameters
is a parameters object.
Client Side Parameters (Substitutions)
Client side parameters, or substitutions, are simply a convenience mechanism that allow complex query strings to be reused within the code by use of substitutions. Substitutions do not provide the performance gains that normal parameters give as they are parsed out before being sent to Neo4j.
Substitutions are defined in the query string using the format ${var}
. The
substitution will be replaced with the value of var
in the substitutions
object.
For example, the following code:
var template = `MATCH (:${foo} {value: {value}})`;
var substitutions = { 'foo': 'Baz'};
var parameters = { 'value': 'bar' };
neo4j.query(template, substitutions, parameters, callback);
Will pass the following statement object to Neo4J:
[{
"statement": "MATCH(:Baz {value: {value}})",
"parameters": { "value": "bar" }
}]
Warning: substitutions should be used with care as they can leave you open to injection attacks. Always be sure you're passing in known strings.
Transactions
Queries are always run within the context of a transaction. Where transactions are not explicitly stated the queries will be wrapped in a begin and commit. Any errors will cause the transaction to rollback.
For transactions that span multiple function calls a call to begin
will open
a transaction and return a transaction ID. This is then used to run multiple
queries before commit
or rollback
are called. Both begin
and commit
can
also run queries.
Transactions time out after a period of time. The timeout is reset each time a call is made on that transaction. An empty query can be used to reset the timeout.
Callback
All functions that take a callback expect it to be in the form:
callback(err, results, info)
If err
is set then results
will be an empty array.
Results format
Results are returned as a list containing one element per query run. Each individual result in this list is itself a list of rows returned. Each row is an object containing the column names as properties and the row data as objects.
For example, if you run the following query as a single statement:
CREATE (foo:Foo {name: 'baz'})
SET foo.type = 'String'
CREATE (bar:Bar {name: 'baz'})
SET bar.type = 'String'
RETURN foo, bar
Will return the result:
[
[
{
"foo": {
"name": "baz",
"type": "String"
},
"bar": {
"name": "baz",
"type": "String"
}
}
]
]
If you run the two following queries as separate statements:
CREATE (foo:Foo {name: 'baz'}) RETURN foo
CREATE (bar:Bar {name: 'baz'}) RETURN bar
You will get the result:
[
[
{
"foo": {
"name": "baz"
}
}
],
[
{
"bar": {
"name": "baz"
}
}
]
]
With the more complex query:
CREATE ({name: 'subject'})-[:R {name: 'relationship'}]->({name: 'object'})
MATCH (s)-[r]-(o) RETURN s, r, o
You will get the result:
[
[],
[
{
"s": { "name": "object" },
"r": { "name": "relationship" },
"o": { "name": "subject" }
},
{
"s": { "name": "subject" },
"r": { "name": "relationship" },
"o": { "name": "object" }
}
]
]
Info Format
The info
object will contain any extra information returned by the function
and will vary depending on the exact context.
The statements
parameter will always be set and will contain the
statements sent to Neo4j.
The errors
parameter will contain an array of any errors returned by Neo4j. If
no errors occurred then this list will be empty.
The timeout
parameter is only set if begin
, or query
within the context of
a transaction has been called. It contains the datetime stamp when the
transaction will time out. See the Neo4j REST documentation for more
details on the timeout.
The transactionID
parameter is only set in the context of a transaction and
contains the current transaction ID. This is set by a call to begin
.
Functions
All functions that accept a queryString
will also accept an array of query
strings. These will be concatenated into a single query and composed into a
statement. If a substitutions object is provided then
substitutions will also be performed. If
substitutions are requires for statements the
compose
function should be used.
begin
Begin a transaction and optionally run a query in that transaction. The returned transaction ID should be used for all future calls involving the transaction.
begin(callback)
begin(queryString, callback)
begin(queryString, parameters, callback)
begin(queryString, substitutions, parameters, callback)
begin(statements, callback)
query
Run a query, either as a single transaction, or part of a larger transaction.
query(queryString, callback)
query(queryString, parameters, callback)
query(queryString, substitutions, parameters, callback)
query(statements, callback)
query(transactionID, callback)
query(transactionID, queryString, callback)
query(transactionID, queryString, parameters, callback)
query(transactionID, queryString, substitutions, parameters, callback)
query(transactionID, statements, callback)
The signature query(transactionID, callback)
is provided as a convenience
function to reset the timeout on a transaction. It will pass an empty set of
statements to Neo4j and is the equivalent of
query(transactionId, [], callback)
commit
Commit an open transaction, optionally running a query before the transaction is closed.
commit(transactionID, callback)
commit(transactionID, queryString, callback)
commit(transactionID, queryString, parameters, callback)
commit(transactionID, queryString, substitutions, parameters, callback)
commit(transactionID, statements, callback)
rollback
Rollback an existing transaction. rollback
will always return an empty result
set.
rollback(transactionID, callback)
resetTimeout
Reset the timeout on a transaction without performing a query. Synonym for
query(transactionID, callback)
.
resetTimeout(transactionID, callback)
compose
The compose
function is a helper function that will construct a valid
statement object for inclusion in an array of statements.
It also allows for the use of substitutions.
compose(queryString, callback)
compose(queryString, parameters, callback)
compose(queryString, substitutions, parameters, callback)
escape
Identifiers in Neo4j follow the following basic rules:
- case sensitive
- can contain underscores and alphanumeric characters (
[a-zA-Z0-9_]
) - must always start with a letter. (
[a-zA-Z]+[a-zA-Z0-9_]*
)
More complex identifiers can be quoted using backtick (`) characters. Backticks themselves can be escaped using a backtick. Identifiers can be easily escaped using:
var identifier = Neo4j.escape('a complex identifier`);
Testing
The package can be tested using:
npm test
This runs the linter, unit tests and creates the docco
documentation along
with coverage reports and plato
reports.
To perform full functional tests that connect to a test Neo4j instance that can be cleared down after each test run:
export NEO4J_TEST_URL=http://localhost:4747
export NEO4J_TEST_USERNAME=neo4j
export NEO4J_TEST_PASSWORD=password
npm run-script functional-test
Replace http://localhost:4747
and the authentication details with the URL and
login credentials of your test Neo4j instance.
Note: the functional tests clear everything in the test database. Please use a stand alone test DB for functional testing.
Functional testing with Docker
The best method of providing a test Neo4j instance for functional testing is by running a throwaway instance in Docker. To run:
docker run -i -t -d --name neo4j --privileged -p 7676:7474 tpires/neo4j
Here the port mapping has been changed from 7676
to 7474
which allows the
Docker instance to live on the same machine as a local instance. You can adjust
7676
to point to any port, potentially running more than one Docker instance
by providing a different name to the docker
command.
You can now expose this to the functional tests using:
export NEO4J_TEST_URL="http:${DOCKER_IP}:7676"
export NEO4J_TEST_USERNAME=neo4j
export NEO4J_TEST_PASSWORD=password
npm run-script functional-test
The Docker instance can now be stopped and deleted if it's no longer needed.
Release Notes
v0.4.3
- [Misc] Updates dependencies and node version
v0.4.2
- [Misc] Updates dependencies to latest
v0.4.1
- [Misc] Minor code enhancement
v0.4.0
- [New] Driver now supports authentication and Neo4j 2.2.
v0.3.1
- [Misc] Lock down node version in
package.json
to avoid problems in the latest version of node and npm.
v0.3.0
- [Misc] Improve error messages for debugging without the
info
object. - [Misc] Errors do not occur at the same index as statements in the
info
object so removed this assertion from the README. - [Misc] Improve documentation for
compose
- [Misc] Add note about Neo4j 2.2 authentication
v0.2.3
- [Misc] Update package dependencies.
- [Misc] Minor cleanup on the README.
v0.2.2
- [Fix] Handle the case when a response is parsed without a body.
- [Fix] Neo4j URLs can now have trailing slashes
v0.2.1
- [Misc] Add warning about substitutions and injection attacks.
v0.2.0
- [New] Transactions over multiple function calls using begin/commit/rollback.
- [New] The statements passed to Neo4j are now returned as part of the callback.
- [New]
buildStatement
andescapeIdentifier
have been replaced withcompose
andescape
respectively.compose
is no longer an asynchronous function. - [New] The error object passed to the callback no longer contains the
errors
andstatements
parameters. These now exist on theinfo
object which is passed as the third parameter to the callback. - [Misc] Complete rewrite of the documentation.
- [Misc] Internal changes to the way parameters are handled
- [Note] This version is a breaking change.
v0.1.5
- [Fix] Fix errors coming through as the string
[object Object]
- [Misc] Give access to the complete error object returned by Neo4j
v0.1.4
- [Fix]
query
now consistently returns anError
object on error. - [Misc] The
Error
object returned byquery
has astatements
property which contains the statements being sent to Neo4j.
v0.1.3
- [New] When calling
buildStatement
with only two arguments the second argument is assumed to be the parameters object.
v0.1.2
- [Fix] Errors are now correctly returned from Neo4j.
v0.1.1
- [Misc] Lock down version numbers of package dependencies.
v0.1.0
- [Fix] Fixed the mapping behaviour when returning more than one variable so that all variables are mapped into the same object rather than multiple objects being returned.
v0.0.4
- [Fix]
buildStatement
no longer needs Neo4J to be initialised.
v0.0.3
- [Fix]
escapeIdentifier
no longer needs Neo4J to be initialised.
v0.0.2
- [New] Add
escapeIdentifier
function.
v0.0.1
- [New] Initial release.
Licence
Copyright (c) 2014, Rainbird Technologies [email protected]
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.