Install npm install graph-calc --save
Test npm test
Generate Docs npm run doc
A more complete setup can be found here.
var Edge = require('graph-calc').Edge;
var Factory = require('graph-calc').Factory;
var Graph = require('graph-calc').Graph;
var Node = require('graph-calc').Node;
var util = require('util');
/* create node types */
var TeacherNode = function (options) {
this.id = this.type + '-' + options.raw.id;
Node.call(this, options);
};
util.inherits(TeacherNode, Node);
TeacherNode.prototype.type = 'teacher';
var ClassNode = function (options) {
this.id = this.type + '-' + options.raw.id;
Node.call(this, options);
};
util.inherits(ClassNode, Node);
ClassNode.prototype.type = 'class';
/* create an edge type */
var TeachesEdge = function (options) {
this.id = this.type + '-' + options.raw.teacher.id + '-' + options.raw.class.id;
this.fromNode = options.factory.createOrUpdateNode(this.fromNodeType, options.raw.teacher);
this.toNode = options.factory.createOrUpdateNode(this.toNodeType, options.raw.class);
Edge.call(this, options);
};
util.inherits(TeachesEdge, Edge);
TeachesEdge.prototype.fromNodeType = 'teacher';
TeachesEdge.prototype.type = 'teaches';
TeachesEdge.prototype.toNodeType = 'class';
TeachesEdge.raw2id = function (raw) { return TeachesEdge.prototype.type + '-' + raw.teacher.id + '-' + raw.class.id };
/* create the graph, registering the nodes/edges via a Factory */
var schoolGraph = new Graph ({
factory: new Factory({
nodeClasses: [ TeacherNode, ClassNode ],
edgeClasses: [ TeachesEdge ]
});
});
Create an edge, automatically creating the node if it doesn't exist (more examples):
schoolGraph.factory.createOrUpdateEdge('teaches', { teacher: { id: 'Sue' }, class: { id: 'Chemistry' } });
schoolGraph.factory.createOrUpdateEdge('teaches', { teacher: { id: 'Sue' }, class: { id: 'Physics' } });
Traverse the full graph (more examples):
var Traverser = require('graph-calc').Traverser;
var startNode = graph.factory.getNode('teacher', 'teacher-Sue');
var traverser = new Traverser({
onVisitNode: function (node, meta) {
var path = meta.path;
var depth = meta.depth;
var viaEdge = meta.viaEdge;
var previouslyVisited = meta.previouslyVisited;
...
},
onTraverseEdge: function (edge) { ... },
// Other options:
// onlyNodeTypes: ['teacher', 'student', ...],
// onlyEdgeTypes: ['teaches', ...],
// excludeNodeTypes: ['teacher', ...],
// excludeEdgeTypes: ['teaches', ...],
// maxDepth: 3,
// allowLoops: true,
// shouldVisitNode: function (node) { return true; },
// shouldTraverseEdge: function (edge) { return true; },
});
traverser.traverse(startNode);
Traverse along a path of edge types (more examples):
var PathTraverser = require('graph-calc').PathTraverser;
var traverser = new PathTraverser({
path: [ 'teaches' /* -> CLASS */, 'attendedBy' /* -> STUDENT */ ],
onLeafNode: function (node, meta) { ... }
});
traverser.traverse(teacherNode);
Perform relationship-based calculations, and queries of the graph aided by lodash (more examples):
var Calculator = require('graph-calc').Calculator;
var classByDepartmentCalculator = new Calculator({ acceptsNodeType: 'student' })
.start()
.withNodes({ path: ['attends' /* -> CLASS */, 'providedBy' /* -> DEPARTMENT */], revisitNodes: true })
.map(function (node) { return node.id; })
.countBy()
.finish();
var teacherStudentCalculator = new Calculator({ acceptsNodeType: 'teacher' })
.start()
.withNodes({ path: ['teaches' /* -> CLASS */, 'attendedBy' /* -> STUDENT */], revisitNodes: false })
.mapAndIndexCalc(classByDepartmentCalculator)
.finish();
var result = teacherStudentCalculator.calculate(targetNode);
// e.g result:
// {
// 'student-Bobby': {
// 'department-Science': 2,
// 'department-Art': 1
// },
// 'student-Jo': {
// 'department-Science': 4
// }
// }
Subscribe to events within a node's network (more examples):
var NetworkSubscriber = require('graph-calc').NetworkSubscriber;
// Subscribe to all the 'grade-added' and 'report-due' (fictional) events for
// all student's taught by a teacher.
new NetworkSubscriber({
node: graph.factory.getNode('teacher', 'teacher-Sue'),
// Define the network
maxDepth: 3,
onlyEdgeTypes: ['teaches', 'attendedBy'],
// Attach the listeners
nodeEvents: {
'grade-added': function (grade) { ... },
'report-due': function (reportName) { ... }
}
});