Skip to content

Commit

Permalink
fix(model): allow objects with toBSON() to make it to save()
Browse files Browse the repository at this point in the history
Fix #8299
  • Loading branch information
vkarpov15 committed Nov 8, 2019
1 parent de3eee5 commit 6c1d46a
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 1 deletion.
6 changes: 5 additions & 1 deletion lib/model.js
Expand Up @@ -52,6 +52,10 @@ const modelDbSymbol = Symbol('mongoose#Model#db');
const modelSymbol = require('./helpers/symbols').modelSymbol;
const subclassedSymbol = Symbol('mongoose#Model#subclassed');

const saveToObjectOptions = Object.assign({}, internalToObjectOptions, {
bson: true
});

/**
* A Model is a class that's your primary tool for interacting with MongoDB.
* An instance of a Model is called a [Document](./api.html#Document).
Expand Down Expand Up @@ -244,7 +248,7 @@ Model.prototype.$__handleSave = function(options, callback) {

if (this.isNew) {
// send entire doc
const obj = this.toObject(internalToObjectOptions);
const obj = this.toObject(saveToObjectOptions);

if ((obj || {})._id === void 0) {
// documents must have an _id else mongoose won't know
Expand Down
7 changes: 7 additions & 0 deletions lib/utils.js
Expand Up @@ -232,6 +232,13 @@ exports.clone = function clone(obj, options, isArrayChild) {
return obj.clone();
}

// If we're cloning this object to go into a MongoDB command,
// and there's a `toBSON()` function, assume this object will be
// stored as a primitive in MongoDB and doesn't need to be cloned.
if (options && options.bson && typeof obj.toBSON === 'function') {
return obj;
}

if (obj.valueOf != null) {
return obj.valueOf();
}
Expand Down
17 changes: 17 additions & 0 deletions test/document.test.js
Expand Up @@ -8141,4 +8141,21 @@ describe('document', function() {
assert.equal(fromDb.activity.description, 'after');
});
});

it('passing an object with toBSON() into `save()` (gh-8299)', function() {
const ActivitySchema = Schema({ description: String });
const RequestSchema = Schema({ activity: ActivitySchema });
const Request = db.model('gh8299', RequestSchema);

return co(function*() {
const doc = yield Request.create({
activity: { description: 'before' }
});
doc.activity.set({ description: 'after' });
yield doc.save();

const fromDb = yield Request.findOne().lean();
assert.equal(fromDb.activity.description, 'after');
});
});
});
14 changes: 14 additions & 0 deletions test/utils.test.js
Expand Up @@ -340,5 +340,19 @@ describe('utils', function() {

done();
});

it('skips cloning types that have `toBSON()` if `bson` is set (gh-8299)', function() {
const o = {
toBSON() {
return 'toBSON';
},
valueOf() {
return 'valueOf()';
}
};

const out = utils.clone(o, { bson: true });
assert.deepEqual(out, o);
});
});
});

0 comments on commit 6c1d46a

Please sign in to comment.