Neography
Neography is object-graph mapping library for Neo4j written in TypeScript. It internally uses official neo4j driver with bolt protocol. Neography supports Active Record pattern. It's goal is to provide simple and convenient API for most common operations. It also provides DSL for constructing advanced cypher queries.
Warning
This library is at early stage of development. Some parts of API most likely will be changed over time. In many areas library requires optimizations. All suggestion, opinions and ideas are gladly welcome.
Installing
npm install neography
Configuring Neography Instance
;; ; //register extensions for managing createdAt and updatedAt properties. //Timestamps are stored as integer valuesneography.registerExtensionTimestampsExtension.getDefault;
Defining Model
Neography provides three types of model types.
NodeEntity
1. ;;
UserNode
class will be directly mapped to Neo4j's node using :User
label. The label for node is set
by @nodeEntity
decorator. Node Entity takes optional generic type in order to enable type safe constructor
taking object with node's properties.
; // OK; // Compile time error
NodeEntity
implements active record pattern and provides save()
method. It creates new node in the database for
not already persisted NodeEntity
instance (adding auto generated, unique, url friendly id property) or updates existing node matched by id.
RelationshipEntity
2. ;;
HasRevision
represents -[:HAS_REVISION]-
relation.
Relationship
3. ;;
It defines relationships between nodes and also supports active record pattern.
;;; postVer1.nextRevision.setpostVer2;postVer2.nextRevision.setWithRelation;await postVer1.save; // .save() creates following nodes and relationships // (:BlogPost {title: "Neo4j})-[:HAS_REVISION {isApproved: false}]-> / // (:BlogPost {title: "Neo4j is fine"})-[:HAS_REVISION {isApproved: true}]->(:BlogPost {title: Graphs are cool})
It also provides many convenient methods for fetching connected nodes. (TODO: docs required)
Querying Nodes
Neography provides convenient query builder for fetching nodes.
; //count all carsresult = await connection.nodeQueryCarNode.count; //get first carresult = await connection.nodeQueryCarNode.first; //find car by idresult = await connection.nodeQueryCarNode.findById'someID'; //it throws error if record not found //find car by id or get undefinedresult = await connection.nodeQueryCarNode.firstById'someID'; //it returns undefined if node not found//it is shortcut forresult = await connection.nodeQueryCarNode.wherew.attribute'id'.equal'someID'.first //get car with greatest horsePowerresult = await connection.nodeQueryCarNode.orderByby.attribute'horsePower'.desc.limit1.first; // get all cars with horsePower greater than 200result = await connection.nodeQueryCarNode.wherew.attribute'horsePower'.greaterThan200.all; // get all cars made by Porsche and Fiat (case sensitive search) result = await connection.nodeQueryCarNode.wherew.attribute'manufacturer'.in.all;
Query Builder for Cypher
Query builder provides simple DSL for building cypher queries. It tries to reflect cypher syntax without introducing any additional abstractions.
;; //create new instance of query builderneography.query;
Inserting Nodes
//create instance of UserNode and assign properties values; //create query .createc.nodeuserNode.as'user' .returns'user';
Query can be executed by calling runQuery
method on Connection
instance. And returns properly mapped response
;
It equals to following cypher query
CREATE(user:UserNode { firstName: "Jane", lastName: "Doe" })RETURN user
Response object provides convenient helper methods for manipulating data.
;
Matching Nodes
.matchm.nodeUserNode.params.as'user' .returns'user'; ;
Matching Nodes Using Where
.matchm.nodeUserNode.as'user' .wherew.attribute'firstName'.equal'Jane' .returns'user'; ;
.matchm.nodeUserNode.as'user' .wherew.attribute'id'.in .returns'user'; ;
Matching Nodes Using Where Literal Statement
.matchm.nodeUserNode.as'user' .wherew.literal`user.createdAt < {userCreateDate}`.params .returns'user'; ;
Matching Nodes Connected by Relationship
.match .returns'user', 'relation', 'friend'; ;;
Matching Nodes Using Optional Match
.matchm.nodeUserNode.as'user'.params .optionalMatch .returns'user', 'relation', 'friend'; ;;
Creating Relations For Existing Nodes
.match .create .returns'user','relation', 'friend'; ;;
Creating Relations with New Node
; .matchm.nodeUserNode.params.as'user' .create .returns'user','relation', 'friend'; ;;