Skip to content

Commit ff7c3d1

Browse files
committed
Merge branch 'release/1.1.1'
2 parents f1e65f8 + bc4fe0d commit ff7c3d1

File tree

4 files changed

+104
-28
lines changed

4 files changed

+104
-28
lines changed

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,9 @@ The path is used for recursive methods and is kept up to date by the plugin if t
7373

7474
Signature:
7575

76-
getChildren([recursive], cb);
76+
getChildren([args], [recursive], cb);
7777

78+
args are additional filters if needed.
7879
if recursive is supplied and true, subchildren are returned
7980

8081
Based on the above hierarchy:
@@ -116,7 +117,7 @@ args is an object you can defined with theses properties :
116117
example: minLevel:2
117118

118119
recursive: boolean, default true
119-
make the search recursive or only fetch childs for the specified level
120+
make the search recursive or only fetch children for the specified level
120121
example: recursive:false
121122

122123
allowEmptyChildren: boolean, default true
@@ -170,7 +171,7 @@ adam.getChildrenTree( function(err, users) {
170171

171172
Signature:
172173

173-
getAncestors(cb);
174+
getAncestors([args], cb);
174175

175176
Based on the above hierarchy:
176177

lib/tree.js

Lines changed: 83 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
var Schema = require('mongoose').Schema;
22

3+
34
module.exports = exports = tree;
45

6+
57
/**
68
* @class tree
79
* Tree Behavior for Mongoose
@@ -13,6 +15,7 @@ module.exports = exports = tree;
1315
* @param {Object} options
1416
*/
1517
function tree(schema, options) {
18+
1619
var pathSeparator = options && options.pathSeparator || '#'
1720
, onDelete = options && options.onDelete || 'DELETE'; //'REPARENT'
1821

@@ -36,6 +39,7 @@ function tree(schema, options) {
3639
}
3740
});
3841

42+
3943
/**
4044
* Pre-save middleware
4145
* Build or rebuild path when needed
@@ -53,6 +57,7 @@ function tree(schema, options) {
5357

5458
var self = this;
5559
this.collection.findOne({ _id: this.parent }, function (err, doc) {
60+
5661
if (err) return next(err);
5762

5863
var previousPath = self.path;
@@ -61,33 +66,40 @@ function tree(schema, options) {
6166
if (isParentChange) {
6267
// When the parent is changed we must rewrite all children paths as well
6368
self.collection.find({ path: { '$regex': '^' + previousPath + pathSeparator } }, function (err, cursor) {
69+
6470
if (err) return next(err);
6571

6672
var stream = cursor.stream();
6773
stream.on('data', function (doc) {
6874
var newPath = self.path + doc.path.substr(previousPath.length);
6975
self.collection.update({ _id: doc._id }, { $set: { path: newPath } }, function (err) {
76+
7077
if (err) return next(err);
7178
});
7279
});
80+
7381
stream.on('close', next);
7482
stream.on('error', next);
7583
});
76-
} else {
84+
}
85+
else {
7786
next();
7887
}
7988
});
80-
} else {
89+
}
90+
else {
8191
next();
8292
}
8393
});
8494

95+
8596
/**
8697
* Pre-remove middleware
8798
*
8899
* @param {Function} next
89100
*/
90101
schema.pre('remove', function preRemove(next) {
102+
91103
if (!this.path)
92104
return next();
93105

@@ -101,21 +113,27 @@ function tree(schema, options) {
101113

102114
// Update parent property from children
103115
this.collection.find({ parent: previousParent }, function (err, cursor) {
116+
104117
if (err) return next(err);
105118
var stream = cursor.stream();
106119
stream.on('data', function streamOnData(doc) {
120+
107121
self.collection.update({ _id: doc._id }, { $set: { parent: newParent } }, function (err) {
122+
108123
if (err) return next(err);
109124
});
110125
});
111126
stream.on('close', function streamOnClose() {
127+
112128
// Cascade update Path
113129
self.collection.find({ path: { $regex: previousParent + pathSeparator} }, function (err, cursor) {
114130

115131
var subStream = cursor.stream();
116132
subStream.on('data', function subStreamOnData(doc) {
133+
117134
var newPath = doc.path.replace(previousParent + pathSeparator, '');
118135
self.collection.update({ _id: doc._id }, { $set: { path: newPath } }, function (err) {
136+
119137
if (err) return next(err);
120138
});
121139
});
@@ -129,47 +147,81 @@ function tree(schema, options) {
129147
}
130148
});
131149

150+
132151
/**
133152
* @method getChildren
134153
*
135-
* @param {[type]} recursive
136-
* @param {Function} next
154+
* @param {Object} args
155+
* @param {Boolean} recursive
156+
* @param {Function} next
137157
* @return {Model}
138158
*/
139-
schema.methods.getChildren = function getChildren(recursive, next) {
140-
if (typeof(recursive) === "function") {
141-
next = recursive;
159+
schema.methods.getChildren = function getChildren(args, recursive, next) {
160+
161+
// normalize the arguments
162+
if ("function" === typeof args) {
163+
next = args;
142164
recursive = false;
165+
args = {};
143166
}
144-
var filter = recursive ? { path: { $regex: '^' + this.path + pathSeparator } } : { parent: this._id };
145-
return this.model(this.constructor.modelName).find(filter, next);
167+
else if ("function" === typeof recursive) {
168+
next = recursive;
169+
if (args instanceof Object) {
170+
recursive = false;
171+
}
172+
else {
173+
recursive = args;
174+
args = {};
175+
}
176+
}
177+
178+
if (recursive) {
179+
args['path'] = {$regex: '^' + this.path + pathSeparator}
180+
}
181+
else {
182+
args['parent'] = this._id
183+
}
184+
185+
return this.model(this.constructor.modelName).find(args, next);
146186
};
147187

188+
148189
/**
149190
* @method getParent
150191
*
151192
* @param {Function} next
152193
* @return {Model}
153194
*/
154195
schema.methods.getParent = function getParent(next) {
196+
155197
return this.model(this.constructor.modelName).findOne({ _id: this.parent }, next);
156198
};
157199

200+
158201
/**
159202
* @method getAncestors
160203
*
204+
* @param {Object} args
161205
* @param {Function} next
162206
* @return {Model}
163207
*/
164-
schema.methods.getAncestors = function getAncestors(next) {
208+
schema.methods.getAncestors = function getAncestors(args, next) {
209+
210+
if ("function" === typeof args) {
211+
next = args;
212+
args = {};
213+
}
214+
215+
var ids = [];
216+
165217
if (this.path) {
166-
var ids = this.path.split(pathSeparator);
218+
ids = this.path.split(pathSeparator);
167219
ids.pop();
168-
} else {
169-
var ids = [];
170220
}
171-
var filter = { _id: { $in: ids } };
172-
return this.model(this.constructor.modelName).find(filter, next);
221+
222+
args['_id'] = {$in: ids};
223+
224+
return this.model(this.constructor.modelName).find(args, next);
173225
};
174226

175227

@@ -187,23 +239,23 @@ function tree(schema, options) {
187239
* @param {Function} next
188240
* @return {Model}
189241
*/
190-
schema.statics.getChildrenTree = function getChildrenTree(root, args, cb) {
242+
schema.statics.getChildrenTree = function getChildrenTree(root, args, next) {
191243

192244
if ("function" === typeof(root))
193245
{
194-
cb = root;
246+
next = root;
195247
root = null;
196248
args = {};
197249
}
198250
else if ("function" === typeof(args)) {
199-
cb = args
251+
next = args;
200252

201253
if ("model" in root) {
202254
args = {};
203255
}
204256
else
205257
{
206-
args = root
258+
args = root;
207259
root = null
208260
}
209261
}
@@ -215,7 +267,7 @@ function tree(schema, options) {
215267
var recursive = args.recursive != undefined ? args.recursive : true;
216268
var allowEmptyChildren = args.allowEmptyChildren != undefined ? args.allowEmptyChildren : true;
217269

218-
if (!cb)
270+
if (!next)
219271
throw new Error('no callback defined when calling getChildrenTree');
220272

221273
// filters: Add recursive path filter or not
@@ -250,18 +302,23 @@ function tree(schema, options) {
250302
}
251303

252304
// options:sort , path sort is mandatory
253-
if (!options.sort) options.sort = {};
305+
if (!options.sort) {
306+
options.sort = {};
307+
}
254308
options.sort.path = 1;
255309
options.lean = true;
256310

257311
return this.find(filters, fields, options, function (err, results) {
312+
258313
if (err) throw err;
259314

260315
var getLevel = function (path) {
316+
261317
return path ? path.split(pathSeparator).length : 0;
262318
};
263319

264320
var createChildren = function (arr, node, level) {
321+
265322
if (level == minLevel) {
266323
if (allowEmptyChildren)
267324
node.children = [];
@@ -291,19 +348,23 @@ function tree(schema, options) {
291348
createChildren(finalResults, results[r], level);
292349
}
293350

294-
cb(err, finalResults);
351+
next(err, finalResults);
295352

296353
});
297354
};
298355

356+
299357
schema.methods.getChildrenTree = function(args, cb) {
358+
300359
this.constructor.getChildrenTree(this, args, cb)
301360
};
302361

362+
303363
/**
304364
* @property {Number} level <virtual>
305365
*/
306366
schema.virtual('level').get(function virtualPropLevel() {
367+
307368
return this.path ? this.path.split(pathSeparator).length : 0;
308369
});
309370
}

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"Franck Tab <franck.tab@gmail.com>",
66
"Tomáš Holas <tomas.holas@gmail.com>",
77
"Oleg Butovich <obutovich@gmail.com>",
8+
"Jake Dempsey <angelo0000@gmail.com>",
89
"Alban Escalier (DaWyz)"
910
],
1011
"name": "mongoose-path-tree",
@@ -15,15 +16,15 @@
1516
"url": "git://github.com/swayf/mongoose-path-tree.git"
1617
},
1718
"main": "index.js",
18-
"version": "1.0.2",
19+
"version": "1.1.1",
1920
"engine": "node >= 0.4.0",
2021
"dependencies": {
2122
"mongoose": "3.x.x"
2223
},
2324
"devDependencies": {
2425
"async": "0.x.x",
2526
"should": "1.x.x",
26-
"underscore": "1.x.x",
27+
"lodash": "2.x.x",
2728
"mocha": "1.x.x"
2829
},
2930
"directories": {

test/tree.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ var assert = require('assert'),
33
tree = require('../lib/tree'),
44
async = require('async'),
55
should = require('should'),
6-
_ = require('underscore');
6+
_ = require('lodash');
77

88
var Schema = mongoose.Schema;
99

@@ -138,6 +138,19 @@ describe('tree tests', function () {
138138
});
139139

140140
describe('get children', function () {
141+
it('should return immediate children with filters', function (done) {
142+
User.findOne({ 'name': 'Adam' }, function (err, adam) {
143+
should.not.exist(err);
144+
145+
adam.getChildren({ name: 'Bob' }, function (err, users) {
146+
should.not.exist(err);
147+
148+
users.length.should.equal(1);
149+
_.pluck(users, 'name').should.include('Bob');
150+
done();
151+
});
152+
});
153+
});
141154
it('should return immediate children', function (done) {
142155
User.findOne({ 'name': 'Adam' }, function (err, adam) {
143156
should.not.exist(err);

0 commit comments

Comments
 (0)