rainbird-neo4j

0.4.3 • Public • Published

Rainbird Neo4j

Build Status

Package Dependencies

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 and escapeIdentifier have been replaced with compose and escape respectively. compose is no longer an asynchronous function.
  • [New] The error object passed to the callback no longer contains the errors and statements parameters. These now exist on the info 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 an Error object on error.
  • [Misc] The Error object returned by query has a statements 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 follow@rainbird.ai

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.

Readme

Keywords

none

Package Sidebar

Install

npm i rainbird-neo4j

Weekly Downloads

0

Version

0.4.3

License

ISC

Last publish

Collaborators

  • domdavis
  • illizian