Skip to content

Commit

Permalink
Merge pull request #9189 from AbdelrahmanHafez/gh-9183
Browse files Browse the repository at this point in the history
add mongoose default option to set `returnOriginal`
  • Loading branch information
vkarpov15 committed Jul 19, 2020
2 parents e4090b1 + 04f9a7a commit c889778
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 17 deletions.
1 change: 1 addition & 0 deletions lib/index.js
Expand Up @@ -147,6 +147,7 @@ Mongoose.prototype.driver = require('./driver');
*
* Currently supported options are:
* - 'debug': If `true`, prints the operations mongoose sends to MongoDB to the console. If a writable stream is passed, it will log to that stream, without colorization. If a callback function is passed, it will receive the collection name, the method name, then all arugments passed to the method. For example, if you wanted to replicate the default logging, you could output from the callback `Mongoose: ${collectionName}.${methodName}(${methodArgs.join(', ')})`.
* - 'returnOriginal': If `false`, changes the default `returnOriginal` option to `findOneAndUpdate()`, `findByIdAndUpdate`, and `findOneAndReplace()` to false. This is equivalent to setting the `new` option to `true` for `findOneAndX()` calls by default. Read our [`findOneAndUpdate()` tutorial](/docs/tutorials/findoneandupdate.html) for more information.
* - 'bufferCommands': enable/disable mongoose's buffering mechanism for all connections and models
* - 'useCreateIndex': false by default. Set to `true` to make Mongoose's default index build use `createIndex()` instead of `ensureIndex()` to avoid deprecation warnings from the MongoDB driver.
* - 'useFindAndModify': true by default. Set to `false` to make `findOneAndUpdate()` and `findOneAndRemove()` use native `findOneAndUpdate()` rather than `findAndModify()`.
Expand Down
6 changes: 3 additions & 3 deletions lib/model.js
Expand Up @@ -2445,7 +2445,7 @@ Model.$where = function $where() {
* @param {Object} [conditions]
* @param {Object} [update]
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
* @param {Boolean} [options.new=false] By default, `findOneAndUpdate()` returns the document as it was **before** `update` was applied. If you set `new: true`, `findOneAndUpdate()` will instead give you the object after `update` was applied.
* @param {Boolean} [options.new=false] By default, `findOneAndUpdate()` returns the document as it was **before** `update` was applied. If you set `new: true`, `findOneAndUpdate()` will instead give you the object after `update` was applied. To change the default to `true`, use `mongoose.set('returnOriginal', false);`.
* @param {Object} [options.lean] if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](/docs/api.html#query_Query-lean) and [the Mongoose lean tutorial](/docs/tutorials/lean.html).
* @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](/docs/transactions.html).
* @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
Expand Down Expand Up @@ -2588,7 +2588,7 @@ function _decorateUpdateWithVersionKey(update, options, versionKey) {
* @param {Object|Number|String} id value of `_id` to query by
* @param {Object} [update]
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
* @param {Boolean} [options.new=false] By default, `findByIdAndUpdate()` returns the document as it was **before** `update` was applied. If you set `new: true`, `findOneAndUpdate()` will instead give you the object after `update` was applied.
* @param {Boolean} [options.new=false] By default, `findByIdAndUpdate()` returns the document as it was **before** `update` was applied. If you set `new: true`, `findOneAndUpdate()` will instead give you the object after `update` was applied. To change the default to `true`, use `mongoose.set('returnOriginal', false);`.
* @param {Object} [options.lean] if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](/docs/api.html#query_Query-lean) and [the Mongoose lean tutorial](/docs/tutorials/lean.html).
* @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](/docs/transactions.html).
* @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
Expand Down Expand Up @@ -2787,7 +2787,7 @@ Model.findByIdAndDelete = function(id, options, callback) {
* @param {Object} filter Replace the first document that matches this filter
* @param {Object} [replacement] Replace with this document
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
* @param {Boolean} [options.new=false] By default, `findOneAndUpdate()` returns the document as it was **before** `update` was applied. If you set `new: true`, `findOneAndUpdate()` will instead give you the object after `update` was applied.
* @param {Boolean} [options.new=false] By default, `findOneAndReplace()` returns the document as it was **before** `update` was applied. If you set `new: true`, `findOneAndReplace()` will instead give you the object after `update` was applied. To change the default to `true`, use `mongoose.set('returnOriginal', false);`.
* @param {Object} [options.lean] if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](/docs/api.html#query_Query-lean) and [the Mongoose lean tutorial](/docs/tutorials/lean.html).
* @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](/docs/transactions.html).
* @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
Expand Down
36 changes: 24 additions & 12 deletions lib/query.js
Expand Up @@ -3004,20 +3004,25 @@ Query.prototype.findOneAndUpdate = function(criteria, doc, options, callback) {
this._mergeUpdate(doc);
}

