Comparing version 1.3.6 to 1.3.7
1.3.7 / 2011-06-03 | ||
=================== | ||
* added MongooseArray#splice support | ||
* fixed; 'path' is now a valid Schema pathname | ||
* improved hooks (utilizing https://github.com/bnoguchi/hooks-js) | ||
* fixed; MongooseArray#$shift now works (never did) | ||
* fixed; Document.modified no longer throws | ||
* fixed; modifying subdoc property sets modified paths for subdoc and parent doc | ||
* fixed; marking subdoc path as modified properly persists the value to the db | ||
* fixed; RexExps can again be saved ( #357 ) | ||
1.3.6 / 2011-05-18 | ||
@@ -3,0 +15,0 @@ =================== |
@@ -14,3 +14,4 @@ | ||
, ActiveRoster = utils.StateMachine.ctor('require', 'modify', 'init') | ||
, deepEqual = utils.deepEqual; | ||
, deepEqual = utils.deepEqual | ||
, hooks = require('hooks'); | ||
@@ -34,3 +35,2 @@ /** | ||
if (obj) this.set(obj); | ||
this.pres = {}; | ||
this.registerHooks(); | ||
@@ -154,20 +154,7 @@ this.doQueue(); | ||
/** | ||
* Registers a middleware that is executed before a method. | ||
* | ||
* @param {String} method name | ||
* @param {Function} callback | ||
* @api public | ||
*/ | ||
// Set up middleware support | ||
for (var k in hooks) { | ||
Document.prototype[k] = Document[k] = hooks[k]; | ||
} | ||
Document.prototype.pre = function (method, fn) { | ||
if (!(method in this.pres)) | ||
this.pres[method] = { | ||
serial: [] | ||
, parallel: [] | ||
}; | ||
this.pres[method][fn.length == 1 ? 'serial' : 'parallel'].push(fn); | ||
return this; | ||
}; | ||
/** | ||
@@ -200,2 +187,3 @@ * Sets a path, or many paths | ||
} | ||
if ('string' !== typeof path) { | ||
@@ -220,3 +208,3 @@ | ||
key = keys[i]; | ||
if (!(this.path(prefix + key) instanceof MixedSchema) | ||
if (!(this._path(prefix + key) instanceof MixedSchema) | ||
&& undefined !== path[key] | ||
@@ -234,3 +222,3 @@ && null !== path[key] | ||
var schema = this.path(path) | ||
var schema = this._path(path) | ||
, parts = path.split('.') | ||
@@ -290,6 +278,2 @@ , obj = this.doc | ||
Document.prototype.markModified = function (path) { | ||
this.activePaths.modify(path); | ||
}; | ||
/** | ||
@@ -375,3 +359,3 @@ * Gets a raw value from a path (no getters) | ||
var obj | ||
, schema = this.path(path) || this.schema.virtualpath(path) | ||
, schema = this._path(path) || this.schema.virtualpath(path) | ||
, adhocs | ||
@@ -397,4 +381,6 @@ , pieces = path.split('.'); | ||
* @param {Object} obj | ||
* @api private | ||
*/ | ||
Document.prototype.path = function (path, obj) { | ||
Document.prototype._path = function (path, obj) { | ||
var adhocs = this._adhocPaths | ||
@@ -409,3 +395,2 @@ , adhocType = adhocs && adhocs[path]; | ||
/** | ||
@@ -417,4 +402,4 @@ * Commits a path, marking as modified if needed. Useful for mixed keys | ||
Document.prototype.markModified = | ||
Document.prototype.commit = function (path) { | ||
// TODO: do actual checking to see if the value changed | ||
this.activePaths.modify(path); | ||
@@ -487,4 +472,4 @@ }; | ||
* @param {String} path | ||
* | ||
*/ | ||
Document.prototype.isDirectModified = function (path) { | ||
@@ -517,3 +502,4 @@ return (path in this.activePaths.states.modify); | ||
if (!this.activePaths.some('require', 'init', 'modify')) return next(); | ||
if (!this.activePaths.some('require', 'init', 'modify')) | ||
return next(); | ||
@@ -532,3 +518,4 @@ function validatePath (path) { | ||
} | ||
--total || next(validationError); | ||
--total || | ||
(validationError ? next(validationError) : next()); | ||
}); | ||
@@ -555,3 +542,3 @@ | ||
Document.prototype.__defineGetter__('modified', function () { | ||
return this.activePaths.some('modified'); | ||
return this.activePaths.some('modify'); | ||
}); | ||
@@ -649,2 +636,4 @@ | ||
if (!this.save) return; | ||
this.pre('save', function checkForExistingErrors (next) { | ||
@@ -657,5 +646,3 @@ if (self.saveError){ | ||
} | ||
}); | ||
this.pre('save', function validation (next) { | ||
}).pre('save', function validation (next) { | ||
return self.validate.call(self, next); | ||
@@ -686,4 +673,5 @@ }); | ||
if (this.schema && this.schema.callQueue) | ||
for (var i = 0, l = this.schema.callQueue.length; i < l; i++) | ||
for (var i = 0, l = this.schema.callQueue.length; i < l; i++) { | ||
this[this.schema.callQueue[i][0]].apply(this, this.schema.callQueue[i][1]); | ||
} | ||
return this; | ||
@@ -725,3 +713,2 @@ }; | ||
/** | ||
@@ -733,2 +720,3 @@ * Returns true if the Document stores the same data as doc. | ||
*/ | ||
Document.prototype.equals = function (doc) { | ||
@@ -739,76 +727,2 @@ return this.get('_id') === doc.get('_id'); | ||
/** | ||
* Wrap methods for hooks. Should be called on implemented classes (eg: Model) | ||
* Takes multiple method names as arguments. | ||
* | ||
* @api private | ||
*/ | ||
function noop () {}; | ||
Document.registerHooks = function () { | ||
for (var i = 0, l = arguments.length; i < l; i++){ | ||
this.prototype[arguments[i]] = (function(methodName, oldFn){ | ||
return function () { | ||
var self = this | ||
, args = arguments | ||
, pres = this.pres[methodName]; | ||
if (!pres) return oldFn.apply(this, args); | ||
function error (err){ | ||
var lastArg = args[args.length-1]; | ||
if (typeof lastArg == 'function') | ||
lastArg.call(self, err); | ||
} | ||
var chain = pres.serial.map(function (fn, i) { | ||
return function (err) { | ||
if (arguments.callee._hookCalled) return; | ||
if (err instanceof Error) | ||
error(err); | ||
else | ||
fn.call(self, chain[i+1] || parallel); | ||
arguments.callee._hookCalled = true; | ||
}; | ||
}); | ||
chain.length ? chain[0]() : parallel(); | ||
function parallel (err) { | ||
if (err instanceof Error) | ||
return error(err); | ||
// chain determines execution, callbacks completeness | ||
var complete = pres.parallel.length; | ||
if (!complete) return oldFn.apply(self, args); | ||
function done (err) { | ||
if (err instanceof Error) | ||
return error(err); | ||
--complete || oldFn.apply(self, args); | ||
} | ||
var chain = pres.parallel.map(function (fn, i) { | ||
return function (err) { | ||
if (arguments.callee._hookCalled) return; | ||
if (err) return error(err); | ||
fn.call(self, chain[i+1] || noop, function (err) { | ||
if (arguments.callee._hookCalled) return; | ||
done(err); | ||
arguments.callee._hookCalled = true; | ||
}); | ||
arguments.callee._hookCalled = true; | ||
}; | ||
}); | ||
chain[0](); | ||
} | ||
}; | ||
})(arguments[i], this.prototype[arguments[i]]); | ||
} | ||
}; | ||
/** | ||
* Module exports. | ||
@@ -815,0 +729,0 @@ */ |
@@ -292,3 +292,3 @@ | ||
exports.version = '1.3.6'; | ||
exports.version = '1.3.7'; | ||
@@ -295,0 +295,0 @@ /** |
@@ -84,3 +84,3 @@ | ||
, value: self.getValue(path) | ||
, schema: self.path(path) }; | ||
, schema: self._path(path) }; | ||
}); | ||
@@ -339,8 +339,2 @@ | ||
/** | ||
* Register hooks for some methods. | ||
*/ | ||
Document.registerHooks.call(Model, 'save', 'remove', 'init'); | ||
/** | ||
* Module exports. | ||
@@ -347,0 +341,0 @@ */ |
@@ -187,3 +187,3 @@ | ||
MongooseArray.prototype.$pop = function () { | ||
this._registerAtomic('$pop', '1'); | ||
this._registerAtomic('$pop', 1); | ||
return this.pop(); | ||
@@ -199,3 +199,3 @@ }; | ||
MongooseArray.prototype.$shift = function () { | ||
this._registerAtomic('$shift', '-1'); | ||
this._registerAtomic('$pop', -1); | ||
return this.shift(); | ||
@@ -275,2 +275,12 @@ }; | ||
/** | ||
* Splices the array. | ||
*/ | ||
MongooseArray.prototype.splice = function () { | ||
Array.prototype.splice.apply(this, arguments); | ||
this._markModified(); | ||
return this; | ||
}; | ||
/** | ||
* Returns an Array | ||
@@ -277,0 +287,0 @@ * |
@@ -31,3 +31,3 @@ | ||
/** | ||
* Override save to mark the parent as modified | ||
* Override set to mark the parent as modified | ||
* | ||
@@ -50,3 +50,6 @@ * @api public | ||
EmbeddedDocument.prototype.commit = | ||
EmbeddedDocument.prototype.markModified = function (path) { | ||
this.activePaths.modify(path); | ||
if (this.isNew) { | ||
@@ -70,2 +73,3 @@ // Mark the WHOLE parent array as modified | ||
fn(null); | ||
this.emit('save', this); | ||
return this; | ||
@@ -109,8 +113,2 @@ }; | ||
/** | ||
* Register hooks for some methods | ||
*/ | ||
Document.registerHooks.call(EmbeddedDocument, 'save', 'remove', 'init'); | ||
/** | ||
* Module exxports. | ||
@@ -117,0 +115,0 @@ */ |
@@ -200,13 +200,21 @@ | ||
return obj | ||
if (Array.isArray(obj)) return cloneArray(obj, shouldMinimizeData); | ||
if (Array.isArray(obj)) | ||
return cloneArray(obj, shouldMinimizeData); | ||
if (obj.toObject) | ||
return obj.toObject(); | ||
if (obj.constructor == Object) { | ||
if (obj.constructor == Object) | ||
return cloneObject(obj, shouldMinimizeData); | ||
} | ||
if (obj.constructor == Date || obj.constructor == RegExp | ||
|| obj.constructor == Function) | ||
if (obj.constructor == Date || obj.constructor == Function) | ||
return new obj.constructor(+obj); | ||
if (obj.constructor == RegExp) | ||
return new RegExp(obj.source); | ||
if (obj instanceof ObjectId) | ||
return ObjectId.fromString(ObjectId.toString(obj)); | ||
if (obj.valueOf) | ||
@@ -213,0 +221,0 @@ return obj.valueOf(); |
{ | ||
"name": "mongoose" | ||
, "description": "Mongoose MongoDB ORM" | ||
, "version": "1.3.6" | ||
, "version": "1.3.7" | ||
, "author": "Guillermo Rauch <guillermo@learnboost.com>" | ||
, "keywords": ["mongodb", "mongoose", "orm", "data", "datastore", "nosql"] | ||
, "dependencies": {} | ||
, "dependencies": { | ||
"hooks": ">=0.1.5" | ||
} | ||
, "directories": { "lib": "./lib/mongoose" } | ||
@@ -9,0 +11,0 @@ , "scripts": { "test": "make test" } |
@@ -192,4 +192,3 @@ Mongoose 1.0 | ||
There's two types of middleware, determined by the signature of the function | ||
you define (ie: the parameters your function accepts): | ||
There's two types of middleware: | ||
@@ -199,3 +198,3 @@ - Serial | ||
.pre(method, function (next) { | ||
.pre(method, function (next, methodArg1, methodArg2, ...) { | ||
// ... | ||
@@ -206,2 +205,7 @@ }) | ||
You can also intercept the `method`'s incoming arguments via your middleware -- | ||
notice `methodArg1`, `methodArg2`, etc in the `pre` definition above. See | ||
section "Intercepting and mutating method arguments" below. | ||
- Parallel | ||
@@ -211,5 +215,5 @@ Parallel middleware offer more fine-grained flow control, and are defined | ||
.pre(method, function (next, done) { | ||
.pre(method, function (next, done, methodArg1, methodArg2) { | ||
// ... | ||
}) | ||
}, true) | ||
@@ -237,2 +241,43 @@ Parallel middleware can `next()` immediately, but the final argument will be | ||
### Intercepting and mutating method arguments | ||
You can intercept method arguments via middleware. | ||
For example, this would allow you to broadcast changes about your Documents | ||
every time someone `set`s a path in your Document to a new value: | ||
```javascript | ||
schema.pre('set', function (next, path, val, typel) { | ||
// `this` is the current Document | ||
this.emit('set', path, val); | ||
// Pass control to the next pre | ||
next(); | ||
}); | ||
``` | ||
Moreover, you can mutate the incoming `method` arguments so that subsequent | ||
middleware see different values for those arguments. To do so, just pass the | ||
new values to `next`: | ||
```javascript | ||
.pre(method, function firstPre (next, methodArg1, methodArg2) { | ||
// Mutate methodArg1 | ||
next("altered-" + methodArg1.toString(), methodArg2); | ||
}) // pre declaration is chainable | ||
.pre(method, function secondPre (next, methodArg1, methodArg2) { | ||
console.log(methodArg1); | ||
// => 'altered-originalValOfMethodArg1' | ||
console.log(methodArg2); | ||
// => 'originalValOfMethodArg2' | ||
// Passing no arguments to `next` automatically passes along the current argument values | ||
// i.e., the following `next()` is equivalent to `next(methodArg1, methodArg2)` | ||
// and also equivalent to, with the example method arg | ||
// values, `next('altered-originalValOfMethodArg1', 'originalValOfMethodArg2')` | ||
next(); | ||
}) | ||
``` | ||
## API docs | ||
@@ -239,0 +284,0 @@ |
@@ -6,3 +6,3 @@ | ||
var mongoose = require('mongoose') | ||
var mongoose = require('../') | ||
, should = require('should') | ||
@@ -9,0 +9,0 @@ , Table = require('cli-table') |
@@ -51,8 +51,2 @@ | ||
/** | ||
* Apply hooks. | ||
*/ | ||
Document.registerHooks.call(TestDocument, 'hooksTest'); | ||
/** | ||
* Test. | ||
@@ -184,3 +178,3 @@ */ | ||
next(); | ||
}); | ||
}, true); | ||
@@ -197,3 +191,3 @@ doc.pre('hooksTest', function(next, done){ | ||
next(); | ||
}); | ||
}, true); | ||
@@ -250,3 +244,3 @@ doc.hooksTest(function(err){ | ||
done(); | ||
}); | ||
}, true); | ||
@@ -258,3 +252,3 @@ doc.pre('hooksTest', function(next, done){ | ||
done(); | ||
}); | ||
}, true); | ||
@@ -284,3 +278,3 @@ doc.hooksTest(function(err){ | ||
done(); | ||
}); | ||
}, true); | ||
@@ -290,3 +284,3 @@ doc.pre('hooksTest', function(next, done){ | ||
next(); | ||
}); | ||
}, true); | ||
@@ -353,21 +347,16 @@ doc.hooksTest(function(err){ | ||
'test that passing something that is not an error is ignored': | ||
function(beforeExit){ | ||
var doc = new TestDocument() | ||
, called = false; | ||
'test mutating incoming args via middleware': function (beforeExit) { | ||
var doc = new TestDocument(); | ||
doc.pre('hooksTest', function(next){ | ||
next(true); | ||
doc.pre('set', function(next, path, val){ | ||
next(path, 'altered-' + val); | ||
}); | ||
doc.hooksTest(function(err){ | ||
should.strictEqual(err, null); | ||
called = true; | ||
}); | ||
doc.set('test', 'me'); | ||
beforeExit(function(){ | ||
called.should.be.true; | ||
doc.test.should.equal('altered-me'); | ||
}); | ||
}, | ||
'test hooks system errors from a parallel hook': function(beforeExit){ | ||
@@ -382,3 +371,3 @@ var doc = new TestDocument() | ||
done(); | ||
}); | ||
}, true); | ||
@@ -389,3 +378,3 @@ doc.pre('hooksTest', function(next, done){ | ||
done(); | ||
}); | ||
}, true); | ||
@@ -396,3 +385,3 @@ doc.pre('hooksTest', function(next, done){ | ||
done(new Error); | ||
}); | ||
}, true); | ||
@@ -399,0 +388,0 @@ doc.hooksTest(function(err){ |
@@ -37,7 +37,7 @@ var start = require('./common') | ||
postOne.set('adhoc', '9', Number); | ||
postOne.path('adhoc').should.not.equal(undefined); | ||
postOne._path('adhoc').should.not.equal(undefined); | ||
var postTwo = new Decorated(); | ||
postTwo.path('title').should.not.equal(undefined); | ||
should.strictEqual(undefined, postTwo.path('adhoc')); | ||
postTwo._path('title').should.not.equal(undefined); | ||
should.strictEqual(undefined, postTwo._path('adhoc')); | ||
db.close(); | ||
@@ -44,0 +44,0 @@ }, |
@@ -40,6 +40,5 @@ | ||
}, | ||
'test indexOf()': function(){ | ||
var db = start() | ||
, a = new MongooseArray | ||
, User = db.model('User', 'users_' + random()) | ||
@@ -59,3 +58,3 @@ , Pet = db.model('Pet', 'pets' + random()); | ||
var pending = 3; | ||
[tobi, loki, jane].forEach(function(pet){ | ||
@@ -81,3 +80,32 @@ pet.save(function(){ | ||
} | ||
}, | ||
'test #splice()': function () { | ||
var collection = 'splicetest' + random(); | ||
var db = start() | ||
, schema = new Schema({ numbers: Array }) | ||
, A = db.model('splicetest', schema, collection); | ||
var a = new A({ numbers: [4,5,6,7] }); | ||
a.save(function (err) { | ||
should.equal(null, err, 'could not save splice test'); | ||
A.findById(a._id, function (err, doc) { | ||
should.equal(null, err, 'error finding splice doc'); | ||
doc.numbers.splice(1, 1); | ||
doc.numbers.toObject().should.eql([4,6,7]); | ||
doc.save(function (err) { | ||
should.equal(null, err, 'could not save splice test'); | ||
A.findById(a._id, function (err, doc) { | ||
should.equal(null, err, 'error finding splice doc'); | ||
doc.numbers.toObject().should.eql([4,6,7]); | ||
A.collection.drop(function (err) { | ||
db.close(); | ||
should.strictEqual(err, null); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
} | ||
}; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1610192
200
28402
348
1
+ Addedhooks@>=0.1.5
+ Addedhooks@0.3.2(transitive)