diff --git a/lib/schema.js b/lib/schema.js index 0d039fff0bb..e0950353d70 100644 --- a/lib/schema.js +++ b/lib/schema.js @@ -652,6 +652,10 @@ Schema.interpretAsType = function(path, obj, options) { 'You can only nest using refs or arrays.'); } + obj = utils.clone(obj, { retainKeyOrder: true }); + if (!('runSettersOnQuery' in obj)) { + obj.runSettersOnQuery = options.runSettersOnQuery; + } return new MongooseTypes[name](path, obj); }; diff --git a/lib/schema/boolean.js b/lib/schema/boolean.js index 206d9fd98f5..5951dd0513d 100644 --- a/lib/schema/boolean.js +++ b/lib/schema/boolean.js @@ -90,10 +90,10 @@ SchemaBoolean.prototype.castForQuery = function($conditional, val) { return handler.call(this, val); } - return this.cast(val); + return this._castForQuery(val); } - return this.cast($conditional); + return this._castForQuery($conditional); }; /*! diff --git a/lib/schema/buffer.js b/lib/schema/buffer.js index 56490dea878..f7ca7588a36 100644 --- a/lib/schema/buffer.js +++ b/lib/schema/buffer.js @@ -178,7 +178,7 @@ SchemaBuffer.prototype.castForQuery = function($conditional, val) { return handler.call(this, val); } val = $conditional; - var casted = this.cast(val); + var casted = this._castForQuery(val); return casted ? casted.toObject({ transform: false, virtuals: false }) : casted; }; diff --git a/lib/schema/date.js b/lib/schema/date.js index b7bcf227b33..9f97096b5ba 100644 --- a/lib/schema/date.js +++ b/lib/schema/date.js @@ -277,7 +277,7 @@ SchemaDate.prototype.castForQuery = function($conditional, val) { var handler; if (arguments.length !== 2) { - return this.cast($conditional); + return this._castForQuery($conditional); } handler = this.$conditionalHandlers[$conditional]; diff --git a/lib/schema/decimal128.js b/lib/schema/decimal128.js index 3400e36ef63..67e35df4830 100644 --- a/lib/schema/decimal128.js +++ b/lib/schema/decimal128.js @@ -139,26 +139,6 @@ Decimal128.prototype.$conditionalHandlers = $lte: handleSingle }); -/** - * Casts contents for queries. - * - * @param {String} $conditional - * @param {any} [val] - * @api private - */ - -Decimal128.prototype.castForQuery = function($conditional, val) { - var handler; - if (arguments.length === 2) { - handler = this.$conditionalHandlers[$conditional]; - if (!handler) { - throw new Error('Can\'t use ' + $conditional + ' with ObjectId.'); - } - return handler.call(this, val); - } - return this.cast($conditional); -}; - /*! * Module exports. */ diff --git a/lib/schema/embedded.js b/lib/schema/embedded.js index 5b20775c797..3ca711534b1 100644 --- a/lib/schema/embedded.js +++ b/lib/schema/embedded.js @@ -156,6 +156,10 @@ Embedded.prototype.castForQuery = function($conditional, val) { return val; } + if (this.options.runSetters) { + val = this._applySetters(val); + } + return new this.caster(val); }; diff --git a/lib/schema/number.js b/lib/schema/number.js index a91f6dda6df..e5b9bc7fa62 100644 --- a/lib/schema/number.js +++ b/lib/schema/number.js @@ -279,7 +279,7 @@ SchemaNumber.prototype.castForQuery = function($conditional, val) { } return handler.call(this, val); } - val = this.cast($conditional); + val = this._castForQuery($conditional); return val; }; diff --git a/lib/schema/objectid.js b/lib/schema/objectid.js index 28858236893..6f684191c90 100644 --- a/lib/schema/objectid.js +++ b/lib/schema/objectid.js @@ -184,7 +184,7 @@ ObjectId.prototype.castForQuery = function($conditional, val) { } return handler.call(this, val); } - return this.cast($conditional); + return this._castForQuery($conditional); }; /*! diff --git a/lib/schema/string.js b/lib/schema/string.js index d969280a9c6..dfd044ad2f8 100644 --- a/lib/schema/string.js +++ b/lib/schema/string.js @@ -506,7 +506,8 @@ SchemaString.prototype.castForQuery = function($conditional, val) { if (Object.prototype.toString.call(val) === '[object RegExp]') { return val; } - return this.cast(val); + + return this._castForQuery(val); }; /*! diff --git a/lib/schematype.js b/lib/schematype.js index e9e36972ae3..35703a03393 100644 --- a/lib/schematype.js +++ b/lib/schematype.js @@ -621,20 +621,17 @@ SchemaType.prototype.getDefault = function(scope, init) { return ret; }; -/** - * Applies setters +/*! + * Applies setters without casting * - * @param {Object} value - * @param {Object} scope - * @param {Boolean} init * @api private */ -SchemaType.prototype.applySetters = function(value, scope, init, priorVal, options) { - var v = value, - setters = this.setters, - len = setters.length, - caster = this.caster; +SchemaType.prototype._applySetters = function(value, scope, init, priorVal) { + var v = value; + var setters = this.setters; + var len = setters.length; + var caster = this.caster; while (len--) { v = setters[len].call(scope, v, this); @@ -648,7 +645,22 @@ SchemaType.prototype.applySetters = function(value, scope, init, priorVal, optio v = newVal; } - if (v === null || v === undefined) { + return v; +}; + +/** + * Applies setters + * + * @param {Object} value + * @param {Object} scope + * @param {Boolean} init + * @api private + */ + +SchemaType.prototype.applySetters = function(value, scope, init, priorVal, options) { + var v = this._applySetters(value, scope, init, priorVal, options); + + if (v == null) { return v; } @@ -995,6 +1007,19 @@ SchemaType.prototype.castForQuery = function($conditional, val) { return handler.call(this, val); } val = $conditional; + return this._castForQuery(val); +}; + +/*! + * Internal switch for runSetters + * + * @api private + */ + +SchemaType.prototype._castForQuery = function(val) { + if (this.options && this.options.runSettersOnQuery) { + return this.applySetters(val, null); + } return this.cast(val); }; diff --git a/test/model.query.casting.test.js b/test/model.query.casting.test.js index 4a47bf88514..98e1d4fbdd1 100644 --- a/test/model.query.casting.test.js +++ b/test/model.query.casting.test.js @@ -1021,6 +1021,34 @@ describe('model query casting', function() { catch(done); }); + it('lowercase in query (gh-4569)', function(done) { + var db = start(); + + var testSchema = new Schema({ + name: { type: String, lowercase: true }, + num: { type: Number, set: function(v) { return Math.floor(v); } } + }, { runSettersOnQuery: true }); + + var Test = db.model('gh-4569', testSchema); + Test.create({ name: 'val', num: 3 }). + then(function() { + return Test.findOne({ name: 'VAL' }); + }). + then(function(doc) { + assert.ok(doc); + assert.equal(doc.name, 'val'); + }). + then(function() { + return Test.findOne({ num: 3.14 }); + }). + then(function(doc) { + assert.ok(doc); + assert.equal(doc.name, 'val'); + }). + then(function() { done(); }). + catch(done); + }); + it('_id = 0 (gh-4610)', function(done) { var db = start();