if (options) {
options = utils.clone(options);
if (options.projection) {
this.select(options.projection);
delete options.projection;
}
if (options.fields) {
this.select(options.fields);
delete options.fields;
}
options = options ? utils.clone(options) : {};

this.setOptions(options);
if (options.projection) {
this.select(options.projection);
delete options.projection;
}
if (options.fields) {
this.select(options.fields);
delete options.fields;
}


const returnOriginal = get(this, 'model.base.options.returnOriginal');
if (options.returnOriginal == null && returnOriginal != null) {
options.returnOriginal = returnOriginal;
}

this.setOptions(options);

if (!callback) {
return this;
}
Expand Down Expand Up @@ -3335,7 +3340,14 @@ Query.prototype.findOneAndReplace = function(filter, replacement, options, callb
this._mergeUpdate(replacement);
}

options && this.setOptions(options);
options = options || {};

const returnOriginal = get(this, 'model.base.options.returnOriginal');
if (options.returnOriginal == null && returnOriginal != null) {
options.returnOriginal = returnOriginal;
}

this.setOptions(options);

if (!callback) {
return this;
Expand Down
5 changes: 3 additions & 2 deletions lib/validoptions.js
Expand Up @@ -14,19 +14,20 @@ const VALID_OPTIONS = Object.freeze([
'debug',
'maxTimeMS',
'objectIdGetter',
'returnOriginal',
'runValidators',
'selectPopulatedPaths',
'setDefaultsOnInsert',
'strict',
'strictQuery',
'toJSON',
'toObject',
'typePojoToMixed',
'useCreateIndex',
'useFindAndModify',
'useNewUrlParser',
'usePushEach',
'useUnifiedTopology',
'typePojoToMixed'
'useUnifiedTopology'
]);

module.exports = VALID_OPTIONS;
53 changes: 53 additions & 0 deletions test/model.test.js
Expand Up @@ -6868,4 +6868,57 @@ describe('Model', function() {
assert.deepEqual(user.friends, ['Sam']);
});
});

describe('returnOriginal (gh-9183)', function() {
const originalValue = mongoose.get('returnOriginal');
beforeEach(() => {
mongoose.set('returnOriginal', false);
});

afterEach(() => {
mongoose.set('returnOriginal', originalValue);
});

it('Setting `returnOriginal` works', function() {
return co(function*() {
const userSchema = new Schema({
name: { type: String }
});

const User = db.model('User', userSchema);

const createdUser = yield User.create({ name: 'Hafez' });

const user1 = yield User.findOneAndUpdate({ _id: createdUser._id }, { name: 'Hafez1' });
assert.equal(user1.name, 'Hafez1');

const user2 = yield User.findByIdAndUpdate(createdUser._id, { name: 'Hafez2' });
assert.equal(user2.name, 'Hafez2');

const user3 = yield User.findOneAndReplace({ _id: createdUser._id }, { name: 'Hafez3' });
assert.equal(user3.name, 'Hafez3');
});
});

it('`returnOriginal` can be overwritten', function() {
return co(function*() {
const userSchema = new Schema({
name: { type: String }
});

const User = db.model('User', userSchema);

const createdUser = yield User.create({ name: 'Hafez' });

const user1 = yield User.findOneAndUpdate({ _id: createdUser._id }, { name: 'Hafez1' }, { new: false });
assert.equal(user1.name, 'Hafez');

const user2 = yield User.findByIdAndUpdate(createdUser._id, { name: 'Hafez2' }, { new: false });
assert.equal(user2.name, 'Hafez1');

const user3 = yield User.findOneAndReplace({ _id: createdUser._id }, { name: 'Hafez3' }, { new: false });
assert.equal(user3.name, 'Hafez2');
});
});
});
});

0 comments on commit c889778

Please sign in to comment.