From 3f9c85b8e4ad99fcf33a3831afd2967663cb3d09 Mon Sep 17 00:00:00 2001 From: Saleh Saeed Date: Tue, 11 Dec 2018 15:24:27 +0300 Subject: [PATCH 01/14] Update mongoose and sync & change from nodeunit to mocha --- lib/nested_set.js | 18 +- package.json | 8 +- tests/nested_set_test.js | 479 ---------------------- tests/nested_set_with_groupingkey_test.js | 206 ---------- 4 files changed, 13 insertions(+), 698 deletions(-) delete mode 100644 tests/nested_set_test.js delete mode 100644 tests/nested_set_with_groupingkey_test.js diff --git a/lib/nested_set.js b/lib/nested_set.js index 4cebd08..ad1208a 100644 --- a/lib/nested_set.js +++ b/lib/nested_set.js @@ -51,9 +51,9 @@ var NestedSetPlugin = function(schema, options) { maxRgt = parentNode.lft; } var conditions = updateConditions({lft: { $gt: maxRgt}}, self); - self.constructor.update(conditions, {$inc: {lft: 2}}, {multi: true}, function(err, updatedCount) { + self.constructor.updateMany(conditions, {$inc: {lft: 2}}, {multi: true}, function(err, updatedCount) { conditions = updateConditions({rgt: { $gt: maxRgt}}, self); - self.constructor.update(conditions, {$inc: {rgt: 2}}, {multi: true}, function(err, updatedCount2) { + self.constructor.updateMany(conditions, {$inc: {rgt: 2}}, {multi: true}, function(err, updatedCount2) { self.lft = maxRgt + 1; self.rgt = maxRgt + 2; next(); @@ -99,9 +99,9 @@ var NestedSetPlugin = function(schema, options) { maxRgt = parentNode.lft; } var conditions = updateConditions({lft: { $gt: maxRgt}}, self); - self.constructor.update(conditions, {$inc: {lft: -2}}, {multi: true}, function(err, updatedCount) { + self.constructor.updateMany(conditions, {$inc: {lft: -2}}, {multi: true}, function(err, updatedCount) { conditions = updateConditions({rgt: { $gt: maxRgt}}, self); - self.constructor.update(conditions, {$inc: {rgt: -2}}, {multi: true}, function(err, updatedCount2) { + self.constructor.updateMany(conditions, {$inc: {rgt: -2}}, {multi: true}, function(err, updatedCount2) { next(); }); }); @@ -136,16 +136,16 @@ var NestedSetPlugin = function(schema, options) { if (!children) return callback(new Error(self.constructor.modelName + ' not found')); if (children.length > 0) { - async.forEachSeries(children, function(item, cb) { + async.forEach(children, function(item, cb) { self.rebuildTree(item, parent.rgt, function() { parent.rgt = item.rgt + 1; - self.update({_id: parent._id}, {lft: parent.lft, rgt: parent.rgt}, cb); + self.updateOne({_id: parent._id}, {lft: parent.lft, rgt: parent.rgt}, cb); }); }, function(err) { - callback(); + callback(err, 'erroraaaaa'); }); } else { - self.update({_id: parent._id}, {lft: parent.lft, rgt: parent.rgt}, callback); + self.updateOne({_id: parent._id}, {lft: parent.lft, rgt: parent.rgt}, callback); } }); }); @@ -175,7 +175,7 @@ var NestedSetPlugin = function(schema, options) { // returns the parent node schema.method('parent', function(callback) { var self = this; - self.constructor.findOne({ _id: self.parentId }, callback); + self.constructor.findById(self.parentId, callback); }); // Returns the list of ancestors + current node diff --git a/package.json b/package.json index a2c895b..7dedce4 100644 --- a/package.json +++ b/package.json @@ -17,16 +17,16 @@ }, "main": "index.js", "scripts": { - "test": "./node_modules/nodeunit/bin/nodeunit tests/*.js" + "test": "./node_modules/.bin/mocha tests/*.js" }, "engines": { "node": "> 0.7.x" }, "dependencies": { - "mongoose": "~2.5.14", - "async": "~0.1.22" + "mongoose": "~5.3.15", + "async": "~2.6.1" }, "devDependencies": { - "nodeunit": "~0.7.4" + "mocha": "^5.2.0" } } diff --git a/tests/nested_set_test.js b/tests/nested_set_test.js deleted file mode 100644 index 9d326be..0000000 --- a/tests/nested_set_test.js +++ /dev/null @@ -1,479 +0,0 @@ -/*globals require, module, console */ - -'use strict'; - -var testCase = require('nodeunit').testCase, - mongoose = require('mongoose'), - NestedSetPlugin = require('../lib/nested_set'), - Schema = mongoose.Schema, - async = require('async'), - Helpers = require('./helpers'); - -var UserSchema, - User; - -var tests = testCase({ - setUp: function(next) { - async.series([ - function(callback) { - mongoose.connect('mongodb://localhost/nested_set_test'); - callback(); - }, - function(callback) { - UserSchema = new Schema({ - username: {type: String} - }); - UserSchema.plugin(NestedSetPlugin); - User = mongoose.model('User', UserSchema); - callback(); - }, - function(callback) { - // see diagram in docs/test_tree.png for a representation of this tree - var michael = new User({username: 'michael'}); - - var meredith = new User({username: 'meredith', parentId: michael._id}); - var jim = new User({username: 'jim', parentId: michael._id}); - var angela = new User({username: 'angela', parentId: michael._id}); - - var kelly = new User({username: 'kelly', parentId: meredith._id}); - var creed = new User({username: 'creed', parentId: meredith._id}); - - var phyllis = new User({username: 'phyllis', parentId: jim._id}); - var stanley = new User({username: 'stanley', parentId: jim._id}); - var dwight = new User({username: 'dwight', parentId: jim._id}); - - var oscar = new User({username: 'oscar', parentId: angela._id}); - - async.forEach([ - michael, - meredith, - jim, - angela, - kelly, - creed, - phyllis, - stanley, - dwight, - oscar - ], function(item, cb) { item.save(cb); }, next); - } - ]); - }, - tearDown: function(callback) { - mongoose.connection.collections.users.drop( function(err) { - mongoose.disconnect(callback); - }); - }, - 'is sane': function(test) { - test.expect(3); - test.ok(User); - test.equal('function', typeof User); - test.equal('User', User.modelName); - test.done(); - }, - 'has created users for testing': function(test) { - test.expect(4); - User.find(function(err, users) { - if (err) { console.log(err); } - test.ok(!err); - test.ok(users); - test.ok(users instanceof Array); - test.equal(10, users.length); - test.done(); - }); - }, - 'can read parentIds as ObjectIDs': function(test) { - test.expect(10); // 1 to test err + only 9 of the tests will run in the forEach loop since root has parentId of null - User.find(function(err, users) { - if (err) { console.log(err); } - test.ok(!err); - users.forEach(function(user) { - if (user.parentId) { - test.ok(Helpers.isObjectId(user.parentId)); - } - }); - test.done(); - }); - }, - 'rebuildTree should set lft and rgt based on parentIds': function(test) { - test.expect(20); - User.findOne({username: 'michael'}, function(err, user) { - User.rebuildTree(user, 1, function() { - User.find(function(err, users) { - // see docs/test_tree.png for the graphical representation of this tree with lft/rgt values - users.forEach(function(person) { - if (person.username === 'michael') { - test.equal(1, person.lft); - test.equal(20, person.rgt); - } else if (person.username === 'meredith') { - test.equal(2, person.lft); - test.equal(7, person.rgt); - } else if (person.username === 'jim') { - test.equal(8, person.lft); - test.equal(15, person.rgt); - } else if (person.username === 'angela') { - test.equal(16, person.lft); - test.equal(19, person.rgt); - } else if (person.username === 'kelly') { - test.equal(3, person.lft); - test.equal(4, person.rgt); - } else if (person.username === 'creed') { - test.equal(5, person.lft); - test.equal(6, person.rgt); - } else if (person.username === 'phyllis') { - test.equal(9, person.lft); - test.equal(10, person.rgt); - } else if (person.username === 'stanley') { - test.equal(11, person.lft); - test.equal(12, person.rgt); - } else if (person.username === 'dwight') { - test.equal(13, person.lft); - test.equal(14, person.rgt); - } else if (person.username === 'oscar') { - test.equal(17, person.lft); - test.equal(18, person.rgt); - } - }); - test.done(); - }); - }); - }); - }, - 'isLeaf should return true if node is leaf': function(test) { - test.expect(2); - User.findOne({username: 'michael'}, function(err, user) { - User.rebuildTree(user, 1, function() { - User.findOne({username: 'kelly'}, function(err, kelly) { - test.ok(kelly.isLeaf()); - User.findOne({username: 'michael'}, function(err, michael) { - test.ok(!michael.isLeaf()); - test.done(); - }); - }); - }); - }); - }, - 'isChild should return true if node has a parent': function(test) { - test.expect(2); - User.findOne({username: 'michael'}, function(err, user) { - User.rebuildTree(user, 1, function() { - User.findOne({username: 'kelly'}, function(err, kelly) { - test.ok(kelly.isChild()); - User.findOne({username: 'michael'}, function(err, michael) { - test.ok(!michael.isChild()); - test.done(); - }); - }); - }); - }); - }, - 'parent should return parent node': function(test) { - test.expect(4); - User.findOne({username: 'michael'}, function(err, user) { - User.rebuildTree(user, 1, function() { - User.findOne({username: 'kelly'}, function(err, kelly) { - test.ok(!err); - test.ok(kelly); - kelly.parent(function(err, node) { - test.ok(!err); - test.equal('meredith',node.username); - test.done(); - }); - }); - }); - }); - }, - 'selfAndAncestors should return all ancestors higher up in tree + current node': function(test) { - test.expect(2); - User.findOne({username: 'michael'}, function(err, user) { - User.rebuildTree(user, 1, function() { - User.findOne({username: 'kelly'}, function(err, kelly) { - kelly.selfAndAncestors(function(err, people) { - test.ok(!err); - test.deepEqual(['kelly', 'meredith', 'michael'], people.map(function(p) {return p.username; }).sort()); - test.done(); - }); - }); - }); - }); - }, - 'ancestors should return all ancestors higher up in tree': function(test) { - test.expect(2); - User.findOne({username: 'michael'}, function(err, user) { - User.rebuildTree(user, 1, function() { - User.findOne({username: 'kelly'}, function(err, kelly) { - kelly.ancestors(function(err, people) { - test.ok(!err); - test.deepEqual(['meredith', 'michael'], people.map(function(p) {return p.username; }).sort()); - test.done(); - }); - }); - }); - }); - }, - 'ancestors should return empty array if it is a root node': function(test) { - test.expect(2); - User.findOne({username: 'michael'}, function(err, user) { - User.rebuildTree(user, 1, function() { - User.findOne({username: 'michael'}, function(err, michael) { - michael.ancestors(function(err, people) { - test.ok(!err); - test.deepEqual([], people.map(function(p) {return p.username; }).sort()); - test.done(); - }); - }); - }); - }); - }, - 'selfAndChildren should return all children + current node': function(test) { - test.expect(2); - User.findOne({username: 'michael'}, function(err, user) { - User.rebuildTree(user, 1, function() { - User.findOne({username: 'michael'}, function(err, michael) { - michael.selfAndChildren(function(err, people) { - test.ok(!err); - test.deepEqual(['angela', 'jim', 'meredith', 'michael'], people.map(function(p) {return p.username; }).sort()); - test.done(); - }); - }); - }); - }); - }, - 'children should return all children': function(test) { - test.expect(2); - User.findOne({username: 'michael'}, function(err, user) { - User.rebuildTree(user, 1, function() { - User.findOne({username: 'michael'}, function(err, michael) { - michael.children(function(err, people) { - test.ok(!err); - test.deepEqual(['angela', 'jim', 'meredith'], people.map(function(p) {return p.username; }).sort()); - test.done(); - }); - }); - }); - }); - }, - 'selfAndDescendants should return all descendants + current node': function(test) { - test.expect(2); - User.findOne({username: 'michael'}, function(err, user) { - User.rebuildTree(user, 1, function() { - User.findOne({username: 'michael'}, function(err, michael) { - michael.selfAndDescendants(function(err, people) { - test.ok(!err); - test.deepEqual( - ['angela', 'creed', 'dwight', 'jim', 'kelly', 'meredith', 'michael', 'oscar', 'phyllis', 'stanley'], - people.map(function(p) {return p.username; }).sort() - ); - test.done(); - }); - }); - }); - }); - }, - 'descendants should return all descendants': function(test) { - test.expect(2); - User.findOne({username: 'michael'}, function(err, user) { - User.rebuildTree(user, 1, function() { - User.findOne({username: 'michael'}, function(err, michael) { - michael.descendants(function(err, people) { - test.ok(!err); - test.deepEqual( - ['angela', 'creed', 'dwight', 'jim', 'kelly', 'meredith', 'oscar', 'phyllis', 'stanley'], - people.map(function(p) {return p.username; }).sort() - ); - test.done(); - }); - }); - }); - }); - }, - 'level should return 0 for root node': function(test) { - test.expect(2); - User.findOne({username: 'michael'}, function(err, user) { - User.rebuildTree(user, 1, function() { - User.findOne({username: 'michael'}, function(err, michael) { - michael.level(function(err, value) { - test.ok(!err); - test.equal(0, value); - test.done(); - }); - }); - }); - }); - }, - 'selfAndSiblings should return all nodes with same parent node + current node': function(test) { - test.expect(2); - User.findOne({username: 'michael'}, function(err, user) { - User.rebuildTree(user, 1, function() { - User.findOne({username: 'meredith'}, function(err, meredith) { - meredith.selfAndSiblings(function(err, people) { - test.ok(!err); - test.deepEqual( - ['angela', 'jim', 'meredith'], - people.map(function(p) {return p.username; }).sort() - ); - test.done(); - }); - }); - }); - }); - }, - 'siblings should return all nodes with same parent node': function(test) { - test.expect(2); - User.findOne({username: 'michael'}, function(err, user) { - User.rebuildTree(user, 1, function() { - User.findOne({username: 'meredith'}, function(err, meredith) { - meredith.siblings(function(err, people) { - test.ok(!err); - test.deepEqual( - ['angela', 'jim'], - people.map(function(p) {return p.username; }).sort() - ); - test.done(); - }); - }); - }); - }); - }, - 'kelly is a descendant of michael': function(test) { - test.expect(2); - User.findOne({username: 'michael'}, function(err, michael) { - User.rebuildTree(michael, 1, function() { - User.findOne({username: 'kelly'}, function(err, kelly) { - test.ok(kelly.isDescendantOf(michael)); - test.ok(!michael.isDescendantOf(kelly)); - test.done(); - }); - }); - }); - }, - 'michael is an ancestor of kelly': function(test) { - test.expect(2); - User.findOne({username: 'michael'}, function(err, michael) { - User.rebuildTree(michael, 1, function() { - User.findOne({username: 'kelly'}, function(err, kelly) { - test.ok(michael.isAncestorOf(kelly)); - test.ok(!kelly.isAncestorOf(michael)); - test.done(); - }); - }); - }); - }, - 'pre save middleware should not set lft and rgt if there is no parentId': function(test) { - test.expect(4); - var user = new User({ - username: 'joe' - }); - user.save(function(err, joe) { - test.ok(!err); - test.equal('joe', joe.username); - test.ok(!joe.lft); - test.ok(!joe.rgt); - test.done(); - }); - }, - 'removing a node to a built tree should re-arrange the tree correctly': function(test) { - test.expect(18); - User.findOne({username: 'michael'}, function(err, michael) { - User.rebuildTree(michael, 1, function() { - User.findOne({username: 'creed'}, function(err, creed) { - creed.remove(function() { - User.find(function(err, users) { - // see docs/test_tree_after_leaf_insertion.png for the graphical representation of this tree - // with lft/rgt values after the insertion - users.forEach(function(person) { - if (person.username === 'michael') { - test.equal(1, person.lft); - test.equal(18, person.rgt); - } else if (person.username === 'meredith') { - test.equal(2, person.lft); - test.equal(5, person.rgt); - } else if (person.username === 'jim') { - test.equal(6, person.lft); - test.equal(13, person.rgt); - } else if (person.username === 'angela') { - test.equal(14, person.lft); - test.equal(17, person.rgt); - } else if (person.username === 'kelly') { - test.equal(3, person.lft); - test.equal(4, person.rgt); - } else if (person.username === 'phyllis') { - test.equal(7, person.lft); - test.equal(8, person.rgt); - } else if (person.username === 'stanley') { - test.equal(9, person.lft); - test.equal(10, person.rgt); - } else if (person.username === 'dwight') { - test.equal(11, person.lft); - test.equal(12, person.rgt); - } else if (person.username === 'oscar') { - test.equal(15, person.lft); - test.equal(16, person.rgt); - } - }); - test.done(); - }); - }); - }); - }); - }); - }, - 'adding a new node to a built tree should re-arrange the tree correctly': function(test) { - test.expect(22); - User.findOne({username: 'michael'}, function(err, michael) { - User.rebuildTree(michael, 1, function() { - User.findOne({username: 'creed'}, function(err, creed) { - var newUser = new User({ - username: 'joe', - parentId: creed._id - }); - newUser.save(function(err, joe) { - User.find(function(err, users) { - // see docs/test_tree_after_leaf_insertion.png for the graphical representation of this tree - // with lft/rgt values after the insertion - users.forEach(function(person) { - if (person.username === 'michael') { - test.equal(1, person.lft); - test.equal(22, person.rgt); - } else if (person.username === 'meredith') { - test.equal(2, person.lft); - test.equal(9, person.rgt); - } else if (person.username === 'jim') { - test.equal(10, person.lft); - test.equal(17, person.rgt); - } else if (person.username === 'angela') { - test.equal(18, person.lft); - test.equal(21, person.rgt); - } else if (person.username === 'kelly') { - test.equal(3, person.lft); - test.equal(4, person.rgt); - } else if (person.username === 'creed') { - test.equal(5, person.lft); - test.equal(8, person.rgt); - } else if (person.username === 'phyllis') { - test.equal(11, person.lft); - test.equal(12, person.rgt); - } else if (person.username === 'stanley') { - test.equal(13, person.lft); - test.equal(14, person.rgt); - } else if (person.username === 'dwight') { - test.equal(15, person.lft); - test.equal(16, person.rgt); - } else if (person.username === 'oscar') { - test.equal(19, person.lft); - test.equal(20, person.rgt); - } else if (person.username === 'joe') { - test.equal(6, person.lft); - test.equal(7, person.rgt); - } - }); - test.done(); - }); - }); - }); - }); - }); - } -}); - -module.exports = tests; diff --git a/tests/nested_set_with_groupingkey_test.js b/tests/nested_set_with_groupingkey_test.js deleted file mode 100644 index e75d638..0000000 --- a/tests/nested_set_with_groupingkey_test.js +++ /dev/null @@ -1,206 +0,0 @@ -/*globals require, module, console */ - -'use strict'; - -var testCase = require('nodeunit').testCase, - mongoose = require('mongoose'), - NestedSetPlugin = require('../lib/nested_set'), - Schema = mongoose.Schema, - async = require('async'), - Helpers = require('./helpers'); - -var UserSchema, - User; - -var createUsers = function(organization, callback) { - // see diagram in docs/test_tree.png for a representation of this tree - var michael = new User({username: 'michael', organization: organization}); - - var meredith = new User({username: 'meredith', parentId: michael._id, organization: organization}); - var jim = new User({username: 'jim', parentId: michael._id, organization: organization}); - var angela = new User({username: 'angela', parentId: michael._id, organization: organization}); - - var kelly = new User({username: 'kelly', parentId: meredith._id, organization: organization}); - var creed = new User({username: 'creed', parentId: meredith._id, organization: organization}); - - var phyllis = new User({username: 'phyllis', parentId: jim._id, organization: organization}); - var stanley = new User({username: 'stanley', parentId: jim._id, organization: organization}); - var dwight = new User({username: 'dwight', parentId: jim._id, organization: organization}); - - var oscar = new User({username: 'oscar', parentId: angela._id, organization: organization}); - - var users = [ - michael, - meredith, - jim, - angela, - kelly, - creed, - phyllis, - stanley, - dwight, - oscar - ]; - - if (organization === 'B') { - // Slightly different tree with less leaves - users = [ - michael, - meredith, - jim, - angela, - kelly, - phyllis, - stanley, - oscar - ]; - } - - async.forEach(users, function(item, cb) { item.save(cb); }, callback); -}; - -var tests = testCase({ - setUp: function(next) { - async.series([ - function(callback) { - mongoose.connect('mongodb://localhost/nested_set_test'); - callback(); - }, - function(callback) { - UserSchema = new Schema({ - username: {type: String}, - organization: {type: String} - }); - UserSchema.plugin(NestedSetPlugin, { groupingKey: 'organization' }); - User = mongoose.model('User', UserSchema); - callback(); - }, - function(callback) { - createUsers('A', callback); - }, - function(callback) { - createUsers('B', callback); - } - ], next); - }, - tearDown: function(callback) { - mongoose.connection.collections.users.drop( function(err) { - mongoose.disconnect(callback); - }); - }, - 'is sane': function(test) { - test.expect(3); - test.ok(User); - test.equal('function', typeof User); - test.equal('User', User.modelName); - test.done(); - }, - 'has created users for testing': function(test) { - test.expect(4); - User.find(function(err, users) { - if (err) { console.log(err); } - test.ok(!err); - test.ok(users); - test.ok(users instanceof Array); - test.equal(18, users.length); - test.done(); - }); - }, - 'can read parentIds as ObjectIDs': function(test) { - test.expect(10); // 1 to test err + only 9 of the tests will run in the forEach loop since root has parentId of null - User.find({organization: 'A'}, function(err, users) { - if (err) { console.log(err); } - test.ok(!err); - users.forEach(function(user) { - if (user.parentId) { - test.ok(Helpers.isObjectId(user.parentId)); - } - }); - test.done(); - }); - }, - 'rebuildTree should set lft and rgt based on parentIds (A)': function(test) { - test.expect(20); - User.findOne({username: 'michael', organization: 'A'}, function(err, user) { - User.rebuildTree(user, 1, function() { - User.find({organization: 'A'}, function(err, users) { - // see docs/test_tree.png for the graphical representation of this tree with lft/rgt values - users.forEach(function(person) { - if (person.username === 'michael') { - test.equal(1, person.lft); - test.equal(20, person.rgt); - } else if (person.username === 'meredith') { - test.equal(2, person.lft); - test.equal(7, person.rgt); - } else if (person.username === 'jim') { - test.equal(8, person.lft); - test.equal(15, person.rgt); - } else if (person.username === 'angela') { - test.equal(16, person.lft); - test.equal(19, person.rgt); - } else if (person.username === 'kelly') { - test.equal(3, person.lft); - test.equal(4, person.rgt); - } else if (person.username === 'creed') { - test.equal(5, person.lft); - test.equal(6, person.rgt); - } else if (person.username === 'phyllis') { - test.equal(9, person.lft); - test.equal(10, person.rgt); - } else if (person.username === 'stanley') { - test.equal(11, person.lft); - test.equal(12, person.rgt); - } else if (person.username === 'dwight') { - test.equal(13, person.lft); - test.equal(14, person.rgt); - } else if (person.username === 'oscar') { - test.equal(17, person.lft); - test.equal(18, person.rgt); - } - }); - test.done(); - }); - }); - }); - }, - 'rebuildTree should set lft and rgt based on parentIds (B)': function(test) { - test.expect(16); - User.findOne({username: 'michael', organization: 'B'}, function(err, user) { - User.rebuildTree(user, 1, function() { - User.find({organization: 'B'}, function(err, users) { - // see docs/test_tree.png for the graphical representation of this tree with lft/rgt values - users.forEach(function(person) { - if (person.username === 'michael') { - test.equal(1, person.lft); - test.equal(16, person.rgt); - } else if (person.username === 'meredith') { - test.equal(2, person.lft); - test.equal(5, person.rgt); - } else if (person.username === 'jim') { - test.equal(6, person.lft); - test.equal(11, person.rgt); - } else if (person.username === 'angela') { - test.equal(12, person.lft); - test.equal(15, person.rgt); - } else if (person.username === 'kelly') { - test.equal(3, person.lft); - test.equal(4, person.rgt); - } else if (person.username === 'phyllis') { - test.equal(7, person.lft); - test.equal(8, person.rgt); - } else if (person.username === 'stanley') { - test.equal(9, person.lft); - test.equal(10, person.rgt); - } else if (person.username === 'oscar') { - test.equal(13, person.lft); - test.equal(14, person.rgt); - } - }); - test.done(); - }); - }); - }); - } -}); - -module.exports = tests; From 4f88790884d96d7dc13f6ded8cd5185898285dd4 Mon Sep 17 00:00:00 2001 From: Saleh Saeed Date: Tue, 11 Dec 2018 15:26:05 +0300 Subject: [PATCH 02/14] replace var with let --- lib/nested_set.js | 54 +++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/lib/nested_set.js b/lib/nested_set.js index ad1208a..9f15ed4 100644 --- a/lib/nested_set.js +++ b/lib/nested_set.js @@ -2,28 +2,28 @@ 'use strict'; -var mongoose = require('mongoose'), +const mongoose = require('mongoose'), Schema = mongoose.Schema, async = require('async'); -var NestedSetPlugin = function(schema, options) { +const NestedSetPlugin = function(schema, options) { options = options || {}; schema.add({ lft: {type: Number, min: 0} }); schema.add({ rgt: {type: Number, min: 0} }); - + // Allows level computong while editing the graph schema.add({ lvl: {type: Number, min: 0, default:0} }); schema.index({lvl: 1}); - + schema.add({ parentId: {type: Schema.ObjectId} }); schema.index({parentId: 1}); schema.index({lft: 1, rgt: 1}); schema.index({rgt: 1}); - var updateConditions = function (conditions, item) { + let updateConditions = function (conditions, item) { if (options.groupingKey) { conditions[options.groupingKey] = item[options.groupingKey]; } @@ -31,16 +31,16 @@ var NestedSetPlugin = function(schema, options) { }; schema.pre('save', function(next) { - var self = this; + let self = this; if (self.parentId) { self.parent(function(err, parentNode) { if (!err && parentNode && parentNode.lft && parentNode.rgt) { //Update level based on parentNode level - self.lvl = parentNode.lvl + 1 + self.lvl = parentNode.lvl + 1; // find siblings and check if they have lft and rgt values set self.siblings(function(err, nodes) { if (nodes.every(function(node) { return node.lft && node.rgt;})) { - var maxRgt = 0; + let maxRgt = 0; nodes.forEach(function(node) { if (node.rgt > maxRgt) { maxRgt = node.rgt; @@ -50,7 +50,7 @@ var NestedSetPlugin = function(schema, options) { // if it is a leaf node, the maxRgt should be the lft value of the parent maxRgt = parentNode.lft; } - var conditions = updateConditions({lft: { $gt: maxRgt}}, self); + let conditions = updateConditions({lft: { $gt: maxRgt}}, self); self.constructor.updateMany(conditions, {$inc: {lft: 2}}, {multi: true}, function(err, updatedCount) { conditions = updateConditions({rgt: { $gt: maxRgt}}, self); self.constructor.updateMany(conditions, {$inc: {rgt: 2}}, {multi: true}, function(err, updatedCount2) { @@ -80,7 +80,7 @@ var NestedSetPlugin = function(schema, options) { }); schema.pre('remove', function(next) { - var self = this; + let self = this; if (self.parentId) { self.parent(function(err, parentNode) { if (!err && parentNode && parentNode.lft && parentNode.rgt) { @@ -88,7 +88,7 @@ var NestedSetPlugin = function(schema, options) { // find siblings and check if they have lft and rgt values set self.siblings(function(err, nodes) { if (nodes.every(function(node) { return node.lft && node.rgt;})) { - var maxRgt = 0; + let maxRgt = 0; nodes.forEach(function(node) { if (node.rgt > maxRgt) { maxRgt = node.rgt; @@ -98,7 +98,7 @@ var NestedSetPlugin = function(schema, options) { // if it is a leaf node, the maxRgt should be the lft value of the parent maxRgt = parentNode.lft; } - var conditions = updateConditions({lft: { $gt: maxRgt}}, self); + let conditions = updateConditions({lft: { $gt: maxRgt}}, self); self.constructor.updateMany(conditions, {$inc: {lft: -2}}, {multi: true}, function(err, updatedCount) { conditions = updateConditions({rgt: { $gt: maxRgt}}, self); self.constructor.updateMany(conditions, {$inc: {rgt: -2}}, {multi: true}, function(err, updatedCount2) { @@ -127,7 +127,7 @@ var NestedSetPlugin = function(schema, options) { // Builds the tree by populating lft and rgt using the parentIds schema.static('rebuildTree', function(parent, left, callback) { - var self = this; + let self = this; parent.lft = left; parent.rgt = left + 1; @@ -136,13 +136,13 @@ var NestedSetPlugin = function(schema, options) { if (!children) return callback(new Error(self.constructor.modelName + ' not found')); if (children.length > 0) { - async.forEach(children, function(item, cb) { + async.eachSeries(children, function(item, cb) { self.rebuildTree(item, parent.rgt, function() { parent.rgt = item.rgt + 1; self.updateOne({_id: parent._id}, {lft: parent.lft, rgt: parent.rgt}, cb); }); }, function(err) { - callback(err, 'erroraaaaa'); + callback(); }); } else { self.updateOne({_id: parent._id}, {lft: parent.lft, rgt: parent.rgt}, callback); @@ -162,25 +162,25 @@ var NestedSetPlugin = function(schema, options) { // Returns true if other is a descendant of self schema.method('isDescendantOf', function(other) { - var self = this; + let self = this; return other.lft < self.lft && self.lft < other.rgt; }); // Returns true if other is an ancestor of self schema.method('isAncestorOf', function(other) { - var self = this; + let self = this; return self.lft < other.lft && other.lft < self.rgt; }); // returns the parent node schema.method('parent', function(callback) { - var self = this; + let self = this; self.constructor.findById(self.parentId, callback); }); // Returns the list of ancestors + current node schema.method('selfAndAncestors', function(filters, fields, options, callback) { - var self = this; + let self = this; if ('function' === typeof filters) { callback = filters; filters = {}; @@ -210,7 +210,7 @@ var NestedSetPlugin = function(schema, options) { // Returns the list of ancestors schema.method('ancestors', function(filters, fields, options, callback) { - var self = this; + let self = this; if ('function' === typeof filters) { callback = filters; filters = {}; @@ -240,7 +240,7 @@ var NestedSetPlugin = function(schema, options) { // Returns the list of children schema.method('children', function(filters, fields, options, callback) { - var self = this; + let self = this; if ('function' === typeof filters) { callback = filters; filters = {}; @@ -268,7 +268,7 @@ var NestedSetPlugin = function(schema, options) { // Returns the list of children + current node schema.method('selfAndChildren',function(filters, fields, options, callback) { - var self = this; + let self = this; if ('function' === typeof filters) { callback = filters; filters = {}; @@ -296,7 +296,7 @@ var NestedSetPlugin = function(schema, options) { // Returns the list of descendants + current node schema.method('selfAndDescendants', function(filters, fields, options, callback) { - var self = this; + let self = this; if ('function' === typeof filters) { callback = filters; filters = {}; @@ -326,7 +326,7 @@ var NestedSetPlugin = function(schema, options) { // Returns the list of descendants schema.method('descendants', function(filters, fields, options, callback) { - var self = this; + let self = this; if ('function' === typeof filters) { callback = filters; filters = {}; @@ -356,7 +356,7 @@ var NestedSetPlugin = function(schema, options) { // Returns the list of all nodes with the same parent + current node schema.method('selfAndSiblings', function(filters, fields, options, callback) { - var self = this; + let self = this; if ('function' === typeof filters) { callback = filters; filters = {}; @@ -384,7 +384,7 @@ var NestedSetPlugin = function(schema, options) { // Returns the list of all nodes with the same parent schema.method('siblings', function(filters, fields, options, callback) { - var self = this; + let self = this; if ('function' === typeof filters) { callback = filters; filters = {}; @@ -414,7 +414,7 @@ var NestedSetPlugin = function(schema, options) { // Returns the level of this object in the tree. Root level is 0 schema.method('level', function(callback) { - var self = this; + let self = this; self.ancestors(function(err, nodes) { callback(err, nodes.length); }); From 5f0d61448b8603a7c81a279be863f4845a225114 Mon Sep 17 00:00:00 2001 From: Saleh Saeed Date: Tue, 11 Dec 2018 15:26:29 +0300 Subject: [PATCH 03/14] Reformat the code --- lib/nested_set.js | 802 +++++++++++++++++++++++----------------------- 1 file changed, 403 insertions(+), 399 deletions(-) diff --git a/lib/nested_set.js b/lib/nested_set.js index 9f15ed4..b07166f 100644 --- a/lib/nested_set.js +++ b/lib/nested_set.js @@ -6,419 +6,423 @@ const mongoose = require('mongoose'), Schema = mongoose.Schema, async = require('async'); -const NestedSetPlugin = function(schema, options) { - options = options || {}; - - schema.add({ lft: {type: Number, min: 0} }); - schema.add({ rgt: {type: Number, min: 0} }); - - // Allows level computong while editing the graph - schema.add({ lvl: {type: Number, min: 0, default:0} }); - schema.index({lvl: 1}); - - - schema.add({ parentId: {type: Schema.ObjectId} }); - - schema.index({parentId: 1}); - schema.index({lft: 1, rgt: 1}); - schema.index({rgt: 1}); - - let updateConditions = function (conditions, item) { - if (options.groupingKey) { - conditions[options.groupingKey] = item[options.groupingKey]; - } - return conditions; - }; - - schema.pre('save', function(next) { - let self = this; - if (self.parentId) { - self.parent(function(err, parentNode) { - if (!err && parentNode && parentNode.lft && parentNode.rgt) { - //Update level based on parentNode level - self.lvl = parentNode.lvl + 1; - // find siblings and check if they have lft and rgt values set - self.siblings(function(err, nodes) { - if (nodes.every(function(node) { return node.lft && node.rgt;})) { - let maxRgt = 0; - nodes.forEach(function(node) { - if (node.rgt > maxRgt) { - maxRgt = node.rgt; +const NestedSetPlugin = function (schema, options) { + options = options || {}; + + schema.add({lft: {type: Number, min: 0}}); + schema.add({rgt: {type: Number, min: 0}}); + + // Allows level computong while editing the graph + schema.add({lvl: {type: Number, min: 0, default: 0}}); + schema.index({lvl: 1}); + + + schema.add({parentId: {type: Schema.ObjectId}}); + + schema.index({parentId: 1}); + schema.index({lft: 1, rgt: 1}); + schema.index({rgt: 1}); + + let updateConditions = function (conditions, item) { + if (options.groupingKey) { + conditions[options.groupingKey] = item[options.groupingKey]; + } + return conditions; + }; + + schema.pre('save', function (next) { + let self = this; + if (self.parentId) { + self.parent(function (err, parentNode) { + if (!err && parentNode && parentNode.lft && parentNode.rgt) { + //Update level based on parentNode level + self.lvl = parentNode.lvl + 1; + // find siblings and check if they have lft and rgt values set + self.siblings(function (err, nodes) { + if (nodes.every(function (node) { + return node.lft && node.rgt; + })) { + let maxRgt = 0; + nodes.forEach(function (node) { + if (node.rgt > maxRgt) { + maxRgt = node.rgt; + } + }); + if (nodes.length === 0) { + // if it is a leaf node, the maxRgt should be the lft value of the parent + maxRgt = parentNode.lft; + } + let conditions = updateConditions({lft: {$gt: maxRgt}}, self); + self.constructor.updateMany(conditions, {$inc: {lft: 2}}, {multi: true}, function (err, updatedCount) { + conditions = updateConditions({rgt: {$gt: maxRgt}}, self); + self.constructor.updateMany(conditions, {$inc: {rgt: 2}}, {multi: true}, function (err, updatedCount2) { + self.lft = maxRgt + 1; + self.rgt = maxRgt + 2; + next(); + }); + }); + } else { + // the siblings do not have lft and rgt set. This means tree was not build. + // warn on console and move on. + // console.log('WARNING: tree is not built for ' + modelName + ' nodes. Siblings does not have lft/rgt'); + next(); + } + }); + } else { + // parent node does not have lft and rgt set. This means tree was not built. + // warn on console and move on. + // console.log('WARNING: tree is not built for ' + modelName + ' nodes. Parent does not have lft/rgt'); + next(); } - }); - if (nodes.length === 0) { - // if it is a leaf node, the maxRgt should be the lft value of the parent - maxRgt = parentNode.lft; - } - let conditions = updateConditions({lft: { $gt: maxRgt}}, self); - self.constructor.updateMany(conditions, {$inc: {lft: 2}}, {multi: true}, function(err, updatedCount) { - conditions = updateConditions({rgt: { $gt: maxRgt}}, self); - self.constructor.updateMany(conditions, {$inc: {rgt: 2}}, {multi: true}, function(err, updatedCount2) { - self.lft = maxRgt + 1; - self.rgt = maxRgt + 2; - next(); - }); - }); - } else { - // the siblings do not have lft and rgt set. This means tree was not build. - // warn on console and move on. - // console.log('WARNING: tree is not built for ' + modelName + ' nodes. Siblings does not have lft/rgt'); - next(); - } - }); + }); } else { - // parent node does not have lft and rgt set. This means tree was not built. - // warn on console and move on. - // console.log('WARNING: tree is not built for ' + modelName + ' nodes. Parent does not have lft/rgt'); - next(); - } - }); - } else { - // no parentId is set, so ignore - next(); - } - }); - - schema.pre('remove', function(next) { - let self = this; - if (self.parentId) { - self.parent(function(err, parentNode) { - if (!err && parentNode && parentNode.lft && parentNode.rgt) { - - // find siblings and check if they have lft and rgt values set - self.siblings(function(err, nodes) { - if (nodes.every(function(node) { return node.lft && node.rgt;})) { - let maxRgt = 0; - nodes.forEach(function(node) { - if (node.rgt > maxRgt) { - maxRgt = node.rgt; + // no parentId is set, so ignore + next(); + } + }); + + schema.pre('remove', function (next) { + let self = this; + if (self.parentId) { + self.parent(function (err, parentNode) { + if (!err && parentNode && parentNode.lft && parentNode.rgt) { + + // find siblings and check if they have lft and rgt values set + self.siblings(function (err, nodes) { + if (nodes.every(function (node) { + return node.lft && node.rgt; + })) { + let maxRgt = 0; + nodes.forEach(function (node) { + if (node.rgt > maxRgt) { + maxRgt = node.rgt; + } + }); + if (nodes.length === 0) { + // if it is a leaf node, the maxRgt should be the lft value of the parent + maxRgt = parentNode.lft; + } + let conditions = updateConditions({lft: {$gt: maxRgt}}, self); + self.constructor.updateMany(conditions, {$inc: {lft: -2}}, {multi: true}, function (err, updatedCount) { + conditions = updateConditions({rgt: {$gt: maxRgt}}, self); + self.constructor.updateMany(conditions, {$inc: {rgt: -2}}, {multi: true}, function (err, updatedCount2) { + next(); + }); + }); + } else { + // the siblings do not have lft and rgt set. This means tree was not build. + // warn on console and move on. + // console.log('WARNING: tree is not built for ' + modelName + ' nodes. Siblings does not have lft/rgt'); + next(); + } + }); + } else { + // parent node does not have lft and rgt set. This means tree was not built. + // warn on console and move on. + // console.log('WARNING: tree is not built for ' + modelName + ' nodes. Parent does not have lft/rgt'); + next(); } - }); - if (nodes.length === 0) { - // if it is a leaf node, the maxRgt should be the lft value of the parent - maxRgt = parentNode.lft; - } - let conditions = updateConditions({lft: { $gt: maxRgt}}, self); - self.constructor.updateMany(conditions, {$inc: {lft: -2}}, {multi: true}, function(err, updatedCount) { - conditions = updateConditions({rgt: { $gt: maxRgt}}, self); - self.constructor.updateMany(conditions, {$inc: {rgt: -2}}, {multi: true}, function(err, updatedCount2) { - next(); + }); + } else { + // no parentId is set, so ignore + next(); + } + }); + + // Builds the tree by populating lft and rgt using the parentIds + schema.static('rebuildTree', function (parent, left, callback) { + let self = this; + parent.lft = left; + parent.rgt = left + 1; + + self.find({parentId: parent._id}, function (err, children) { + if (err) return callback(err); + if (!children) return callback(new Error(self.constructor.modelName + ' not found')); + + if (children.length > 0) { + async.eachSeries(children, function (item, cb) { + self.rebuildTree(item, parent.rgt, function () { + parent.rgt = item.rgt + 1; + self.updateOne({_id: parent._id}, {lft: parent.lft, rgt: parent.rgt}, cb); + }); + }, function (err) { + callback(); }); - }); } else { - // the siblings do not have lft and rgt set. This means tree was not build. - // warn on console and move on. - // console.log('WARNING: tree is not built for ' + modelName + ' nodes. Siblings does not have lft/rgt'); - next(); + self.updateOne({_id: parent._id}, {lft: parent.lft, rgt: parent.rgt}, callback); } - }); - } else { - // parent node does not have lft and rgt set. This means tree was not built. - // warn on console and move on. - // console.log('WARNING: tree is not built for ' + modelName + ' nodes. Parent does not have lft/rgt'); - next(); - } - }); - } else { - // no parentId is set, so ignore - next(); - } - }); - - // Builds the tree by populating lft and rgt using the parentIds - schema.static('rebuildTree', function(parent, left, callback) { - let self = this; - parent.lft = left; - parent.rgt = left + 1; - - self.find({parentId: parent._id}, function(err, children) { - if (err) return callback(err); - if (!children) return callback(new Error(self.constructor.modelName + ' not found')); - - if (children.length > 0) { - async.eachSeries(children, function(item, cb) { - self.rebuildTree(item, parent.rgt, function() { - parent.rgt = item.rgt + 1; - self.updateOne({_id: parent._id}, {lft: parent.lft, rgt: parent.rgt}, cb); - }); - }, function(err) { - callback(); }); - } else { - self.updateOne({_id: parent._id}, {lft: parent.lft, rgt: parent.rgt}, callback); - } }); - }); - - // Returns true if the node is a leaf node (i.e. has no children) - schema.method('isLeaf', function() { - return this.lft && this.rgt && (this.rgt - this.lft === 1); - }); - - // Returns true if the node is a child node (i.e. has a parent) - schema.method('isChild', function() { - return !!this.parentId; - }); - - // Returns true if other is a descendant of self - schema.method('isDescendantOf', function(other) { - let self = this; - return other.lft < self.lft && self.lft < other.rgt; - }); - - // Returns true if other is an ancestor of self - schema.method('isAncestorOf', function(other) { - let self = this; - return self.lft < other.lft && other.lft < self.rgt; - }); - - // returns the parent node - schema.method('parent', function(callback) { - let self = this; - self.constructor.findById(self.parentId, callback); - }); - - // Returns the list of ancestors + current node - schema.method('selfAndAncestors', function(filters, fields, options, callback) { - let self = this; - if ('function' === typeof filters) { - callback = filters; - filters = {}; - } - else if ('function' === typeof fields) { - callback = fields; - fields = null; - } - else if ('function' === typeof options) { - callback = options; - options = {}; - } - - filters = filters || {}; - fields = fields || null; - options = options || {}; - if(filters['$query']){ - filters['$query']['lft'] = { $lte: self.lft }; - filters['$query']['rgt'] = { $gte: self.rgt }; - } else { - filters['lft'] = { $lte: self.lft }; - filters['rgt'] = { $gte: self.rgt }; - } - self.constructor.find(filters, fields, options, callback); - }); - - // Returns the list of ancestors - schema.method('ancestors', function(filters, fields, options, callback) { - let self = this; - if ('function' === typeof filters) { - callback = filters; - filters = {}; - } - else if ('function' === typeof fields) { - callback = fields; - fields = null; - } - else if ('function' === typeof options) { - callback = options; - options = {}; - } - - filters = filters || {}; - fields = fields || null; - options = options || {}; + // Returns true if the node is a leaf node (i.e. has no children) + schema.method('isLeaf', function () { + return this.lft && this.rgt && (this.rgt - this.lft === 1); + }); - if(filters['$query']){ - filters['$query']['lft'] = { $lt: self.lft }; - filters['$query']['rgt'] = { $gt: self.rgt }; - } else { - filters['lft'] = { $lt: self.lft }; - filters['rgt'] = { $gt: self.rgt }; - } - self.constructor.find(filters, fields, options, callback); - }); - - // Returns the list of children - schema.method('children', function(filters, fields, options, callback) { - let self = this; - if ('function' === typeof filters) { - callback = filters; - filters = {}; - } - else if ('function' === typeof fields) { - callback = fields; - fields = null; - } - else if ('function' === typeof options) { - callback = options; - options = {}; - } - - filters = filters || {}; - fields = fields || null; - options = options || {}; - - if(filters['$query']){ - filters['$query']['parentId'] = self._id; - } else { - filters['parentId'] = self._id; - } - self.constructor.find(filters, fields, options, callback); - }); - - // Returns the list of children + current node - schema.method('selfAndChildren',function(filters, fields, options, callback) { - let self = this; - if ('function' === typeof filters) { - callback = filters; - filters = {}; - } - else if ('function' === typeof fields) { - callback = fields; - fields = null; - } - else if ('function' === typeof options) { - callback = options; - options = {}; - } - - filters = filters || {}; - fields = fields || null; - options = options || {}; - - if(filters['$query']){ - filters['$query']['$or'] = [{ parentId: self._id }, {_id: self._id }] ; - } else { - filters['$or'] = [{ parentId: self._id }, {_id: self._id }]; - } - self.constructor.find(filters, fields, options, callback); - }); - - // Returns the list of descendants + current node - schema.method('selfAndDescendants', function(filters, fields, options, callback) { - let self = this; - if ('function' === typeof filters) { - callback = filters; - filters = {}; - } - else if ('function' === typeof fields) { - callback = fields; - fields = null; - } - else if ('function' === typeof options) { - callback = options; - options = {}; - } - - filters = filters || {}; - fields = fields || null; - options = options || {}; + // Returns true if the node is a child node (i.e. has a parent) + schema.method('isChild', function () { + return !!this.parentId; + }); - if(filters['$query']){ - filters['$query']['lft'] = { $gte: self.lft }; - filters['$query']['rgt'] = { $lte: self.rgt }; - } else { - filters['lft'] = { $gte: self.lft }; - filters['rgt'] = { $lte: self.rgt }; - } - self.constructor.find(filters, fields, options, callback); - }); - - // Returns the list of descendants - schema.method('descendants', function(filters, fields, options, callback) { - let self = this; - if ('function' === typeof filters) { - callback = filters; - filters = {}; - } - else if ('function' === typeof fields) { - callback = fields; - fields = null; - } - else if ('function' === typeof options) { - callback = options; - options = {}; - } - - filters = filters || {}; - fields = fields || null; - options = options || {}; + // Returns true if other is a descendant of self + schema.method('isDescendantOf', function (other) { + let self = this; + return other.lft < self.lft && self.lft < other.rgt; + }); - if(filters['$query']){ - filters['$query']['lft'] = { $gt: self.lft }; - filters['$query']['rgt'] = { $lt: self.rgt }; - } else { - filters['lft'] = { $gt: self.lft }; - filters['rgt'] = { $lt: self.rgt }; - } - self.constructor.find(filters, fields, options, callback); - }); - - // Returns the list of all nodes with the same parent + current node - schema.method('selfAndSiblings', function(filters, fields, options, callback) { - let self = this; - if ('function' === typeof filters) { - callback = filters; - filters = {}; - } - else if ('function' === typeof fields) { - callback = fields; - fields = null; - } - else if ('function' === typeof options) { - callback = options; - options = {}; - } - - filters = filters || {}; - fields = fields || null; - options = options || {}; - - if(filters['$query']){ - filters['$query']['parentId'] = self.parentId; - } else { - filters['parentId'] = self.parentId; - } - self.constructor.find(filters, fields, options, callback); - }); - - // Returns the list of all nodes with the same parent - schema.method('siblings', function(filters, fields, options, callback) { - let self = this; - if ('function' === typeof filters) { - callback = filters; - filters = {}; - } - else if ('function' === typeof fields) { - callback = fields; - fields = null; - } - else if ('function' === typeof options) { - callback = options; - options = {}; - } - - filters = filters || {}; - fields = fields || null; - options = options || {}; + // Returns true if other is an ancestor of self + schema.method('isAncestorOf', function (other) { + let self = this; + return self.lft < other.lft && other.lft < self.rgt; + }); + + // returns the parent node + schema.method('parent', function (callback) { + let self = this; + self.constructor.findById(self.parentId, callback); + }); + + // Returns the list of ancestors + current node + schema.method('selfAndAncestors', function (filters, fields, options, callback) { + let self = this; + if ('function' === typeof filters) { + callback = filters; + filters = {}; + } + else if ('function' === typeof fields) { + callback = fields; + fields = null; + } + else if ('function' === typeof options) { + callback = options; + options = {}; + } + + filters = filters || {}; + fields = fields || null; + options = options || {}; + + if (filters['$query']) { + filters['$query']['lft'] = {$lte: self.lft}; + filters['$query']['rgt'] = {$gte: self.rgt}; + } else { + filters['lft'] = {$lte: self.lft}; + filters['rgt'] = {$gte: self.rgt}; + } + self.constructor.find(filters, fields, options, callback); + }); + + // Returns the list of ancestors + schema.method('ancestors', function (filters, fields, options, callback) { + let self = this; + if ('function' === typeof filters) { + callback = filters; + filters = {}; + } + else if ('function' === typeof fields) { + callback = fields; + fields = null; + } + else if ('function' === typeof options) { + callback = options; + options = {}; + } + + filters = filters || {}; + fields = fields || null; + options = options || {}; + + if (filters['$query']) { + filters['$query']['lft'] = {$lt: self.lft}; + filters['$query']['rgt'] = {$gt: self.rgt}; + } else { + filters['lft'] = {$lt: self.lft}; + filters['rgt'] = {$gt: self.rgt}; + } + self.constructor.find(filters, fields, options, callback); + }); + + // Returns the list of children + schema.method('children', function (filters, fields, options, callback) { + let self = this; + if ('function' === typeof filters) { + callback = filters; + filters = {}; + } + else if ('function' === typeof fields) { + callback = fields; + fields = null; + } + else if ('function' === typeof options) { + callback = options; + options = {}; + } - if(filters['$query']){ - filters['$query']['parentId'] = self.parentId; - filters['$query']['_id'] = { $ne: self._id } ; - } else { - filters['parentId'] = self.parentId; - filters['_id'] = { $ne: self._id } ; - } - self.constructor.find(filters, fields, options, callback); - }); - - // Returns the level of this object in the tree. Root level is 0 - schema.method('level', function(callback) { - let self = this; - self.ancestors(function(err, nodes) { - callback(err, nodes.length); + filters = filters || {}; + fields = fields || null; + options = options || {}; + + if (filters['$query']) { + filters['$query']['parentId'] = self._id; + } else { + filters['parentId'] = self._id; + } + self.constructor.find(filters, fields, options, callback); + }); + + // Returns the list of children + current node + schema.method('selfAndChildren', function (filters, fields, options, callback) { + let self = this; + if ('function' === typeof filters) { + callback = filters; + filters = {}; + } + else if ('function' === typeof fields) { + callback = fields; + fields = null; + } + else if ('function' === typeof options) { + callback = options; + options = {}; + } + + filters = filters || {}; + fields = fields || null; + options = options || {}; + + if (filters['$query']) { + filters['$query']['$or'] = [{parentId: self._id}, {_id: self._id}]; + } else { + filters['$or'] = [{parentId: self._id}, {_id: self._id}]; + } + self.constructor.find(filters, fields, options, callback); + }); + + // Returns the list of descendants + current node + schema.method('selfAndDescendants', function (filters, fields, options, callback) { + let self = this; + if ('function' === typeof filters) { + callback = filters; + filters = {}; + } + else if ('function' === typeof fields) { + callback = fields; + fields = null; + } + else if ('function' === typeof options) { + callback = options; + options = {}; + } + + filters = filters || {}; + fields = fields || null; + options = options || {}; + + if (filters['$query']) { + filters['$query']['lft'] = {$gte: self.lft}; + filters['$query']['rgt'] = {$lte: self.rgt}; + } else { + filters['lft'] = {$gte: self.lft}; + filters['rgt'] = {$lte: self.rgt}; + } + self.constructor.find(filters, fields, options, callback); + }); + + // Returns the list of descendants + schema.method('descendants', function (filters, fields, options, callback) { + let self = this; + if ('function' === typeof filters) { + callback = filters; + filters = {}; + } + else if ('function' === typeof fields) { + callback = fields; + fields = null; + } + else if ('function' === typeof options) { + callback = options; + options = {}; + } + + filters = filters || {}; + fields = fields || null; + options = options || {}; + + if (filters['$query']) { + filters['$query']['lft'] = {$gt: self.lft}; + filters['$query']['rgt'] = {$lt: self.rgt}; + } else { + filters['lft'] = {$gt: self.lft}; + filters['rgt'] = {$lt: self.rgt}; + } + self.constructor.find(filters, fields, options, callback); + }); + + // Returns the list of all nodes with the same parent + current node + schema.method('selfAndSiblings', function (filters, fields, options, callback) { + let self = this; + if ('function' === typeof filters) { + callback = filters; + filters = {}; + } + else if ('function' === typeof fields) { + callback = fields; + fields = null; + } + else if ('function' === typeof options) { + callback = options; + options = {}; + } + + filters = filters || {}; + fields = fields || null; + options = options || {}; + + if (filters['$query']) { + filters['$query']['parentId'] = self.parentId; + } else { + filters['parentId'] = self.parentId; + } + self.constructor.find(filters, fields, options, callback); + }); + + // Returns the list of all nodes with the same parent + schema.method('siblings', function (filters, fields, options, callback) { + let self = this; + if ('function' === typeof filters) { + callback = filters; + filters = {}; + } + else if ('function' === typeof fields) { + callback = fields; + fields = null; + } + else if ('function' === typeof options) { + callback = options; + options = {}; + } + + filters = filters || {}; + fields = fields || null; + options = options || {}; + + if (filters['$query']) { + filters['$query']['parentId'] = self.parentId; + filters['$query']['_id'] = {$ne: self._id}; + } else { + filters['parentId'] = self.parentId; + filters['_id'] = {$ne: self._id}; + } + self.constructor.find(filters, fields, options, callback); + }); + + // Returns the level of this object in the tree. Root level is 0 + schema.method('level', function (callback) { + let self = this; + self.ancestors(function (err, nodes) { + callback(err, nodes.length); + }); }); - }); }; module.exports = exports = NestedSetPlugin; From c1fcf617cdf1e0545e6e7b7016d13f4d4834ceef Mon Sep 17 00:00:00 2001 From: Saleh Saeed Date: Tue, 11 Dec 2018 16:30:15 +0300 Subject: [PATCH 04/14] Fix save middleware in case there is no siblings --- lib/nested_set.js | 70 ++++-- tests/nested_set.js | 512 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 561 insertions(+), 21 deletions(-) create mode 100644 tests/nested_set.js diff --git a/lib/nested_set.js b/lib/nested_set.js index b07166f..b385d8e 100644 --- a/lib/nested_set.js +++ b/lib/nested_set.js @@ -39,33 +39,61 @@ const NestedSetPlugin = function (schema, options) { self.lvl = parentNode.lvl + 1; // find siblings and check if they have lft and rgt values set self.siblings(function (err, nodes) { - if (nodes.every(function (node) { - return node.lft && node.rgt; - })) { - let maxRgt = 0; - nodes.forEach(function (node) { - if (node.rgt > maxRgt) { - maxRgt = node.rgt; + if (nodes.length > 0) { + if (nodes.every(function (node) { + return node.lft && node.rgt; + })) { + let maxRgt = 0; + nodes.forEach(function (node) { + if (node.rgt > maxRgt) { + maxRgt = node.rgt; + } + }); + if (nodes.length === 0) { + // if it is a leaf node, the maxRgt should be the lft value of the parent + maxRgt = parentNode.lft; } - }); - if (nodes.length === 0) { - // if it is a leaf node, the maxRgt should be the lft value of the parent - maxRgt = parentNode.lft; - } - let conditions = updateConditions({lft: {$gt: maxRgt}}, self); - self.constructor.updateMany(conditions, {$inc: {lft: 2}}, {multi: true}, function (err, updatedCount) { - conditions = updateConditions({rgt: {$gt: maxRgt}}, self); - self.constructor.updateMany(conditions, {$inc: {rgt: 2}}, {multi: true}, function (err, updatedCount2) { + + async.series([ + function (cb) { + let conditions = updateConditions({lft: {$gt: maxRgt}}, self); + self.constructor.updateMany(conditions, {$inc: {lft: 2}}, cb); + }, + function (cb) { + let conditions = updateConditions({rgt: {$gt: maxRgt}}, self); + self.constructor.updateMany(conditions, {$inc: {rgt: 2}}, cb); + } + ], function (err, result) { self.lft = maxRgt + 1; self.rgt = maxRgt + 2; + next(); }); + } else { + // the siblings do not have lft and rgt set. This means tree was not build. + // warn on console and move on. + // console.log('WARNING: tree is not built for ' + modelName + ' nodes. Siblings does not have lft/rgt'); + next(); + } + }else{ + // if it is a leaf node, the maxRgt should be the lft value of the parent + let maxRgt = parentNode.lft; + + async.series([ + function (cb) { + let conditions = updateConditions({lft: {$gt: maxRgt}}, self); + self.constructor.updateMany(conditions, {$inc: {lft: 2}}, cb); + }, + function (cb) { + let conditions = updateConditions({rgt: {$gt: maxRgt}}, self); + self.constructor.updateMany(conditions, {$inc: {rgt: 2}}, cb); + } + ], function (err, result) { + self.lft = maxRgt + 1; + self.rgt = maxRgt + 2; + + next(); }); - } else { - // the siblings do not have lft and rgt set. This means tree was not build. - // warn on console and move on. - // console.log('WARNING: tree is not built for ' + modelName + ' nodes. Siblings does not have lft/rgt'); - next(); } }); } else { diff --git a/tests/nested_set.js b/tests/nested_set.js new file mode 100644 index 0000000..edb4a26 --- /dev/null +++ b/tests/nested_set.js @@ -0,0 +1,512 @@ +/*globals require, module, console */ + +'use strict'; + +let mongoose = require('mongoose'), + Schema = mongoose.Schema, + assert = require('assert'), + async = require('async'), + Helpers = require('./helpers'), + NestedSetPlugin = require('../lib/nested_set'); + +let UserSchema, + User; + +before(function (done) { + async.series([ + function (callback) { + mongoose.connect('mongodb://localhost/nested_set_test', {useNewUrlParser: true}); + mongoose.set('useCreateIndex', true); + callback(); + }, + function (callback) { + UserSchema = new Schema({ + username: {type: String} + }); + UserSchema.plugin(NestedSetPlugin); + User = mongoose.model('User', UserSchema); + callback(null); + }, + function (callback) { + // see diagram in docs/test_tree.png for a representation of this tree + let michael = new User({username: 'michael'}); + + let meredith = new User({username: 'meredith', parentId: michael._id}); + let jim = new User({username: 'jim', parentId: michael._id}); + let angela = new User({username: 'angela', parentId: michael._id}); + + let kelly = new User({username: 'kelly', parentId: meredith._id}); + let creed = new User({username: 'creed', parentId: meredith._id}); + + let phyllis = new User({username: 'phyllis', parentId: jim._id}); + let stanley = new User({username: 'stanley', parentId: jim._id}); + let dwight = new User({username: 'dwight', parentId: jim._id}); + + let oscar = new User({username: 'oscar', parentId: angela._id}); + + async.eachSeries([ + michael, + meredith, + jim, + angela, + kelly, + creed, + phyllis, + stanley, + dwight, + oscar + ], function (item, cb) { + item.save(cb); + }, callback); + } + ], function (err, results) { + if (!err) done(); + }); +}); + +after(function (done) { + mongoose.connection.collections.users.drop(function (err) { + mongoose.disconnect(); + }); + done(); +}); + +describe('Normal nested set', function () { + it('is same', function (done) { + assert.ok(User); + assert.equal('function', typeof User); + assert.equal('User', User.modelName); + done(); + }); + + it('has created users for testing', function (done) { + User.find(function (err, users) { + if (err) { + console.log(err); + } + assert.ok(!err); + assert.ok(users); + assert.ok(users instanceof Array); + assert.equal(10, users.length); + done(); + }); + }); + + it('can read parentIds as ObjectIDs', function (done) { + User.find(function (err, users) { + if (err) { + console.log(err); + } + assert.ok(!err); + users.forEach(function (user) { + if (user.parentId) { + assert.ok(Helpers.isObjectId(user.parentId)); + } + }); + done(); + }); + }); + + it('rebuildTree should set lft and rgt based on parentIds', function (done) { + User.findOne({username: 'michael'}, function (err, user) { + User.rebuildTree(user, 1, function (err) { + if (err) console.log(err); + User.find({}, function (err, users) { + // see docs/test_tree.png for the graphical representation of this tree with lft/rgt values + users.forEach(function (person) { + if (person.username === 'michael') { + assert.equal(1, person.lft); + assert.equal(20, person.rgt); + } else if (person.username === 'meredith') { + assert.equal(2, person.lft); + assert.equal(7, person.rgt); + } else if (person.username === 'jim') { + assert.equal(8, person.lft); + assert.equal(15, person.rgt); + } else if (person.username === 'angela') { + assert.equal(16, person.lft); + assert.equal(19, person.rgt); + } else if (person.username === 'kelly') { + assert.equal(3, person.lft); + assert.equal(4, person.rgt); + } else if (person.username === 'creed') { + assert.equal(5, person.lft); + assert.equal(6, person.rgt); + } else if (person.username === 'phyllis') { + assert.equal(9, person.lft); + assert.equal(10, person.rgt); + } else if (person.username === 'stanley') { + assert.equal(11, person.lft); + assert.equal(12, person.rgt); + } else if (person.username === 'dwight') { + assert.equal(13, person.lft); + assert.equal(14, person.rgt); + } else if (person.username === 'oscar') { + assert.equal(17, person.lft); + assert.equal(18, person.rgt); + } + }); + done(); + }); + }); + }); + }); + + it('isLeaf should return true if node is leaf', function (done) { + User.findOne({username: 'michael'}, function (err, user) { + User.rebuildTree(user, 1, function () { + User.findOne({username: 'kelly'}, function (err, kelly) { + assert.ok(kelly.isLeaf()); + User.findOne({username: 'michael'}, function (err, michael) { + assert.ok(!michael.isLeaf()); + done(); + }); + }); + }); + }); + }); + + it('isChild should return true if node has a parent', function (done) { + User.findOne({username: 'michael'}, function (err, user) { + User.rebuildTree(user, 1, function () { + User.findOne({username: 'kelly'}, function (err, kelly) { + assert.ok(kelly.isChild()); + User.findOne({username: 'michael'}, function (err, michael) { + assert.ok(!michael.isChild()); + done(); + }); + }); + }); + }); + }); + + it('parent should return parent node', function (done) { + User.findOne({username: 'michael'}, function (err, user) { + User.rebuildTree(user, 1, function () { + User.findOne({username: 'kelly'}, function (err, kelly) { + assert.ok(!err); + assert.ok(kelly); + kelly.parent(function (err, node) { + assert.ok(!err); + assert.equal('meredith', node.username); + done(); + }); + }); + }); + }); + }); + + it('selfAndAncestors should return all ancestors higher up in tree + current node', function (done) { + User.findOne({username: 'michael'}, function (err, user) { + User.rebuildTree(user, 1, function () { + User.findOne({username: 'kelly'}, function (err, kelly) { + kelly.selfAndAncestors(function (err, people) { + assert.ok(!err); + assert.deepEqual(['kelly', 'meredith', 'michael'], people.map(function (p) { + return p.username; + }).sort()); + done(); + }); + }); + }); + }); + }); + + it('ancestors should return all ancestors higher up in tree', function (done) { + User.findOne({username: 'michael'}, function (err, user) { + User.rebuildTree(user, 1, function () { + User.findOne({username: 'kelly'}, function (err, kelly) { + kelly.ancestors(function (err, people) { + assert.ok(!err); + assert.deepEqual(['meredith', 'michael'], people.map(function (p) { + return p.username; + }).sort()); + done(); + }); + }); + }); + }); + }); + + it('ancestors should return empty array if it is a root node', function (done) { + User.findOne({username: 'michael'}, function (err, user) { + User.rebuildTree(user, 1, function () { + User.findOne({username: 'michael'}, function (err, michael) { + michael.ancestors(function (err, people) { + assert.ok(!err); + assert.deepEqual([], people.map(function (p) { + return p.username; + }).sort()); + done(); + }); + }); + }); + }); + }); + + it('selfAndChildren should return all children + current node', function (done) { + User.findOne({username: 'michael'}, function (err, user) { + User.rebuildTree(user, 1, function () { + User.findOne({username: 'michael'}, function (err, michael) { + michael.selfAndChildren(function (err, people) { + assert.ok(!err); + assert.deepEqual(['angela', 'jim', 'meredith', 'michael'], people.map(function (p) { + return p.username; + }).sort()); + done(); + }); + }); + }); + }); + }); + + it('children should return all children', function (done) { + User.findOne({username: 'michael'}, function (err, user) { + User.rebuildTree(user, 1, function () { + User.findOne({username: 'michael'}, function (err, michael) { + michael.children(function (err, people) { + assert.ok(!err); + assert.deepEqual(['angela', 'jim', 'meredith'], people.map(function (p) { + return p.username; + }).sort()); + done(); + }); + }); + }); + }); + }); + + it('selfAndDescendants should return all descendants + current node', function (done) { + User.findOne({username: 'michael'}, function (err, user) { + User.rebuildTree(user, 1, function () { + User.findOne({username: 'michael'}, function (err, michael) { + michael.selfAndDescendants(function (err, people) { + assert.ok(!err); + assert.deepEqual( + ['angela', 'creed', 'dwight', 'jim', 'kelly', 'meredith', 'michael', 'oscar', 'phyllis', 'stanley'], + people.map(function (p) { + return p.username; + }).sort() + ); + done(); + }); + }); + }); + }); + }); + + it('descendants should return all descendants', function (done) { + User.findOne({username: 'michael'}, function (err, user) { + User.rebuildTree(user, 1, function () { + User.findOne({username: 'michael'}, function (err, michael) { + michael.descendants(function (err, people) { + assert.ok(!err); + assert.deepEqual( + ['angela', 'creed', 'dwight', 'jim', 'kelly', 'meredith', 'oscar', 'phyllis', 'stanley'], + people.map(function (p) { + return p.username; + }).sort() + ); + done(); + }); + }); + }); + }); + }); + + it('level should return 0 for root node', function (done) { + User.findOne({username: 'michael'}, function (err, user) { + User.rebuildTree(user, 1, function () { + User.findOne({username: 'michael'}, function (err, michael) { + michael.level(function (err, value) { + assert.ok(!err); + assert.equal(0, value); + done(); + }); + }); + }); + }); + }); + + it('selfAndSiblings should return all nodes with same parent node + current node', function (done) { + User.findOne({username: 'michael'}, function (err, user) { + User.rebuildTree(user, 1, function () { + User.findOne({username: 'meredith'}, function (err, meredith) { + meredith.selfAndSiblings(function (err, people) { + assert.ok(!err); + assert.deepEqual( + ['angela', 'jim', 'meredith'], + people.map(function (p) { + return p.username; + }).sort() + ); + done(); + }); + }); + }); + }); + }); + + it('siblings should return all nodes with same parent node', function (done) { + User.findOne({username: 'michael'}, function (err, user) { + User.rebuildTree(user, 1, function () { + User.findOne({username: 'meredith'}, function (err, meredith) { + meredith.siblings(function (err, people) { + assert.ok(!err); + assert.deepEqual( + ['angela', 'jim'], + people.map(function (p) { + return p.username; + }).sort() + ); + done(); + }); + }); + }); + }); + }); + + it('kelly is a descendant of michael', function (done) { + User.findOne({username: 'michael'}, function (err, michael) { + User.rebuildTree(michael, 1, function () { + User.findOne({username: 'kelly'}, function (err, kelly) { + assert.ok(kelly.isDescendantOf(michael)); + assert.ok(!michael.isDescendantOf(kelly)); + done(); + }); + }); + }); + }); + + it('michael is an ancestor of kelly', function (done) { + User.findOne({username: 'michael'}, function (err, michael) { + User.rebuildTree(michael, 1, function () { + User.findOne({username: 'kelly'}, function (err, kelly) { + assert.ok(michael.isAncestorOf(kelly)); + assert.ok(!kelly.isAncestorOf(michael)); + done(); + }); + }); + }); + }); + + it('pre save middleware should not set lft and rgt if there is no parentId', function (done) { + let user = new User({ + username: 'joe' + }); + + user.save(function (err, joe) { + assert.ok(!err); + assert.equal('joe', joe.username); + assert.ok(!joe.lft); + assert.ok(!joe.rgt); + + user.remove(); // Remove user after assertion + + done(); + }); + }); + + it('adding a new node to a built tree should re-arrange the tree correctly', function (done) { + User.findOne({username: 'michael'}, function (err, michael) { + User.rebuildTree(michael, 1, function () { + User.findOne({username: 'creed'}, function (err, creed) { + //console.log(creed); + let newUser = new User({ + username: 'joe', + parentId: creed._id + }); + newUser.save(function (err, joe) { + User.find(function (err, users) { + // see docs/test_tree_after_leaf_insertion.png for the graphical representation of this tree + // with lft/rgt values after the insertion + users.forEach(function (person) { + if (person.username === 'michael') { + assert.equal(1, person.lft); + assert.equal(22, person.rgt); + } else if (person.username === 'meredith') { + assert.equal(2, person.lft); + assert.equal(9, person.rgt); + } else if (person.username === 'jim') { + assert.equal(10, person.lft); + assert.equal(17, person.rgt); + } else if (person.username === 'angela') { + assert.equal(18, person.lft); + assert.equal(21, person.rgt); + } else if (person.username === 'kelly') { + assert.equal(3, person.lft); + assert.equal(4, person.rgt); + } else if (person.username === 'creed') { + assert.equal(5, person.lft); + assert.equal(8, person.rgt); + } else if (person.username === 'phyllis') { + assert.equal(11, person.lft); + assert.equal(12, person.rgt); + } else if (person.username === 'stanley') { + assert.equal(13, person.lft); + assert.equal(14, person.rgt); + } else if (person.username === 'dwight') { + assert.equal(15, person.lft); + assert.equal(16, person.rgt); + } else if (person.username === 'oscar') { + assert.equal(19, person.lft); + assert.equal(20, person.rgt); + } else if (person.username === 'joe') { + assert.equal(6, person.lft); + assert.equal(7, person.rgt); + } + }); + done(); + }); + }); + }); + }); + }); + }); + + it('removing a node to a built tree should re-arrange the tree correctly', function (done) { + User.findOne({username: 'michael'}, function(err, michael) { + User.rebuildTree(michael, 1, function() { + User.findOne({username: 'creed'}, function(err, creed) { + creed.remove(function() { + User.find(function(err, users) { + // see docs/test_tree_after_leaf_insertion.png for the graphical representation of this tree + // with lft/rgt values after the insertion + users.forEach(function(person) { + if (person.username === 'michael') { + assert.equal(1, person.lft); + assert.equal(18, person.rgt); + } else if (person.username === 'meredith') { + assert.equal(2, person.lft); + assert.equal(5, person.rgt); + } else if (person.username === 'jim') { + assert.equal(6, person.lft); + assert.equal(13, person.rgt); + } else if (person.username === 'angela') { + assert.equal(14, person.lft); + assert.equal(17, person.rgt); + } else if (person.username === 'kelly') { + assert.equal(3, person.lft); + assert.equal(4, person.rgt); + } else if (person.username === 'phyllis') { + assert.equal(7, person.lft); + assert.equal(8, person.rgt); + } else if (person.username === 'stanley') { + assert.equal(9, person.lft); + assert.equal(10, person.rgt); + } else if (person.username === 'dwight') { + assert.equal(11, person.lft); + assert.equal(12, person.rgt); + } else if (person.username === 'oscar') { + assert.equal(15, person.lft); + assert.equal(16, person.rgt); + } + }); + done(); + }); + }); + }); + }); + }); + }); +}); \ No newline at end of file From 48ef9deb6d3f4e111516bc80a123e90e9fb812fc Mon Sep 17 00:00:00 2001 From: Saleh Saeed Date: Tue, 11 Dec 2018 16:45:55 +0300 Subject: [PATCH 05/14] Fix remove middleware test --- lib/nested_set.js | 72 ++++++++++++++++++--------------------------- tests/nested_set.js | 2 ++ 2 files changed, 31 insertions(+), 43 deletions(-) diff --git a/lib/nested_set.js b/lib/nested_set.js index b385d8e..dc68380 100644 --- a/lib/nested_set.js +++ b/lib/nested_set.js @@ -39,45 +39,19 @@ const NestedSetPlugin = function (schema, options) { self.lvl = parentNode.lvl + 1; // find siblings and check if they have lft and rgt values set self.siblings(function (err, nodes) { - if (nodes.length > 0) { - if (nodes.every(function (node) { - return node.lft && node.rgt; - })) { - let maxRgt = 0; - nodes.forEach(function (node) { - if (node.rgt > maxRgt) { - maxRgt = node.rgt; - } - }); - if (nodes.length === 0) { - // if it is a leaf node, the maxRgt should be the lft value of the parent - maxRgt = parentNode.lft; + if (nodes.every(function (node) { + return node.lft && node.rgt; + })) { + let maxRgt = 0; + nodes.forEach(function (node) { + if (node.rgt > maxRgt) { + maxRgt = node.rgt; } - - async.series([ - function (cb) { - let conditions = updateConditions({lft: {$gt: maxRgt}}, self); - self.constructor.updateMany(conditions, {$inc: {lft: 2}}, cb); - }, - function (cb) { - let conditions = updateConditions({rgt: {$gt: maxRgt}}, self); - self.constructor.updateMany(conditions, {$inc: {rgt: 2}}, cb); - } - ], function (err, result) { - self.lft = maxRgt + 1; - self.rgt = maxRgt + 2; - - next(); - }); - } else { - // the siblings do not have lft and rgt set. This means tree was not build. - // warn on console and move on. - // console.log('WARNING: tree is not built for ' + modelName + ' nodes. Siblings does not have lft/rgt'); - next(); + }); + if (nodes.length === 0) { + // if it is a leaf node, the maxRgt should be the lft value of the parent + maxRgt = parentNode.lft; } - }else{ - // if it is a leaf node, the maxRgt should be the lft value of the parent - let maxRgt = parentNode.lft; async.series([ function (cb) { @@ -94,6 +68,11 @@ const NestedSetPlugin = function (schema, options) { next(); }); + } else { + // the siblings do not have lft and rgt set. This means tree was not build. + // warn on console and move on. + // console.log('WARNING: tree is not built for ' + modelName + ' nodes. Siblings does not have lft/rgt'); + next(); } }); } else { @@ -130,12 +109,18 @@ const NestedSetPlugin = function (schema, options) { // if it is a leaf node, the maxRgt should be the lft value of the parent maxRgt = parentNode.lft; } - let conditions = updateConditions({lft: {$gt: maxRgt}}, self); - self.constructor.updateMany(conditions, {$inc: {lft: -2}}, {multi: true}, function (err, updatedCount) { - conditions = updateConditions({rgt: {$gt: maxRgt}}, self); - self.constructor.updateMany(conditions, {$inc: {rgt: -2}}, {multi: true}, function (err, updatedCount2) { - next(); - }); + + async.series([ + function (cb) { + let conditions = updateConditions({lft: {$gt: maxRgt}}, self); + self.constructor.updateMany(conditions, {$inc: {lft: -2}}, cb); + }, + function (cb) { + let conditions = updateConditions({rgt: {$gt: maxRgt}}, self); + self.constructor.updateMany(conditions, {$inc: {rgt: -2}}, cb); + } + ], function (err, result) { + next(); }); } else { // the siblings do not have lft and rgt set. This means tree was not build. @@ -143,6 +128,7 @@ const NestedSetPlugin = function (schema, options) { // console.log('WARNING: tree is not built for ' + modelName + ' nodes. Siblings does not have lft/rgt'); next(); } + }); } else { // parent node does not have lft and rgt set. This means tree was not built. diff --git a/tests/nested_set.js b/tests/nested_set.js index edb4a26..c3fcd1f 100644 --- a/tests/nested_set.js +++ b/tests/nested_set.js @@ -457,6 +457,8 @@ describe('Normal nested set', function () { } }); done(); + + newUser.remove(); // Remove user after assertion }); }); }); From 2cd55c0a968f3c9da1a3811138fc9a8e74d313e4 Mon Sep 17 00:00:00 2001 From: Saleh Saeed Date: Tue, 11 Dec 2018 16:47:10 +0300 Subject: [PATCH 06/14] Add .idea and npm-debug.log to .gitignore --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index bded1e2..839ff57 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ node_modules -npm-debug.log +npm-debug.log* .DS_Store */.DS_Store + +.idea/ From 649e8e1ea2b42109c1982118d43f6dca36c12f24 Mon Sep 17 00:00:00 2001 From: Saleh Saeed Date: Tue, 11 Dec 2018 16:48:13 +0300 Subject: [PATCH 07/14] Change test file name --- tests/{nested_set.js => nested_set_test.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{nested_set.js => nested_set_test.js} (100%) diff --git a/tests/nested_set.js b/tests/nested_set_test.js similarity index 100% rename from tests/nested_set.js rename to tests/nested_set_test.js From 04dc94ee799fa52525ddd2005512c44263f1f60d Mon Sep 17 00:00:00 2001 From: Saleh Saeed Date: Tue, 11 Dec 2018 17:24:35 +0300 Subject: [PATCH 08/14] Add test for groupingKey --- tests/nested_set_groupingKey_test.js | 216 +++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 tests/nested_set_groupingKey_test.js diff --git a/tests/nested_set_groupingKey_test.js b/tests/nested_set_groupingKey_test.js new file mode 100644 index 0000000..3521209 --- /dev/null +++ b/tests/nested_set_groupingKey_test.js @@ -0,0 +1,216 @@ +/*globals require, module, console */ + +'use strict'; + +let mongoose = require('mongoose'), + Schema = mongoose.Schema, + assert = require('assert'), + async = require('async'), + Helpers = require('./helpers'), + NestedSetPlugin = require('../lib/nested_set'); + +let UserSchema, + User; + +let createUsers = function (organization, callback) { + // see diagram in docs/test_tree.png for a representation of this tree + let michael = new User({username: 'michael', organization: organization}); + + let meredith = new User({username: 'meredith', parentId: michael._id, organization: organization}); + let jim = new User({username: 'jim', parentId: michael._id, organization: organization}); + let angela = new User({username: 'angela', parentId: michael._id, organization: organization}); + + let kelly = new User({username: 'kelly', parentId: meredith._id, organization: organization}); + let creed = new User({username: 'creed', parentId: meredith._id, organization: organization}); + + let phyllis = new User({username: 'phyllis', parentId: jim._id, organization: organization}); + let stanley = new User({username: 'stanley', parentId: jim._id, organization: organization}); + let dwight = new User({username: 'dwight', parentId: jim._id, organization: organization}); + + let oscar = new User({username: 'oscar', parentId: angela._id, organization: organization}); + + let users = [ + michael, + meredith, + jim, + angela, + kelly, + creed, + phyllis, + stanley, + dwight, + oscar + ]; + + if (organization === 'B') { + // Slightly different tree with less leaves + users = [ + michael, + meredith, + jim, + angela, + kelly, + phyllis, + stanley, + oscar + ]; + } + + async.eachSeries(users, function (item, cb) { + item.save(cb); + }, callback); +}; + +describe('NestedSet#GroupingKey', function () { + before(function (done) { + async.series([ + function (callback) { + mongoose.connect('mongodb://localhost/nested_set_test', {useNewUrlParser: true}); + mongoose.set('useCreateIndex', true); + callback(); + }, + function (callback) { + UserSchema = new Schema({ + username: {type: String}, + organization: {type: String} + }); + UserSchema.plugin(NestedSetPlugin); + User = mongoose.model('UserGrouping', UserSchema); + callback(); + }, + function (callback) { + createUsers('A', callback); + }, + function (callback) { + createUsers('B', callback); + } + ], function (err, results) { + if (!err) done(); + }); + }); + + after(function (done) { + mongoose.connection.collections.usergroupings.drop(function (err) { + mongoose.disconnect(); + + done(); + }); + }); + + it('is same', function (done) { + assert.ok(User); + assert.equal('function', typeof User); + assert.equal('UserGrouping', User.modelName); + done(); + }); + + it('has created users for testing', function (done) { + User.find(function (err, users) { + if (err) { + console.log(err); + } + assert.ok(!err); + assert.ok(users); + assert.ok(users instanceof Array); + assert.equal(18, users.length); + done(); + }); + }); + + it('can read parentIds as ObjectIDs', function (done) { + User.find({organization: 'A'}, function (err, users) { + if (err) { + console.log(err); + } + assert.ok(!err); + users.forEach(function (user) { + if (user.parentId) { + assert.ok(Helpers.isObjectId(user.parentId)); + } + }); + done(); + }); + }); + + it('rebuildTree should set lft and rgt based on parentIds (A)', function (done) { + User.findOne({username: 'michael', organization: 'A'}, function (err, user) { + User.rebuildTree(user, 1, function () { + User.find({organization: 'A'}, function (err, users) { + // see docs/test_tree.png for the graphical representation of this tree with lft/rgt values + users.forEach(function (person) { + if (person.username === 'michael') { + assert.equal(1, person.lft); + assert.equal(20, person.rgt); + } else if (person.username === 'meredith') { + assert.equal(2, person.lft); + assert.equal(7, person.rgt); + } else if (person.username === 'jim') { + assert.equal(8, person.lft); + assert.equal(15, person.rgt); + } else if (person.username === 'angela') { + assert.equal(16, person.lft); + assert.equal(19, person.rgt); + } else if (person.username === 'kelly') { + assert.equal(3, person.lft); + assert.equal(4, person.rgt); + } else if (person.username === 'creed') { + assert.equal(5, person.lft); + assert.equal(6, person.rgt); + } else if (person.username === 'phyllis') { + assert.equal(9, person.lft); + assert.equal(10, person.rgt); + } else if (person.username === 'stanley') { + assert.equal(11, person.lft); + assert.equal(12, person.rgt); + } else if (person.username === 'dwight') { + assert.equal(13, person.lft); + assert.equal(14, person.rgt); + } else if (person.username === 'oscar') { + assert.equal(17, person.lft); + assert.equal(18, person.rgt); + } + }); + done(); + }); + }); + }); + }); + + it('rebuildTree should set lft and rgt based on parentIds (B)', function (done) { + User.findOne({username: 'michael', organization: 'B'}, function (err, user) { + User.rebuildTree(user, 1, function () { + User.find({organization: 'B'}, function (err, users) { + // see docs/test_tree.png for the graphical representation of this tree with lft/rgt values + users.forEach(function (person) { + if (person.username === 'michael') { + assert.equal(1, person.lft); + assert.equal(16, person.rgt); + } else if (person.username === 'meredith') { + assert.equal(2, person.lft); + assert.equal(5, person.rgt); + } else if (person.username === 'jim') { + assert.equal(6, person.lft); + assert.equal(11, person.rgt); + } else if (person.username === 'angela') { + assert.equal(12, person.lft); + assert.equal(15, person.rgt); + } else if (person.username === 'kelly') { + assert.equal(3, person.lft); + assert.equal(4, person.rgt); + } else if (person.username === 'phyllis') { + assert.equal(7, person.lft); + assert.equal(8, person.rgt); + } else if (person.username === 'stanley') { + assert.equal(9, person.lft); + assert.equal(10, person.rgt); + } else if (person.username === 'oscar') { + assert.equal(13, person.lft); + assert.equal(14, person.rgt); + } + }); + done(); + }); + }); + }); + }); +}); \ No newline at end of file From 0aad79859e34930b9a58891c5b9d6e0f19dab5bc Mon Sep 17 00:00:00 2001 From: Saleh Saeed Date: Tue, 11 Dec 2018 17:24:49 +0300 Subject: [PATCH 09/14] Fix test --- tests/nested_set_test.js | 125 ++++++++++++++++++++------------------- 1 file changed, 63 insertions(+), 62 deletions(-) diff --git a/tests/nested_set_test.js b/tests/nested_set_test.js index c3fcd1f..33ce7f6 100644 --- a/tests/nested_set_test.js +++ b/tests/nested_set_test.js @@ -12,66 +12,67 @@ let mongoose = require('mongoose'), let UserSchema, User; -before(function (done) { - async.series([ - function (callback) { - mongoose.connect('mongodb://localhost/nested_set_test', {useNewUrlParser: true}); - mongoose.set('useCreateIndex', true); - callback(); - }, - function (callback) { - UserSchema = new Schema({ - username: {type: String} - }); - UserSchema.plugin(NestedSetPlugin); - User = mongoose.model('User', UserSchema); - callback(null); - }, - function (callback) { - // see diagram in docs/test_tree.png for a representation of this tree - let michael = new User({username: 'michael'}); - - let meredith = new User({username: 'meredith', parentId: michael._id}); - let jim = new User({username: 'jim', parentId: michael._id}); - let angela = new User({username: 'angela', parentId: michael._id}); - - let kelly = new User({username: 'kelly', parentId: meredith._id}); - let creed = new User({username: 'creed', parentId: meredith._id}); - - let phyllis = new User({username: 'phyllis', parentId: jim._id}); - let stanley = new User({username: 'stanley', parentId: jim._id}); - let dwight = new User({username: 'dwight', parentId: jim._id}); - - let oscar = new User({username: 'oscar', parentId: angela._id}); - - async.eachSeries([ - michael, - meredith, - jim, - angela, - kelly, - creed, - phyllis, - stanley, - dwight, - oscar - ], function (item, cb) { - item.save(cb); - }, callback); - } - ], function (err, results) { - if (!err) done(); + +describe('NestedSet', function () { + before(function (done) { + async.series([ + function (callback) { + mongoose.connect('mongodb://localhost/nested_set_test', {useNewUrlParser: true}); + mongoose.set('useCreateIndex', true); + callback(); + }, + function (callback) { + UserSchema = new Schema({ + username: {type: String} + }); + UserSchema.plugin(NestedSetPlugin); + User = mongoose.model('User', UserSchema); + callback(null); + }, + function (callback) { + // see diagram in docs/test_tree.png for a representation of this tree + let michael = new User({username: 'michael'}); + + let meredith = new User({username: 'meredith', parentId: michael._id}); + let jim = new User({username: 'jim', parentId: michael._id}); + let angela = new User({username: 'angela', parentId: michael._id}); + + let kelly = new User({username: 'kelly', parentId: meredith._id}); + let creed = new User({username: 'creed', parentId: meredith._id}); + + let phyllis = new User({username: 'phyllis', parentId: jim._id}); + let stanley = new User({username: 'stanley', parentId: jim._id}); + let dwight = new User({username: 'dwight', parentId: jim._id}); + + let oscar = new User({username: 'oscar', parentId: angela._id}); + + async.eachSeries([ + michael, + meredith, + jim, + angela, + kelly, + creed, + phyllis, + stanley, + dwight, + oscar + ], function (item, cb) { + item.save(cb); + }, callback); + } + ], function (err, results) { + if (!err) done(); + }); }); -}); -after(function (done) { - mongoose.connection.collections.users.drop(function (err) { - mongoose.disconnect(); + after(function (done) { + mongoose.connection.collections.users.drop(function (err) { + mongoose.disconnect(); + }); + done(); }); - done(); -}); -describe('Normal nested set', function () { it('is same', function (done) { assert.ok(User); assert.equal('function', typeof User); @@ -467,14 +468,14 @@ describe('Normal nested set', function () { }); it('removing a node to a built tree should re-arrange the tree correctly', function (done) { - User.findOne({username: 'michael'}, function(err, michael) { - User.rebuildTree(michael, 1, function() { - User.findOne({username: 'creed'}, function(err, creed) { - creed.remove(function() { - User.find(function(err, users) { + User.findOne({username: 'michael'}, function (err, michael) { + User.rebuildTree(michael, 1, function () { + User.findOne({username: 'creed'}, function (err, creed) { + creed.remove(function () { + User.find(function (err, users) { // see docs/test_tree_after_leaf_insertion.png for the graphical representation of this tree // with lft/rgt values after the insertion - users.forEach(function(person) { + users.forEach(function (person) { if (person.username === 'michael') { assert.equal(1, person.lft); assert.equal(18, person.rgt); From e3dbf2fa577c0e402a16070a1ca778d3ec2e7273 Mon Sep 17 00:00:00 2001 From: Saleh Saeed Date: Tue, 11 Dec 2018 17:47:49 +0300 Subject: [PATCH 10/14] Add .travis.yml file --- .travis.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..64907f9 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: node_js +services: mongodb +node_js: + - "iojs" + - "7" + - "6" + - "5" + - "4" + - "0.12" + - "0.10" \ No newline at end of file From add51c3666c169c6e07688adaa0e854eaceeccce Mon Sep 17 00:00:00 2001 From: Saleh Saeed Date: Tue, 11 Dec 2018 17:50:59 +0300 Subject: [PATCH 11/14] Remove old node versions --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 64907f9..7e9b515 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,4 @@ node_js: - "7" - "6" - "5" - - "4" - - "0.12" - - "0.10" \ No newline at end of file + - "4" \ No newline at end of file From 8dcc8c64418766321cb7ef95f404f6522e58e5bb Mon Sep 17 00:00:00 2001 From: Saleh Saeed Date: Tue, 11 Dec 2018 17:53:33 +0300 Subject: [PATCH 12/14] Improve travis-ci file --- .travis.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7e9b515..672d083 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,7 @@ +sudo: false language: node_js services: mongodb node_js: - - "iojs" - - "7" - "6" - - "5" - - "4" \ No newline at end of file + - "8" + - "10" \ No newline at end of file From abc186e6857d3ad83890064f1de0996913706c44 Mon Sep 17 00:00:00 2001 From: Saleh Saeed Date: Tue, 11 Dec 2018 17:56:15 +0300 Subject: [PATCH 13/14] Add build status image --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a0ac9c1..5cfcf75 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # mongoose-nested-set +[![Build Status](https://travis-ci.org/saleh199/mongoose-nested-set.svg?branch=change-nodeunit-to-mocha)](https://travis-ci.org/saleh199/mongoose-nested-set) + A mongoose plugin implementing the nested set pattern for mongoose models ### Usage From 770ac3f0bff4b9d4710cf947c6472fcedadd59cd Mon Sep 17 00:00:00 2001 From: Saleh Saeed Date: Wed, 19 Aug 2020 14:29:45 +0300 Subject: [PATCH 14/14] Update mongoose --- package-lock.json | 421 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 4 +- 2 files changed, 423 insertions(+), 2 deletions(-) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..a633d77 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,421 @@ +{ + "name": "mongoose-nested-set", + "version": "0.0.7", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "requires": { + "lodash": "^4.17.14" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "bl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.0.tgz", + "integrity": "sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==", + "requires": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "bson": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.5.tgz", + "integrity": "sha512-kDuEzldR21lHciPQAIulLs1LZlCXdLziXI6Mb/TDkwXhb//UORJNPXgcRs2CuO4H0DcMkpfT3/ySsP3unoZjBg==" + }, + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "denque": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz", + "integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==" + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "kareem": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.1.tgz", + "integrity": "sha512-l3hLhffs9zqoDe8zjmb/mAN4B8VT3L56EUvKNqLFVs9YlFA+zx7ke1DO8STAdDyYNkeSo1nKmjuvQeI12So8Xw==" + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + }, + "memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "dev": true, + "requires": { + "browser-stdout": "1.3.1", + "commander": "2.15.1", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.5", + "he": "1.1.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "supports-color": "5.4.0" + } + }, + "mongodb": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.0.tgz", + "integrity": "sha512-/XWWub1mHZVoqEsUppE0GV7u9kanLvHxho6EvBxQbShXTKYF9trhZC2NzbulRGeG7xMJHD8IOWRcdKx5LPjAjQ==", + "requires": { + "bl": "^2.2.0", + "bson": "^1.1.4", + "denque": "^1.4.1", + "require_optional": "^1.0.1", + "safe-buffer": "^5.1.2", + "saslprep": "^1.0.0" + } + }, + "mongoose": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.10.0.tgz", + "integrity": "sha512-5itAvBMVDG4+zTDtuLg/IyoTxEMgvpOSHnigQ9Cyh8LR4BEgMAChJj7JSaGkg+tr1AjCSY9DgSdU8bHqCOoxXg==", + "requires": { + "bson": "^1.1.4", + "kareem": "2.3.1", + "mongodb": "3.6.0", + "mongoose-legacy-pluralize": "1.0.2", + "mpath": "0.7.0", + "mquery": "3.2.2", + "ms": "2.1.2", + "regexp-clone": "1.0.0", + "safe-buffer": "5.2.1", + "sift": "7.0.1", + "sliced": "1.0.1" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "mongoose-legacy-pluralize": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz", + "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==" + }, + "mpath": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.7.0.tgz", + "integrity": "sha512-Aiq04hILxhz1L+f7sjGyn7IxYzWm1zLNNXcfhDtx04kZ2Gk7uvFdgZ8ts1cWa/6d0TQmag2yR8zSGZUmp0tFNg==" + }, + "mquery": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.2.tgz", + "integrity": "sha512-XB52992COp0KP230I3qloVUbkLUxJIu328HBP2t2EsxSFtf4W1HPSOBWOXf1bqxK4Xbb66lfMJ+Bpfd9/yZE1Q==", + "requires": { + "bluebird": "3.5.1", + "debug": "3.1.0", + "regexp-clone": "^1.0.0", + "safe-buffer": "5.1.2", + "sliced": "1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "regexp-clone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz", + "integrity": "sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw==" + }, + "require_optional": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", + "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", + "requires": { + "resolve-from": "^2.0.0", + "semver": "^5.1.0" + } + }, + "resolve-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "requires": { + "sparse-bitfield": "^3.0.3" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "sift": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/sift/-/sift-7.0.1.tgz", + "integrity": "sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g==" + }, + "sliced": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", + "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" + }, + "sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", + "optional": true, + "requires": { + "memory-pager": "^1.0.2" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + } + } +} diff --git a/package.json b/package.json index 7dedce4..9f22e9a 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,8 @@ "node": "> 0.7.x" }, "dependencies": { - "mongoose": "~5.3.15", - "async": "~2.6.1" + "async": "~2.6.1", + "mongoose": "^5.10.0" }, "devDependencies": { "mocha": "^5.2.0"