Skip to content

Commit

Permalink
fix(document): support getter setting virtual on manually populated d…
Browse files Browse the repository at this point in the history
…oc when calling toJSON()

Fix #8295
  • Loading branch information
vkarpov15 committed Nov 8, 2019
1 parent d4648ee commit 03ef4d8
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 11 deletions.
27 changes: 16 additions & 11 deletions lib/document.js
Expand Up @@ -2836,6 +2836,13 @@ Document.prototype.$toObject = function(options, json) {
minimize: _minimize
});

if (utils.hasUserDefinedProperty(options, 'getters')) {
cloneOptions.getters = options.getters;
}
if (utils.hasUserDefinedProperty(options, 'virtuals')) {
cloneOptions.virtuals = options.virtuals;
}

const depopulate = options.depopulate ||
get(options, '_parentOptions.depopulate', false);
// _isNested will only be true if this is not the top level document, we
Expand All @@ -2852,6 +2859,10 @@ Document.prototype.$toObject = function(options, json) {
options.minimize = _minimize;

cloneOptions._parentOptions = options;
cloneOptions._skipSingleNestedGetters = true;

const gettersOptions = Object.assign({}, cloneOptions);
gettersOptions._skipSingleNestedGetters = false;

// remember the root transform function
// to save it from being overwritten by sub-transform functions
Expand All @@ -2860,16 +2871,15 @@ Document.prototype.$toObject = function(options, json) {
let ret = clone(this._doc, cloneOptions) || {};

if (options.getters) {
applyGetters(this, ret, cloneOptions);
// applyGetters for paths will add nested empty objects;
// if minimize is set, we need to remove them.
applyGetters(this, ret, gettersOptions);

if (options.minimize) {
ret = minimize(ret) || {};
}
}

if (options.virtuals || options.getters && options.virtuals !== false) {
applyVirtuals(this, ret, cloneOptions, options);
if (options.virtuals || (options.getters && options.virtuals !== false)) {
applyVirtuals(this, ret, gettersOptions, options);
}

if (options.versionKey === false && this.schema.options.versionKey) {
Expand Down Expand Up @@ -3180,12 +3190,7 @@ function applyGetters(self, json, options) {
v = cur[part];
if (ii === last) {
const val = self.get(path);
// Ignore single nested docs: getters will run because of `clone()`
// before `applyGetters()` in `$toObject()`. Quirk because single
// nested subdocs are hydrated docs in `_doc` as opposed to POJOs.
if (val != null && val.$__ == null) {
branch[part] = clone(val, options);
}
branch[part] = clone(val, options);
} else if (v == null) {
if (part in cur) {
branch[part] = v;
Expand Down
5 changes: 5 additions & 0 deletions lib/utils.js
Expand Up @@ -193,6 +193,11 @@ exports.clone = function clone(obj, options, isArrayChild) {
}

if (isMongooseObject(obj)) {
// Single nested subdocs should apply getters later in `applyGetters()`
// when calling `toObject()`. See gh-7442, gh-8295
if (options && options._skipSingleNestedGetters && obj.$isSingleNested) {
options = Object.assign({}, options, { getters: false });
}
if (options && options.json && typeof obj.toJSON === 'function') {
return obj.toJSON(options);
}
Expand Down

0 comments on commit 03ef4d8

Please sign in to comment.