Neo4j features
This commit is contained in:
parent
8e05e59933
commit
ece00ceaaa
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* Module dependencies
|
||||
*/
|
||||
var neo4j = require('neo4j');
|
||||
var neo4j = require('./neo4j-lib');
|
||||
|
||||
exports.initialize = function initializeSchema(schema, callback) {
|
||||
schema.client = new neo4j.GraphDatabase(schema.settings.url);
|
||||
|
@ -15,9 +15,107 @@ function Neo4j(client) {
|
|||
}
|
||||
|
||||
Neo4j.prototype.define = function defineModel(descr) {
|
||||
this.mixClassMethods(descr.model, descr.properties);
|
||||
this.mixInstanceMethods(descr.model.prototype, descr.properties);
|
||||
this._models[descr.model.modelName] = descr;
|
||||
};
|
||||
|
||||
Neo4j.prototype.createIndexHelper = function (class, indexName) {
|
||||
var db = this.client;
|
||||
var method = 'findBy' + indexName[0].toUpperCase() + indexName.substr(1);
|
||||
class[method] = function (value, cb) {
|
||||
db.getIndexedNode(class.modelName, indexName, value, function (err, node) {
|
||||
if (err) return cb(err);
|
||||
if (node) {
|
||||
node.data.id = node.id;
|
||||
cb(null, new class(node.data));
|
||||
} else {
|
||||
cb(null, null);
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
Neo4j.prototype.mixClassMethods = function mixClassMethods(class, properties) {
|
||||
var neo = this;
|
||||
|
||||
Object.keys(properties).forEach(function (name) {
|
||||
if (properties[name].index) {
|
||||
neo.createIndexHelper(class, name);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @param from - id of object to check relation from
|
||||
* @param to - id of object to check relation to
|
||||
* @param type - type of relation
|
||||
* @param direction - all | incoming | outgoing
|
||||
* @param cb - callback (err, rel || false)
|
||||
*/
|
||||
class.relationshipExists = function relationshipExists(from, to, type, direction, cb) {
|
||||
neo.node(from, function (err, node) {
|
||||
if (err) return cb(err);
|
||||
node._getRelationships(direction, type, function (err, rels) {
|
||||
if (err) return cb(err);
|
||||
var found = false;
|
||||
if (rels && rels.forEach) {
|
||||
rels.forEach(function (r) {
|
||||
if (r.start.id === from && r.end.id === to) {
|
||||
found = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
cb(err, found);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
class.createRelationshipTo = function createRelationshipTo(id1, id2, type, data, cb) {
|
||||
var fromNode, toNode;
|
||||
neo.node(id1, function (err, node) {
|
||||
if (err) return cb(err);
|
||||
fromNode = node;
|
||||
ok();
|
||||
});
|
||||
neo.node(id2, function (err, node) {
|
||||
if (err) return cb(err);
|
||||
toNode = node;
|
||||
ok();
|
||||
});
|
||||
function ok() {
|
||||
if (fromNode && toNode) {
|
||||
fromNode.createRelationshipTo(toNode, type, cleanup(data), cb);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class.createRelationshipFrom = function createRelationshipFrom(id1, id2, type, data, cb) {
|
||||
class.createRelationshipTo(id2, id1, type, data, cb);
|
||||
}
|
||||
|
||||
// only create relationship if it is not exists
|
||||
class.ensureRelationshipTo = function (id1, id2, type, data, cb) {
|
||||
class.relationshipExists(id1, id2, type, 'outgoing', function (err, exists) {
|
||||
if (err) return cb(err);
|
||||
if (exists) return cb(null);
|
||||
class.createRelationshipTo(id1, id2, type, data, cb);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Neo4j.prototype.mixInstanceMethods = function mixInstanceMethods(proto) {
|
||||
var neo = this;
|
||||
|
||||
/**
|
||||
* @param obj - Object or id of object to check relation with
|
||||
* @param type - type of relation
|
||||
* @param cb - callback (err, rel || false)
|
||||
*/
|
||||
proto.isInRelationWith = function isInRelationWith(obj, type, direction, cb) {
|
||||
this.constructor.relationshipExists(this.id, obj.id || obj, type, 'all', cb);
|
||||
};
|
||||
};
|
||||
|
||||
Neo4j.prototype.node = function find(id, callback) {
|
||||
if (this.cache[id]) {
|
||||
callback(null, this.cache[id]);
|
||||
|
@ -35,15 +133,40 @@ Neo4j.prototype.create = function create(model, data, callback) {
|
|||
node.data = cleanup(data);
|
||||
node.save(function (err) {
|
||||
if (err) {
|
||||
return callback && callback(err);
|
||||
return callback(err);
|
||||
}
|
||||
this.cache[node.id] = node;
|
||||
node.index(model, 'id', node.id, function (err) {
|
||||
callback && callback(err, node.id);
|
||||
});
|
||||
if (err) return callback(err);
|
||||
this.updateIndexes(model, node, function (err) {
|
||||
if (err) return callback(err);
|
||||
callback(null, node.id);
|
||||
});
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Neo4j.prototype.updateIndexes = function updateIndexes(model, node, cb) {
|
||||
var props = this._models[model].properties;
|
||||
var wait = 1;
|
||||
Object.keys(props).forEach(function (key) {
|
||||
if (props[key].index) {
|
||||
wait += 1;
|
||||
node.index(model, key, node.data[key], done);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
|
||||
var error = false;
|
||||
function done(err) {
|
||||
error = error || err;
|
||||
if (--wait === 0) {
|
||||
cb(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Neo4j.prototype.save = function save(model, data, callback) {
|
||||
this.node(data.id, function (err, node) {
|
||||
if (err) return callback(err);
|
||||
|
@ -82,12 +205,13 @@ Neo4j.prototype.readFromDb = function readFromDb(model, data) {
|
|||
};
|
||||
|
||||
Neo4j.prototype.destroy = function destroy(model, id, callback) {
|
||||
var force = true;
|
||||
this.node(id, function (err, node) {
|
||||
if (err) return callback(err);
|
||||
node.delete(function (err) {
|
||||
if (err) return callback(err);
|
||||
delete this.cache[id];
|
||||
}.bind(this), true);
|
||||
}.bind(this), force);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -153,7 +277,7 @@ Neo4j.prototype.updateAttributes = function updateAttributes(model, id, data, cb
|
|||
};
|
||||
|
||||
function cleanup(data) {
|
||||
if (!data) return console.log('no data!') && {};
|
||||
if (!data) return null;
|
||||
var res = {};
|
||||
Object.keys(data).forEach(function (key) {
|
||||
var v = data[key];
|
||||
|
|
|
@ -17,11 +17,14 @@ var schemas = {
|
|||
memory: {}
|
||||
};
|
||||
|
||||
var specificTest = getSpecificTests();
|
||||
|
||||
Object.keys(schemas).forEach(function (schemaName) {
|
||||
if (process.env.ONLY && process.env.ONLY !== schemaName) return;
|
||||
context(schemaName, function () {
|
||||
var schema = new Schema(schemaName, schemas[schemaName]);
|
||||
testOrm(schema);
|
||||
if (specificTest[schemaName]) specificTest[schemaName](schema);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -41,7 +44,7 @@ function testOrm(schema) {
|
|||
});
|
||||
|
||||
Post = schema.define('Post', {
|
||||
title: { type: String, length: 255 },
|
||||
title: { type: String, length: 255, index: true },
|
||||
content: { type: Text },
|
||||
date: { type: Date, default: Date.now },
|
||||
published: { type: Boolean, default: false }
|
||||
|
@ -342,3 +345,28 @@ function testOrm(schema) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
function getSpecificTests() {
|
||||
var sp = {};
|
||||
|
||||
sp['neo4j'] = function (schema) {
|
||||
|
||||
it('should create methods for searching by index', function (test) {
|
||||
var Post = schema.models['Post'];
|
||||
test.ok(typeof Post.findByTitle === 'function');
|
||||
Post.create({title: 'Catcher in the rye'}, function (err, post) {
|
||||
if (err) return console.log(err);
|
||||
test.ok(!post.isNewRecord());
|
||||
Post.findByTitle('Catcher in the rye', function (err, foundPost) {
|
||||
if (err) return console.log(err);
|
||||
if (foundPost) {
|
||||
test.equal(post.id, foundPost.id);
|
||||
test.done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return sp;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue