mongoose-path-tree-ng
Version:
Maintaied version of materialized path hierarchy for mongoose with reparent option
404 lines (271 loc) • 12.2 kB
JavaScript
var Mongoose = require('mongoose');
var Tree = require('../lib/tree');
var Async = require('async');
var should = require('should');
var _ = require('lodash');
var shortId = require('shortid');
var Schema = Mongoose.Schema;
Mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost:27017/mongoose-path-tree');
describe('tree tests', function () {
var userSchema = {
name: String
};
var pluginOptions = {
pathSeparator: '.'
};
if (process.env.MONGOOSE_TREE_SHORTID === '1') {
userSchema._id = {
type: String,
unique: true,
'default': function(){
return shortId.generate();
}
};
pluginOptions.idType = String
}
// Schema for tests
var UserSchema = new Schema(userSchema);
UserSchema.plugin(Tree, pluginOptions);
var User = Mongoose.model('User', UserSchema);
// Set up the fixture
beforeEach(function (done) {
User.remove({}, function (err) {
should.not.exist(err);
var adam = new User({name: 'Adam' });
var eden = new User({name: 'Eden' });
var bob = new User({name: 'Bob', parent: adam });
var carol = new User({name: 'Carol', parent: adam });
var dann = new User({name: 'Dann', parent: carol });
var emily = new User({name: 'Emily', parent: dann });
Async.forEachSeries([adam, bob, carol, dann, emily, eden], function (doc, cb) {
doc.save(cb);
}, done);
});
});
describe('adding documents', function () {
it('should set parent id and path', function (done) {
User.find({}, function (err, users) {
should.not.exist(err);
var names = {};
users.forEach(function (user) {
names[user.name] = user;
});
should.not.exist(names['Adam'].parent);
names['Bob'].parent.toString().should.equal(names['Adam']._id.toString());
names['Carol'].parent.toString().should.equal(names['Adam']._id.toString());
names['Dann'].parent.toString().should.equal(names['Carol']._id.toString());
names['Emily'].parent.toString().should.equal(names['Dann']._id.toString());
var expectedPath = [names['Adam']._id, names['Carol']._id, names['Dann']._id].join('.');
names['Dann'].path.should.equal(expectedPath);
done();
});
});
});
describe('removing document', function () {
it('should remove leaf nodes', function (done) {
User.findOne({ name: 'Emily' }, function (err, emily) {
emily.remove(function (err) {
should.not.exist(err);
User.find(function (err, users) {
should.not.exist(err);
users.length.should.equal(5);
_.pluck(users, 'name').should.not.include('Emily');
done();
});
});
});
});
it('should remove all children', function (done) {
User.findOne({ name: 'Carol' }, function (err, user) {
should.not.exist(err);
user.remove(function (err) {
should.not.exist(err);
User.find(function (err, users) {
should.not.exist(err);
users.length.should.equal(3);
_.pluck(users, 'name').should.include('Adam').and.include('Bob');
done();
});
});
});
});
});
function checkPaths(done) {
User.find({}, function (err, users) {
should.not.exist(err);
var ids = {};
users.forEach(function (user) {
ids[user._id] = user;
});
users.forEach(function (user) {
if (!user.parent) {
return;
}
should.exist(ids[user.parent]);
user.path.should.equal(ids[user.parent].path + "." + user._id);
});
done();
});
}
describe('moving documents', function () {
it('should change children paths', function (done) {
User.find({}, function (err, users) {
should.not.exist(err);
var names = {};
users.forEach(function (user) {
names[user.name] = user;
});
var carol = names['Carol'];
var bob = names['Bob'];
carol.parent = bob;
carol.save(function (err) {
should.not.exist(err);
checkPaths(done);
});
});
});
});
describe('get children', function () {
it('should return immediate children with filters', function (done) {
User.findOne({name: 'Adam'}, function (err, adam) {
should.not.exist(err);
adam.getChildren({name: 'Bob'}, function (err, users) {
should.not.exist(err);
users.length.should.equal(1);
_.pluck(users, 'name').should.include('Bob');
done();
});
});
});
it('should return immediate children', function (done) {
User.findOne({name: 'Adam'}, function (err, adam) {
should.not.exist(err);
adam.getChildren(function (err, users) {
should.not.exist(err);
users.length.should.equal(2);
_.pluck(users, 'name').should.include('Bob').and.include('Carol');
done();
});
});
});
it('should return recursive children', function (done) {
User.findOne({ 'name': 'Carol' }, function (err, carol) {
should.not.exist(err);
carol.getChildren(true, function (err, users) {
should.not.exist(err);
users.length.should.equal(2);
_.pluck(users, 'name').should.include('Dann').and.include('Emily');
done();
});
});
});
it('should return children with only name and _id fields', function (done) {
User.findOne({ 'name': 'Carol' }, function (err, carol) {
should.not.exist(err);
carol.getChildren({}, 'name', true, function (err, users) {
should.not.exist(err);
users.length.should.equal(2);
users[0].should.not.have.property('parent');
_.pluck(users, 'name').should.include('Dann').and.include('Emily');
done();
});
});
});
it('should return children sorted on name', function (done) {
User.findOne({ 'name': 'Carol' }, function (err, carol) {
should.not.exist(err);
carol.getChildren({}, null, {sort: {name: -1}}, true, function (err, users) {
should.not.exist(err);
users.length.should.equal(2);
users[0].name.should.equal('Emily');
_.pluck(users, 'name').should.include('Dann').and.include('Emily');
done();
});
});
});
});
describe('level virtual', function () {
it('should equal the number of ancestors', function (done) {
User.findOne({ 'name': 'Dann' }, function (err, dann) {
should.not.exist(err);
dann.level.should.equal(3);
done();
});
});
});
describe('get ancestors', function () {
it('should return ancestors', function (done) {
User.findOne({ 'name': 'Dann' }, function (err, dann) {
dann.getAncestors(function (err, ancestors) {
should.not.exist(err);
ancestors.length.should.equal(2);
_.pluck(ancestors, 'name').should.include('Carol').and.include('Adam');
done();
});
});
});
it('should return ancestors with only name and _id fields', function (done) {
User.findOne({ 'name': 'Dann' }, function (err, dann) {
dann.getAncestors({}, 'name', function (err, ancestors) {
should.not.exist(err);
ancestors.length.should.equal(2);
ancestors[0].should.not.have.property('parent');
ancestors[0].should.have.property('name');
_.pluck(ancestors, 'name').should.include('Carol').and.include('Adam');
done();
});
});
});
it('should return ancestors sorted on name and without wrappers', function (done) {
User.findOne({ 'name': 'Dann' }, function (err, dann) {
dann.getAncestors({}, null, {sort: {name: -1}, lean: 1}, function (err, ancestors) {
should.not.exist(err);
ancestors.length.should.equal(2);
ancestors[0].name.should.equal('Carol');
should.not.exist(ancestors[0].getAncestors);
_.pluck(ancestors, 'name').should.include('Carol').and.include('Adam');
done();
});
});
});
});
describe('get children tree', function () {
it("should return complete children tree", function (done) {
User.getChildrenTree(function (err, childrenTree) {
should.not.exist(err);
childrenTree.length.should.equal(2);
var adamTree = _.find(childrenTree, function(x){ return x.name == 'Adam'});
var edenTree = _.find(childrenTree, function(x){ return x.name == 'Eden'});
var bobTree = _.find(adamTree.children, function(x){ return x.name == 'Bob'});
var carolTree = _.find(adamTree.children, function(x){ return x.name == 'Carol'});
var danTree = _.find(carolTree.children, function(x){ return x.name == 'Dann'});
var emilyTree = _.find(danTree.children, function(x){ return x.name == 'Emily'});
adamTree.children.length.should.equal(2);
edenTree.children.length.should.equal(0);
bobTree.children.length.should.equal(0);
carolTree.children.length.should.equal(1);
danTree.children.length.should.equal(1);
danTree.children[0].name.should.equal('Emily');
emilyTree.children.length.should.equal(0);
done();
});
});
it("should return adam's children tree", function (done) {
User.findOne({ 'name': 'Adam' }, function (err, adam) {
adam.getChildrenTree(function (err, childrenTree) {
should.not.exist(err);
var bobTree = _.find(childrenTree, function(x){ return x.name == 'Bob'});
var carolTree = _.find(childrenTree, function(x){ return x.name == 'Carol'});
var danTree = _.find(carolTree.children, function(x){ return x.name == 'Dann'});
var emilyTree = _.find(danTree.children, function(x){ return x.name == 'Emily'});
bobTree.children.length.should.equal(0);
carolTree.children.length.should.equal(1);
danTree.children.length.should.equal(1);
danTree.children[0].name.should.equal('Emily');
emilyTree.children.length.should.equal(0);
done();
});
});
});
});
});