1 | 'use strict';
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 | const DivergentArrayError = require('./error/divergentArray');
|
8 | const EventEmitter = require('events').EventEmitter;
|
9 | const InternalCache = require('./internal');
|
10 | const MongooseBuffer = require('./types/buffer');
|
11 | const MongooseError = require('./error/index');
|
12 | const MixedSchema = require('./schema/mixed');
|
13 | const ModifiedPathsSnapshot = require('./modifiedPathsSnapshot');
|
14 | const ObjectExpectedError = require('./error/objectExpected');
|
15 | const ObjectParameterError = require('./error/objectParameter');
|
16 | const ParallelValidateError = require('./error/parallelValidate');
|
17 | const Schema = require('./schema');
|
18 | const StrictModeError = require('./error/strict');
|
19 | const ValidationError = require('./error/validation');
|
20 | const ValidatorError = require('./error/validator');
|
21 | const $__hasIncludedChildren = require('./helpers/projection/hasIncludedChildren');
|
22 | const applyDefaults = require('./helpers/document/applyDefaults');
|
23 | const cleanModifiedSubpaths = require('./helpers/document/cleanModifiedSubpaths');
|
24 | const clone = require('./helpers/clone');
|
25 | const compile = require('./helpers/document/compile').compile;
|
26 | const defineKey = require('./helpers/document/compile').defineKey;
|
27 | const firstKey = require('./helpers/firstKey');
|
28 | const flatten = require('./helpers/common').flatten;
|
29 | const getEmbeddedDiscriminatorPath = require('./helpers/document/getEmbeddedDiscriminatorPath');
|
30 | const getKeysInSchemaOrder = require('./helpers/schema/getKeysInSchemaOrder');
|
31 | const getSubdocumentStrictValue = require('./helpers/schema/getSubdocumentStrictValue');
|
32 | const handleSpreadDoc = require('./helpers/document/handleSpreadDoc');
|
33 | const immediate = require('./helpers/immediate');
|
34 | const isBsonType = require('./helpers/isBsonType');
|
35 | const isDefiningProjection = require('./helpers/projection/isDefiningProjection');
|
36 | const isExclusive = require('./helpers/projection/isExclusive');
|
37 | const isPathExcluded = require('./helpers/projection/isPathExcluded');
|
38 | const inspect = require('util').inspect;
|
39 | const internalToObjectOptions = require('./options').internalToObjectOptions;
|
40 | const markArraySubdocsPopulated = require('./helpers/populate/markArraySubdocsPopulated');
|
41 | const minimize = require('./helpers/minimize');
|
42 | const mpath = require('mpath');
|
43 | const parentPaths = require('./helpers/path/parentPaths');
|
44 | const queryhelpers = require('./queryHelpers');
|
45 | const utils = require('./utils');
|
46 | const isPromise = require('./helpers/isPromise');
|
47 |
|
48 | const deepEqual = utils.deepEqual;
|
49 | const isMongooseObject = utils.isMongooseObject;
|
50 |
|
51 | const arrayAtomicsBackupSymbol = require('./helpers/symbols').arrayAtomicsBackupSymbol;
|
52 | const arrayAtomicsSymbol = require('./helpers/symbols').arrayAtomicsSymbol;
|
53 | const documentArrayParent = require('./helpers/symbols').documentArrayParent;
|
54 | const documentIsModified = require('./helpers/symbols').documentIsModified;
|
55 | const documentModifiedPaths = require('./helpers/symbols').documentModifiedPaths;
|
56 | const documentSchemaSymbol = require('./helpers/symbols').documentSchemaSymbol;
|
57 | const getSymbol = require('./helpers/symbols').getSymbol;
|
58 | const populateModelSymbol = require('./helpers/symbols').populateModelSymbol;
|
59 | const scopeSymbol = require('./helpers/symbols').scopeSymbol;
|
60 | const schemaMixedSymbol = require('./schema/symbols').schemaMixedSymbol;
|
61 | const getDeepestSubdocumentForPath = require('./helpers/document/getDeepestSubdocumentForPath');
|
62 | const sessionNewDocuments = require('./helpers/symbols').sessionNewDocuments;
|
63 |
|
64 | let DocumentArray;
|
65 | let MongooseArray;
|
66 | let Embedded;
|
67 |
|
68 | const specialProperties = utils.specialProperties;
|
69 |
|
70 | const VERSION_WHERE = 1;
|
71 | const VERSION_INC = 2;
|
72 | const VERSION_ALL = VERSION_WHERE | VERSION_INC;
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 | function Document(obj, fields, skipId, options) {
|
89 | if (typeof skipId === 'object' && skipId != null) {
|
90 | options = skipId;
|
91 | skipId = options.skipId;
|
92 | }
|
93 | options = Object.assign({}, options);
|
94 |
|
95 |
|
96 | if (this.$__schema == null) {
|
97 | const _schema = utils.isObject(fields) && !fields.instanceOfSchema ?
|
98 | new Schema(fields) :
|
99 | fields;
|
100 | this.$__setSchema(_schema);
|
101 | fields = skipId;
|
102 | skipId = options;
|
103 | options = arguments[4] || {};
|
104 | }
|
105 |
|
106 | this.$__ = new InternalCache();
|
107 |
|
108 |
|
109 | if (options.isNew != null && options.isNew !== true) {
|
110 | this.$isNew = options.isNew;
|
111 | }
|
112 |
|
113 | if (options.priorDoc != null) {
|
114 | this.$__.priorDoc = options.priorDoc;
|
115 | }
|
116 |
|
117 | if (skipId) {
|
118 | this.$__.skipId = skipId;
|
119 | }
|
120 |
|
121 | if (obj != null && typeof obj !== 'object') {
|
122 | throw new ObjectParameterError(obj, 'obj', 'Document');
|
123 | }
|
124 |
|
125 | let defaults = true;
|
126 | if (options.defaults !== undefined) {
|
127 | this.$__.defaults = options.defaults;
|
128 | defaults = options.defaults;
|
129 | }
|
130 |
|
131 | const schema = this.$__schema;
|
132 |
|
133 | if (typeof fields === 'boolean' || fields === 'throw') {
|
134 | if (fields !== true) {
|
135 | this.$__.strictMode = fields;
|
136 | }
|
137 | fields = undefined;
|
138 | } else if (schema.options.strict !== true) {
|
139 | this.$__.strictMode = schema.options.strict;
|
140 | }
|
141 |
|
142 | const requiredPaths = schema.requiredPaths(true);
|
143 | for (const path of requiredPaths) {
|
144 | this.$__.activePaths.require(path);
|
145 | }
|
146 |
|
147 | let exclude = null;
|
148 |
|
149 |
|
150 |
|
151 | if (utils.isPOJO(fields) && Object.keys(fields).length > 0) {
|
152 | exclude = isExclusive(fields);
|
153 | this.$__.selected = fields;
|
154 | this.$__.exclude = exclude;
|
155 | }
|
156 |
|
157 | const hasIncludedChildren = exclude === false && fields ?
|
158 | $__hasIncludedChildren(fields) :
|
159 | null;
|
160 |
|
161 | if (this._doc == null) {
|
162 | this.$__buildDoc(obj, fields, skipId, exclude, hasIncludedChildren, false);
|
163 |
|
164 |
|
165 |
|
166 | if (defaults) {
|
167 | applyDefaults(this, fields, exclude, hasIncludedChildren, true, null, {
|
168 | skipParentChangeTracking: true
|
169 | });
|
170 | }
|
171 | }
|
172 | if (obj) {
|
173 |
|
174 | if (this.$__original_set) {
|
175 | this.$__original_set(obj, undefined, true, options);
|
176 | } else {
|
177 | this.$set(obj, undefined, true, options);
|
178 | }
|
179 |
|
180 | if (obj instanceof Document) {
|
181 | this.$isNew = obj.$isNew;
|
182 | }
|
183 | }
|
184 |
|
185 |
|
186 |
|
187 |
|
188 | if (options.willInit && defaults) {
|
189 | if (options.skipDefaults) {
|
190 | this.$__.skipDefaults = options.skipDefaults;
|
191 | }
|
192 | } else if (defaults) {
|
193 | applyDefaults(this, fields, exclude, hasIncludedChildren, false, options.skipDefaults);
|
194 | }
|
195 |
|
196 | if (!this.$__.strictMode && obj) {
|
197 | const _this = this;
|
198 | const keys = Object.keys(this._doc);
|
199 |
|
200 | keys.forEach(function(key) {
|
201 |
|
202 |
|
203 | if (!(key in schema.tree) && !(key in schema.methods) && !(key in schema.virtuals) && !key.startsWith('$')) {
|
204 | defineKey({ prop: key, subprops: null, prototype: _this });
|
205 | }
|
206 | });
|
207 | }
|
208 |
|
209 | applyQueue(this);
|
210 | }
|
211 |
|
212 | Document.prototype.$isMongooseDocumentPrototype = true;
|
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 |
|
227 |
|
228 |
|
229 |
|
230 |
|
231 |
|
232 |
|
233 |
|
234 |
|
235 |
|
236 |
|
237 |
|
238 |
|
239 |
|
240 |
|
241 |
|
242 |
|
243 |
|
244 |
|
245 |
|
246 |
|
247 |
|
248 |
|
249 |
|
250 |
|
251 |
|
252 |
|
253 |
|
254 |
|
255 |
|
256 |
|
257 |
|
258 |
|
259 |
|
260 |
|
261 |
|
262 |
|
263 |
|
264 |
|
265 | Object.defineProperty(Document.prototype, 'isNew', {
|
266 | get: function() {
|
267 | return this.$isNew;
|
268 | },
|
269 | set: function(value) {
|
270 | this.$isNew = value;
|
271 | }
|
272 | });
|
273 |
|
274 |
|
275 |
|
276 |
|
277 |
|
278 |
|
279 |
|
280 |
|
281 |
|
282 |
|
283 | Object.defineProperty(Document.prototype, 'errors', {
|
284 | get: function() {
|
285 | return this.$errors;
|
286 | },
|
287 | set: function(value) {
|
288 | this.$errors = value;
|
289 | }
|
290 | });
|
291 |
|
292 |
|
293 |
|
294 |
|
295 |
|
296 | Document.prototype.$isNew = true;
|
297 |
|
298 |
|
299 |
|
300 |
|
301 |
|
302 | utils.each(
|
303 | ['on', 'once', 'emit', 'listeners', 'removeListener', 'setMaxListeners',
|
304 | 'removeAllListeners', 'addListener'],
|
305 | function(emitterFn) {
|
306 | Document.prototype[emitterFn] = function() {
|
307 |
|
308 |
|
309 | if (!this.$__.emitter) {
|
310 | if (emitterFn === 'emit') {
|
311 | return;
|
312 | }
|
313 | this.$__.emitter = new EventEmitter();
|
314 | this.$__.emitter.setMaxListeners(0);
|
315 | }
|
316 | return this.$__.emitter[emitterFn].apply(this.$__.emitter, arguments);
|
317 | };
|
318 | Document.prototype[`$${emitterFn}`] = Document.prototype[emitterFn];
|
319 | });
|
320 |
|
321 | Document.prototype.constructor = Document;
|
322 |
|
323 | for (const i in EventEmitter.prototype) {
|
324 | Document[i] = EventEmitter.prototype[i];
|
325 | }
|
326 |
|
327 |
|
328 |
|
329 |
|
330 |
|
331 |
|
332 |
|
333 |
|
334 |
|
335 |
|
336 | Document.prototype.$__schema;
|
337 |
|
338 |
|
339 |
|
340 |
|
341 |
|
342 |
|
343 |
|
344 |
|
345 |
|
346 |
|
347 | Document.prototype.schema;
|
348 |
|
349 |
|
350 |
|
351 |
|
352 |
|
353 |
|
354 |
|
355 |
|
356 |
|
357 |
|
358 |
|
359 |
|
360 |
|
361 |
|
362 |
|
363 |
|
364 |
|
365 |
|
366 |
|
367 |
|
368 |
|
369 |
|
370 |
|
371 |
|
372 | Object.defineProperty(Document.prototype, '$locals', {
|
373 | configurable: false,
|
374 | enumerable: false,
|
375 | get: function() {
|
376 | if (this.$__.locals == null) {
|
377 | this.$__.locals = {};
|
378 | }
|
379 | return this.$__.locals;
|
380 | },
|
381 | set: function(v) {
|
382 | this.$__.locals = v;
|
383 | }
|
384 | });
|
385 |
|
386 |
|
387 |
|
388 |
|
389 |
|
390 |
|
391 |
|
392 |
|
393 |
|
394 |
|
395 |
|
396 | Document.prototype.isNew;
|
397 |
|
398 |
|
399 |
|
400 |
|
401 |
|
402 |
|
403 |
|
404 |
|
405 |
|
406 |
|
407 |
|
408 |
|
409 |
|
410 |
|
411 |
|
412 |
|
413 |
|
414 | Object.defineProperty(Document.prototype, '$where', {
|
415 | configurable: false,
|
416 | enumerable: false,
|
417 | writable: true
|
418 | });
|
419 |
|
420 |
|
421 |
|
422 |
|
423 |
|
424 |
|
425 |
|
426 |
|
427 |
|
428 |
|
429 |
|
430 |
|
431 |
|
432 |
|
433 |
|
434 |
|
435 |
|
436 | Document.prototype.id;
|
437 |
|
438 |
|
439 |
|
440 |
|
441 |
|
442 |
|
443 |
|
444 |
|
445 |
|
446 |
|
447 | Document.prototype.$errors;
|
448 |
|
449 |
|
450 |
|
451 |
|
452 |
|
453 |
|
454 |
|
455 |
|
456 |
|
457 |
|
458 |
|
459 |
|
460 |
|
461 |
|
462 |
|
463 |
|
464 |
|
465 |
|
466 |
|
467 |
|
468 |
|
469 |
|
470 | Object.defineProperty(Document.prototype, '$op', {
|
471 | get: function() {
|
472 | return this.$__.op || null;
|
473 | },
|
474 | set: function(value) {
|
475 | this.$__.op = value;
|
476 | }
|
477 | });
|
478 |
|
479 |
|
480 |
|
481 |
|
482 |
|
483 | function $applyDefaultsToNested(val, path, doc) {
|
484 | if (val == null) {
|
485 | return;
|
486 | }
|
487 |
|
488 | const paths = Object.keys(doc.$__schema.paths);
|
489 | const plen = paths.length;
|
490 |
|
491 | const pathPieces = path.indexOf('.') === -1 ? [path] : path.split('.');
|
492 |
|
493 | for (let i = 0; i < plen; ++i) {
|
494 | let curPath = '';
|
495 | const p = paths[i];
|
496 |
|
497 | if (!p.startsWith(path + '.')) {
|
498 | continue;
|
499 | }
|
500 |
|
501 | const type = doc.$__schema.paths[p];
|
502 | const pieces = type.splitPath().slice(pathPieces.length);
|
503 | const len = pieces.length;
|
504 |
|
505 | if (type.defaultValue === void 0) {
|
506 | continue;
|
507 | }
|
508 |
|
509 | let cur = val;
|
510 |
|
511 | for (let j = 0; j < len; ++j) {
|
512 | if (cur == null) {
|
513 | break;
|
514 | }
|
515 |
|
516 | const piece = pieces[j];
|
517 |
|
518 | if (j === len - 1) {
|
519 | if (cur[piece] !== void 0) {
|
520 | break;
|
521 | }
|
522 |
|
523 | try {
|
524 | const def = type.getDefault(doc, false);
|
525 | if (def !== void 0) {
|
526 | cur[piece] = def;
|
527 | }
|
528 | } catch (err) {
|
529 | doc.invalidate(path + '.' + curPath, err);
|
530 | break;
|
531 | }
|
532 |
|
533 | break;
|
534 | }
|
535 |
|
536 | curPath += (!curPath.length ? '' : '.') + piece;
|
537 |
|
538 | cur[piece] = cur[piece] || {};
|
539 | cur = cur[piece];
|
540 | }
|
541 | }
|
542 | }
|
543 |
|
544 |
|
545 |
|
546 |
|
547 |
|
548 |
|
549 |
|
550 |
|
551 |
|
552 |
|
553 |
|
554 |
|
555 |
|
556 |
|
557 |
|
558 | Document.prototype.$__buildDoc = function(obj, fields, skipId, exclude, hasIncludedChildren) {
|
559 | const doc = {};
|
560 |
|
561 | const paths = Object.keys(this.$__schema.paths).
|
562 |
|
563 |
|
564 | filter(p => !p.includes('$*'));
|
565 | const plen = paths.length;
|
566 | let ii = 0;
|
567 |
|
568 | for (; ii < plen; ++ii) {
|
569 | const p = paths[ii];
|
570 |
|
571 | if (p === '_id') {
|
572 | if (skipId) {
|
573 | continue;
|
574 | }
|
575 | if (obj && '_id' in obj) {
|
576 | continue;
|
577 | }
|
578 | }
|
579 |
|
580 | const path = this.$__schema.paths[p].splitPath();
|
581 | const len = path.length;
|
582 | const last = len - 1;
|
583 | let curPath = '';
|
584 | let doc_ = doc;
|
585 | let included = false;
|
586 |
|
587 | for (let i = 0; i < len; ++i) {
|
588 | const piece = path[i];
|
589 |
|
590 | if (!curPath.length) {
|
591 | curPath = piece;
|
592 | } else {
|
593 | curPath += '.' + piece;
|
594 | }
|
595 |
|
596 |
|
597 | if (exclude === true) {
|
598 | if (curPath in fields) {
|
599 | break;
|
600 | }
|
601 | } else if (exclude === false && fields && !included) {
|
602 | if (curPath in fields) {
|
603 | included = true;
|
604 | } else if (!hasIncludedChildren[curPath]) {
|
605 | break;
|
606 | }
|
607 | }
|
608 |
|
609 | if (i < last) {
|
610 | doc_ = doc_[piece] || (doc_[piece] = {});
|
611 | }
|
612 | }
|
613 | }
|
614 |
|
615 | this._doc = doc;
|
616 | };
|
617 |
|
618 |
|
619 |
|
620 |
|
621 |
|
622 | Document.prototype.toBSON = function() {
|
623 | return this.toObject(internalToObjectOptions);
|
624 | };
|
625 |
|
626 |
|
627 |
|
628 |
|
629 |
|
630 |
|
631 |
|
632 |
|
633 |
|
634 |
|
635 |
|
636 |
|
637 |
|
638 |
|
639 |
|
640 |
|
641 |
|
642 |
|
643 | Document.prototype.init = function(doc, opts, fn) {
|
644 | if (typeof opts === 'function') {
|
645 | fn = opts;
|
646 | opts = null;
|
647 | }
|
648 |
|
649 | this.$__init(doc, opts);
|
650 |
|
651 | if (fn) {
|
652 | fn(null, this);
|
653 | }
|
654 |
|
655 | return this;
|
656 | };
|
657 |
|
658 |
|
659 |
|
660 |
|
661 |
|
662 |
|
663 |
|
664 | Document.prototype.$init = function() {
|
665 | return this.constructor.prototype.init.apply(this, arguments);
|
666 | };
|
667 |
|
668 |
|
669 |
|
670 |
|
671 |
|
672 |
|
673 |
|
674 |
|
675 |
|
676 |
|
677 | Document.prototype.$__init = function(doc, opts) {
|
678 | this.$isNew = false;
|
679 | opts = opts || {};
|
680 |
|
681 |
|
682 |
|
683 | if (doc._id != null && opts.populated && opts.populated.length) {
|
684 | const id = String(doc._id);
|
685 | for (const item of opts.populated) {
|
686 | if (item.isVirtual) {
|
687 | this.$populated(item.path, utils.getValue(item.path, doc), item);
|
688 | } else {
|
689 | this.$populated(item.path, item._docs[id], item);
|
690 | }
|
691 |
|
692 | if (item._childDocs == null) {
|
693 | continue;
|
694 | }
|
695 | for (const child of item._childDocs) {
|
696 | if (child == null || child.$__ == null) {
|
697 | continue;
|
698 | }
|
699 | child.$__.parent = this;
|
700 | }
|
701 | item._childDocs = [];
|
702 | }
|
703 | }
|
704 |
|
705 | init(this, doc, this._doc, opts);
|
706 |
|
707 | markArraySubdocsPopulated(this, opts.populated);
|
708 | this.$emit('init', this);
|
709 | this.constructor.emit('init', this);
|
710 |
|
711 | const hasIncludedChildren = this.$__.exclude === false && this.$__.selected ?
|
712 | $__hasIncludedChildren(this.$__.selected) :
|
713 | null;
|
714 |
|
715 | applyDefaults(this, this.$__.selected, this.$__.exclude, hasIncludedChildren, false, this.$__.skipDefaults);
|
716 | return this;
|
717 | };
|
718 |
|
719 |
|
720 |
|
721 |
|
722 |
|
723 |
|
724 |
|
725 |
|
726 |
|
727 |
|
728 |
|
729 |
|
730 |
|
731 | function init(self, obj, doc, opts, prefix) {
|
732 | prefix = prefix || '';
|
733 |
|
734 | if (obj.$__ != null) {
|
735 | obj = obj._doc;
|
736 | }
|
737 | const keys = Object.keys(obj);
|
738 | const len = keys.length;
|
739 | let schemaType;
|
740 | let path;
|
741 | let i;
|
742 | let index = 0;
|
743 | const strict = self.$__.strictMode;
|
744 | const docSchema = self.$__schema;
|
745 |
|
746 | while (index < len) {
|
747 | _init(index++);
|
748 | }
|
749 |
|
750 | function _init(index) {
|
751 | i = keys[index];
|
752 |
|
753 | if (i === '__proto__' || i === 'constructor') {
|
754 | return;
|
755 | }
|
756 | path = prefix ? prefix + i : i;
|
757 | schemaType = docSchema.path(path);
|
758 |
|
759 |
|
760 |
|
761 | if (docSchema.$isRootDiscriminator && !self.$__isSelected(path)) {
|
762 | return;
|
763 | }
|
764 |
|
765 | const value = obj[i];
|
766 | if (!schemaType && utils.isPOJO(value)) {
|
767 |
|
768 | if (!doc[i]) {
|
769 | doc[i] = {};
|
770 | if (!strict && !(i in docSchema.tree) && !(i in docSchema.methods) && !(i in docSchema.virtuals)) {
|
771 | self[i] = doc[i];
|
772 | }
|
773 | }
|
774 | init(self, value, doc[i], opts, path + '.');
|
775 | } else if (!schemaType) {
|
776 | doc[i] = value;
|
777 | if (!strict && !prefix) {
|
778 | self[i] = value;
|
779 | }
|
780 | } else {
|
781 |
|
782 | if (doc.hasOwnProperty(i) && value !== void 0 && !opts.hydratedPopulatedDocs) {
|
783 | delete doc[i];
|
784 | }
|
785 | if (value === null) {
|
786 | doc[i] = schemaType._castNullish(null);
|
787 | } else if (value !== undefined) {
|
788 | const wasPopulated = value.$__ == null ? null : value.$__.wasPopulated;
|
789 |
|
790 | if (schemaType && !wasPopulated && !opts.hydratedPopulatedDocs) {
|
791 | try {
|
792 | if (opts && opts.setters) {
|
793 |
|
794 | const overrideInit = false;
|
795 | doc[i] = schemaType.applySetters(value, self, overrideInit);
|
796 | } else {
|
797 | doc[i] = schemaType.cast(value, self, true);
|
798 | }
|
799 | } catch (e) {
|
800 | self.invalidate(e.path, new ValidatorError({
|
801 | path: e.path,
|
802 | message: e.message,
|
803 | type: 'cast',
|
804 | value: e.value,
|
805 | reason: e
|
806 | }));
|
807 | }
|
808 | } else {
|
809 | doc[i] = value;
|
810 | }
|
811 | }
|
812 |
|
813 | if (!self.$isModified(path)) {
|
814 | self.$__.activePaths.init(path);
|
815 | }
|
816 | }
|
817 | }
|
818 | }
|
819 |
|
820 |
|
821 |
|
822 |
|
823 |
|
824 |
|
825 |
|
826 |
|
827 |
|
828 |
|
829 |
|
830 |
|
831 |
|
832 |
|
833 |
|
834 |
|
835 |
|
836 |
|
837 |
|
838 |
|
839 |
|
840 |
|
841 |
|
842 |
|
843 |
|
844 | Document.prototype.updateOne = function updateOne(doc, options, callback) {
|
845 | const query = this.constructor.updateOne({ _id: this._id }, doc, options);
|
846 | const self = this;
|
847 | query.pre(function queryPreUpdateOne(cb) {
|
848 | self.constructor._middleware.execPre('updateOne', self, [self], cb);
|
849 | });
|
850 | query.post(function queryPostUpdateOne(cb) {
|
851 | self.constructor._middleware.execPost('updateOne', self, [self], {}, cb);
|
852 | });
|
853 |
|
854 | if (this.$session() != null) {
|
855 | if (!('session' in query.options)) {
|
856 | query.options.session = this.$session();
|
857 | }
|
858 | }
|
859 |
|
860 | if (callback != null) {
|
861 | return query.exec(callback);
|
862 | }
|
863 |
|
864 | return query;
|
865 | };
|
866 |
|
867 |
|
868 |
|
869 |
|
870 |
|
871 |
|
872 |
|
873 |
|
874 |
|
875 |
|
876 |
|
877 |
|
878 |
|
879 |
|
880 |
|
881 |
|
882 |
|
883 |
|
884 | Document.prototype.replaceOne = function replaceOne() {
|
885 | const args = [...arguments];
|
886 | args.unshift({ _id: this._id });
|
887 | return this.constructor.replaceOne.apply(this.constructor, args);
|
888 | };
|
889 |
|
890 |
|
891 |
|
892 |
|
893 |
|
894 |
|
895 |
|
896 |
|
897 |
|
898 |
|
899 |
|
900 |
|
901 |
|
902 |
|
903 |
|
904 |
|
905 |
|
906 |
|
907 |
|
908 |
|
909 |
|
910 |
|
911 |
|
912 |
|
913 | Document.prototype.$session = function $session(session) {
|
914 | if (arguments.length === 0) {
|
915 | if (this.$__.session != null && this.$__.session.hasEnded) {
|
916 | this.$__.session = null;
|
917 | return null;
|
918 | }
|
919 | return this.$__.session;
|
920 | }
|
921 |
|
922 | if (session != null && session.hasEnded) {
|
923 | throw new MongooseError('Cannot set a document\'s session to a session that has ended. Make sure you haven\'t ' +
|
924 | 'called `endSession()` on the session you are passing to `$session()`.');
|
925 | }
|
926 |
|
927 | if (session == null && this.$__.session == null) {
|
928 | return;
|
929 | }
|
930 |
|
931 | this.$__.session = session;
|
932 |
|
933 | if (!this.$isSubdocument) {
|
934 | const subdocs = this.$getAllSubdocs();
|
935 | for (const child of subdocs) {
|
936 | child.$session(session);
|
937 | }
|
938 | }
|
939 |
|
940 | return session;
|
941 | };
|
942 |
|
943 |
|
944 |
|
945 |
|
946 |
|
947 |
|
948 |
|
949 |
|
950 |
|
951 |
|
952 |
|
953 |
|
954 |
|
955 |
|
956 |
|
957 |
|
958 |
|
959 |
|
960 |
|
961 |
|
962 |
|
963 |
|
964 | Document.prototype.$timestamps = function $timestamps(value) {
|
965 | if (arguments.length === 0) {
|
966 | if (this.$__.timestamps != null) {
|
967 | return this.$__.timestamps;
|
968 | }
|
969 |
|
970 | if (this.$__schema) {
|
971 | return this.$__schema.options.timestamps;
|
972 | }
|
973 |
|
974 | return undefined;
|
975 | }
|
976 |
|
977 | const currentValue = this.$timestamps();
|
978 | if (value !== currentValue) {
|
979 | this.$__.timestamps = value;
|
980 | }
|
981 |
|
982 | return this;
|
983 | };
|
984 |
|
985 |
|
986 |
|
987 |
|
988 |
|
989 |
|
990 |
|
991 |
|
992 |
|
993 |
|
994 |
|
995 |
|
996 |
|
997 |
|
998 | Document.prototype.overwrite = function overwrite(obj) {
|
999 | const keys = Array.from(new Set(Object.keys(this._doc).concat(Object.keys(obj))));
|
1000 |
|
1001 | for (const key of keys) {
|
1002 | if (key === '_id') {
|
1003 | continue;
|
1004 | }
|
1005 |
|
1006 | if (this.$__schema.options.versionKey && key === this.$__schema.options.versionKey) {
|
1007 | continue;
|
1008 | }
|
1009 | if (this.$__schema.options.discriminatorKey && key === this.$__schema.options.discriminatorKey) {
|
1010 | continue;
|
1011 | }
|
1012 | this.$set(key, obj[key]);
|
1013 | }
|
1014 |
|
1015 | return this;
|
1016 | };
|
1017 |
|
1018 | /**
|
1019 | * Alias for `set()`, used internally to avoid conflicts
|
1020 | *
|
1021 | * @param {String|Object} path path or object of key/vals to set
|
1022 | * @param {Any} val the value to set
|
1023 | * @param {Schema|String|Number|Buffer|*} [type] optionally specify a type for "on-the-fly" attributes
|
1024 | * @param {Object} [options] optionally specify options that modify the behavior of the set
|
1025 | * @param {Boolean} [options.merge=false] if true, setting a [nested path](https:
|
1026 | * @return {Document} this
|
1027 | * @method $set
|
1028 | * @memberOf Document
|
1029 | * @instance
|
1030 | * @api public
|
1031 | */
|
1032 |
|
1033 | Document.prototype.$set = function $set(path, val, type, options) {
|
1034 | if (utils.isPOJO(type)) {
|
1035 | options = type;
|
1036 | type = undefined;
|
1037 | }
|
1038 |
|
1039 | const merge = options && options.merge;
|
1040 | const adhoc = type && type !== true;
|
1041 | const constructing = type === true;
|
1042 | let adhocs;
|
1043 | let keys;
|
1044 | let i = 0;
|
1045 | let pathtype;
|
1046 | let key;
|
1047 | let prefix;
|
1048 |
|
1049 | const userSpecifiedStrict = options && 'strict' in options;
|
1050 | let strict = userSpecifiedStrict
|
1051 | ? options.strict
|
1052 | : this.$__.strictMode;
|
1053 |
|
1054 | if (adhoc) {
|
1055 | adhocs = this.$__.adhocPaths || (this.$__.adhocPaths = {});
|
1056 | adhocs[path] = this.$__schema.interpretAsType(path, type, this.$__schema.options);
|
1057 | }
|
1058 |
|
1059 | if (path == null) {
|
1060 | [path, val] = [val, path];
|
1061 | } else if (typeof path !== 'string') {
|
1062 |
|
1063 | if (path instanceof Document) {
|
1064 | if (path.$__isNested) {
|
1065 | path = path.toObject();
|
1066 | } else {
|
1067 |
|
1068 |
|
1069 | path = path.$__schema === this.$__schema
|
1070 | ? applyVirtuals(path, { ...path._doc })
|
1071 | : path._doc;
|
1072 | }
|
1073 | }
|
1074 | if (path == null) {
|
1075 | [path, val] = [val, path];
|
1076 | }
|
1077 |
|
1078 | prefix = val ? val + '.' : '';
|
1079 | keys = getKeysInSchemaOrder(this.$__schema, path);
|
1080 |
|
1081 | const len = keys.length;
|
1082 |
|
1083 |
|
1084 |
|
1085 | const _skipMinimizeTopLevel = options && options._skipMinimizeTopLevel || false;
|
1086 | if (len === 0 && _skipMinimizeTopLevel) {
|
1087 | delete options._skipMinimizeTopLevel;
|
1088 | if (val) {
|
1089 | this.$set(val, {});
|
1090 | }
|
1091 | return this;
|
1092 | }
|
1093 |
|
1094 | options = Object.assign({}, options, { _skipMinimizeTopLevel: false });
|
1095 |
|
1096 | for (let i = 0; i < len; ++i) {
|
1097 | key = keys[i];
|
1098 | const pathName = prefix ? prefix + key : key;
|
1099 | pathtype = this.$__schema.pathType(pathName);
|
1100 | const valForKey = path[key];
|
1101 |
|
1102 |
|
1103 |
|
1104 | if (type === true &&
|
1105 | !prefix &&
|
1106 | valForKey != null &&
|
1107 | pathtype === 'nested' &&
|
1108 | this._doc[key] != null) {
|
1109 | delete this._doc[key];
|
1110 | }
|
1111 |
|
1112 | if (utils.isNonBuiltinObject(valForKey) && pathtype === 'nested') {
|
1113 | this.$set(pathName, valForKey, constructing, Object.assign({}, options, { _skipMarkModified: true }));
|
1114 | $applyDefaultsToNested(this.$get(pathName), pathName, this);
|
1115 | continue;
|
1116 | } else if (strict) {
|
1117 |
|
1118 | if (constructing && valForKey === void 0 &&
|
1119 | this.$get(pathName) !== void 0) {
|
1120 | continue;
|
1121 | }
|
1122 |
|
1123 | if (pathtype === 'adhocOrUndefined') {
|
1124 | pathtype = getEmbeddedDiscriminatorPath(this, pathName, { typeOnly: true });
|
1125 | }
|
1126 |
|
1127 | if (pathtype === 'real' || pathtype === 'virtual') {
|
1128 | this.$set(pathName, valForKey, constructing, options);
|
1129 | } else if (pathtype === 'nested' && valForKey instanceof Document) {
|
1130 | this.$set(pathName,
|
1131 | valForKey.toObject({ transform: false }), constructing, options);
|
1132 | } else if (strict === 'throw') {
|
1133 | if (pathtype === 'nested') {
|
1134 | throw new ObjectExpectedError(key, valForKey);
|
1135 | } else {
|
1136 | throw new StrictModeError(key);
|
1137 | }
|
1138 | } else if (pathtype === 'nested' && valForKey == null) {
|
1139 | this.$set(pathName, valForKey, constructing, options);
|
1140 | }
|
1141 | } else if (valForKey !== void 0) {
|
1142 | this.$set(pathName, valForKey, constructing, options);
|
1143 | }
|
1144 | }
|
1145 |
|
1146 | // Ensure all properties are in correct order
|
1147 | const orderedDoc = {};
|
1148 | const orderedKeys = Object.keys(this.$__schema.tree);
|
1149 | for (let i = 0, len = orderedKeys.length; i < len; ++i) {
|
1150 | (key = orderedKeys[i]) &&
|
1151 | (this._doc.hasOwnProperty(key)) &&
|
1152 | (orderedDoc[key] = undefined);
|
1153 | }
|
1154 | this._doc = Object.assign(orderedDoc, this._doc);
|
1155 |
|
1156 | return this;
|
1157 | }
|
1158 |
|
1159 | let pathType = this.$__schema.pathType(path);
|
1160 | let parts = null;
|
1161 | if (pathType === 'adhocOrUndefined') {
|
1162 | parts = path.indexOf('.') === -1 ? [path] : path.split('.');
|
1163 | pathType = getEmbeddedDiscriminatorPath(this, parts, { typeOnly: true });
|
1164 | }
|
1165 | if (pathType === 'adhocOrUndefined' && !userSpecifiedStrict) {
|
1166 |
|
1167 | if (parts == null) {
|
1168 | parts = path.indexOf('.') === -1 ? [path] : path.split('.');
|
1169 | }
|
1170 | const subdocStrict = getSubdocumentStrictValue(this.$__schema, parts);
|
1171 | if (subdocStrict !== undefined) {
|
1172 | strict = subdocStrict;
|
1173 | }
|
1174 | }
|
1175 |
|
1176 |
|
1177 |
|
1178 | val = handleSpreadDoc(val, true);
|
1179 |
|
1180 |
|
1181 | const priorVal = (() => {
|
1182 | if (this.$__.priorDoc != null) {
|
1183 | return this.$__.priorDoc.$__getValue(path);
|
1184 | }
|
1185 | if (constructing) {
|
1186 | return void 0;
|
1187 | }
|
1188 | return this.$__getValue(path);
|
1189 | })();
|
1190 |
|
1191 | if (pathType === 'nested' && val) {
|
1192 | if (typeof val === 'object' && val != null) {
|
1193 | if (val.$__ != null) {
|
1194 | val = val.toObject(internalToObjectOptions);
|
1195 | }
|
1196 | if (val == null) {
|
1197 | this.invalidate(path, new MongooseError.CastError('Object', val, path));
|
1198 | return this;
|
1199 | }
|
1200 | const wasModified = this.$isModified(path);
|
1201 | const hasInitialVal = this.$__.savedState != null && this.$__.savedState.hasOwnProperty(path);
|
1202 | if (this.$__.savedState != null && !this.$isNew && !this.$__.savedState.hasOwnProperty(path)) {
|
1203 | const initialVal = this.$__getValue(path);
|
1204 | this.$__.savedState[path] = initialVal;
|
1205 |
|
1206 | const keys = Object.keys(initialVal || {});
|
1207 | for (const key of keys) {
|
1208 | this.$__.savedState[path + '.' + key] = initialVal[key];
|
1209 | }
|
1210 | }
|
1211 |
|
1212 | if (!merge) {
|
1213 | this.$__setValue(path, null);
|
1214 | cleanModifiedSubpaths(this, path);
|
1215 | } else {
|
1216 | return this.$set(val, path, constructing);
|
1217 | }
|
1218 |
|
1219 | const keys = getKeysInSchemaOrder(this.$__schema, val, path);
|
1220 |
|
1221 | this.$__setValue(path, {});
|
1222 | for (const key of keys) {
|
1223 | this.$set(path + '.' + key, val[key], constructing, { ...options, _skipMarkModified: true });
|
1224 | }
|
1225 | if (priorVal != null &&
|
1226 | (!wasModified || hasInitialVal) &&
|
1227 | utils.deepEqual(hasInitialVal ? this.$__.savedState[path] : priorVal, val)) {
|
1228 | this.unmarkModified(path);
|
1229 | } else {
|
1230 | this.markModified(path);
|
1231 | }
|
1232 | return this;
|
1233 | }
|
1234 | this.invalidate(path, new MongooseError.CastError('Object', val, path));
|
1235 | return this;
|
1236 | }
|
1237 |
|
1238 | let schema;
|
1239 | if (parts == null) {
|
1240 | parts = path.indexOf('.') === -1 ? [path] : path.split('.');
|
1241 | }
|
1242 |
|
1243 |
|
1244 | if (typeof this.$__schema.aliases[parts[0]] === 'string') {
|
1245 | parts[0] = this.$__schema.aliases[parts[0]];
|
1246 | }
|
1247 |
|
1248 | if (pathType === 'adhocOrUndefined' && strict) {
|
1249 |
|
1250 | let mixed;
|
1251 |
|
1252 | for (i = 0; i < parts.length; ++i) {
|
1253 | const subpath = parts.slice(0, i + 1).join('.');
|
1254 |
|
1255 |
|
1256 | if (i + 1 < parts.length && this.$__schema.pathType(subpath) === 'virtual') {
|
1257 | mpath.set(path, val, this);
|
1258 | return this;
|
1259 | }
|
1260 |
|
1261 | schema = this.$__schema.path(subpath);
|
1262 | if (schema == null) {
|
1263 | continue;
|
1264 | }
|
1265 |
|
1266 | if (schema instanceof MixedSchema) {
|
1267 |
|
1268 | mixed = true;
|
1269 | break;
|
1270 | } else if (schema.$isSchemaMap && schema.$__schemaType instanceof MixedSchema && i < parts.length - 1) {
|
1271 |
|
1272 | mixed = true;
|
1273 | schema = schema.$__schemaType;
|
1274 | break;
|
1275 | }
|
1276 | }
|
1277 |
|
1278 | if (schema == null) {
|
1279 |
|
1280 | schema = getEmbeddedDiscriminatorPath(this, path);
|
1281 | }
|
1282 |
|
1283 | if (!mixed && !schema) {
|
1284 | if (strict === 'throw') {
|
1285 | throw new StrictModeError(path);
|
1286 | }
|
1287 | return this;
|
1288 | }
|
1289 | } else if (pathType === 'virtual') {
|
1290 | schema = this.$__schema.virtualpath(path);
|
1291 | schema.applySetters(val, this);
|
1292 | return this;
|
1293 | } else {
|
1294 | schema = this.$__path(path);
|
1295 | }
|
1296 |
|
1297 |
|
1298 | let cur = this._doc;
|
1299 | let curPath = '';
|
1300 | for (i = 0; i < parts.length - 1; ++i) {
|
1301 | cur = cur[parts[i]];
|
1302 | curPath += (curPath.length !== 0 ? '.' : '') + parts[i];
|
1303 | if (!cur) {
|
1304 | this.$set(curPath, {});
|
1305 |
|
1306 |
|
1307 |
|
1308 |
|
1309 |
|
1310 | if (!this.$__isSelected(curPath)) {
|
1311 | this.unmarkModified(curPath);
|
1312 | }
|
1313 | cur = this.$__getValue(curPath);
|
1314 | }
|
1315 | }
|
1316 |
|
1317 | let pathToMark;
|
1318 |
|
1319 |
|
1320 |
|
1321 |
|
1322 | if (parts.length <= 1) {
|
1323 | pathToMark = path;
|
1324 | } else {
|
1325 | const len = parts.length;
|
1326 | for (i = 0; i < len; ++i) {
|
1327 | const subpath = parts.slice(0, i + 1).join('.');
|
1328 | if (this.$get(subpath, null, { getters: false }) === null) {
|
1329 | pathToMark = subpath;
|
1330 | break;
|
1331 | }
|
1332 | }
|
1333 |
|
1334 | if (!pathToMark) {
|
1335 | pathToMark = path;
|
1336 | }
|
1337 | }
|
1338 |
|
1339 | if (!schema) {
|
1340 | this.$__set(pathToMark, path, options, constructing, parts, schema, val, priorVal);
|
1341 |
|
1342 | if (pathType === 'nested' && val == null) {
|
1343 | cleanModifiedSubpaths(this, path);
|
1344 | }
|
1345 | return this;
|
1346 | }
|
1347 |
|
1348 |
|
1349 |
|
1350 |
|
1351 | if (schema.$isSingleNested || schema.$isMongooseArray) {
|
1352 | _markValidSubpaths(this, path);
|
1353 | }
|
1354 |
|
1355 | if (val != null && merge && schema.$isSingleNested) {
|
1356 | if (val instanceof Document) {
|
1357 | val = val.toObject({ virtuals: false, transform: false });
|
1358 | }
|
1359 | const keys = Object.keys(val);
|
1360 | for (const key of keys) {
|
1361 | this.$set(path + '.' + key, val[key], constructing, options);
|
1362 | }
|
1363 |
|
1364 | return this;
|
1365 | }
|
1366 |
|
1367 | let shouldSet = true;
|
1368 | try {
|
1369 |
|
1370 |
|
1371 | const refMatches = (() => {
|
1372 | if (schema.options == null) {
|
1373 | return false;
|
1374 | }
|
1375 | if (!(val instanceof Document)) {
|
1376 | return false;
|
1377 | }
|
1378 | const model = val.constructor;
|
1379 |
|
1380 |
|
1381 | const ref = schema.options.ref;
|
1382 | if (ref != null && (ref === model.modelName || ref === model.baseModelName)) {
|
1383 | return true;
|
1384 | }
|
1385 |
|
1386 |
|
1387 | const refPath = schema.options.refPath;
|
1388 | if (refPath == null) {
|
1389 | return false;
|
1390 | }
|
1391 | const modelName = val.get(refPath);
|
1392 | return modelName === model.modelName || modelName === model.baseModelName;
|
1393 | })();
|
1394 |
|
1395 | let didPopulate = false;
|
1396 | if (refMatches && val instanceof Document && (!val.$__.wasPopulated || utils.deepEqual(val.$__.wasPopulated.value, val._doc._id))) {
|
1397 | const unpopulatedValue = (schema && schema.$isSingleNested) ? schema.cast(val, this) : val._doc._id;
|
1398 | this.$populated(path, unpopulatedValue, { [populateModelSymbol]: val.constructor });
|
1399 | val.$__.wasPopulated = { value: unpopulatedValue };
|
1400 | didPopulate = true;
|
1401 | }
|
1402 |
|
1403 | let popOpts;
|
1404 | const typeKey = this.$__schema.options.typeKey;
|
1405 | if (schema.options &&
|
1406 | Array.isArray(schema.options[typeKey]) &&
|
1407 | schema.options[typeKey].length &&
|
1408 | schema.options[typeKey][0] &&
|
1409 | schema.options[typeKey][0].ref &&
|
1410 | _isManuallyPopulatedArray(val, schema.options[typeKey][0].ref)) {
|
1411 | popOpts = { [populateModelSymbol]: val[0].constructor };
|
1412 | this.$populated(path, val.map(function(v) { return v._doc._id; }), popOpts);
|
1413 |
|
1414 | for (const doc of val) {
|
1415 | doc.$__.wasPopulated = { value: doc._doc._id };
|
1416 | }
|
1417 | didPopulate = true;
|
1418 | }
|
1419 |
|
1420 | if (!refMatches || !schema.$isSingleNested || !val.$__) {
|
1421 |
|
1422 |
|
1423 |
|
1424 |
|
1425 | let setterContext = this;
|
1426 | if (this.$__schema.singleNestedPaths[path] != null && parts.length > 1) {
|
1427 | setterContext = getDeepestSubdocumentForPath(this, parts, this.schema);
|
1428 | }
|
1429 | if (options != null && options.overwriteImmutable) {
|
1430 | val = schema.applySetters(val, setterContext, false, priorVal, { overwriteImmutable: true });
|
1431 | } else {
|
1432 | val = schema.applySetters(val, setterContext, false, priorVal);
|
1433 | }
|
1434 | }
|
1435 |
|
1436 | if (Array.isArray(val) &&
|
1437 | !Array.isArray(schema) &&
|
1438 | schema.$isMongooseDocumentArray &&
|
1439 | val.length !== 0 &&
|
1440 | val[0] != null &&
|
1441 | val[0].$__ != null &&
|
1442 | val[0].$__.populated != null) {
|
1443 | const populatedPaths = Object.keys(val[0].$__.populated);
|
1444 | for (const populatedPath of populatedPaths) {
|
1445 | this.$populated(path + '.' + populatedPath,
|
1446 | val.map(v => v.$populated(populatedPath)),
|
1447 | val[0].$__.populated[populatedPath].options);
|
1448 | }
|
1449 | didPopulate = true;
|
1450 | }
|
1451 |
|
1452 | if (!didPopulate && this.$__.populated) {
|
1453 |
|
1454 |
|
1455 | if (Array.isArray(val) && this.$__.populated[path]) {
|
1456 | for (let i = 0; i < val.length; ++i) {
|
1457 | if (val[i] instanceof Document) {
|
1458 | val.set(i, val[i]._doc._id, true);
|
1459 | }
|
1460 | }
|
1461 | }
|
1462 | delete this.$__.populated[path];
|
1463 | }
|
1464 |
|
1465 | if (val != null && schema.$isSingleNested) {
|
1466 | _checkImmutableSubpaths(val, schema, priorVal);
|
1467 | }
|
1468 |
|
1469 | this.$markValid(path);
|
1470 | } catch (e) {
|
1471 | if (e instanceof MongooseError.StrictModeError && e.isImmutableError) {
|
1472 | this.invalidate(path, e);
|
1473 | } else if (e instanceof MongooseError.CastError) {
|
1474 | this.invalidate(e.path, e);
|
1475 | if (e.$originalErrorPath) {
|
1476 | this.invalidate(path,
|
1477 | new MongooseError.CastError(schema.instance, val, path, e.$originalErrorPath));
|
1478 | }
|
1479 | } else {
|
1480 | this.invalidate(path,
|
1481 | new MongooseError.CastError(schema.instance, val, path, e));
|
1482 | }
|
1483 | shouldSet = false;
|
1484 | }
|
1485 |
|
1486 | if (shouldSet) {
|
1487 | let savedState = null;
|
1488 | let savedStatePath = null;
|
1489 | if (!constructing) {
|
1490 | const doc = this.$isSubdocument ? this.ownerDocument() : this;
|
1491 | savedState = doc.$__.savedState;
|
1492 | savedStatePath = this.$isSubdocument ? this.$__.fullPath + '.' + path : path;
|
1493 | doc.$__saveInitialState(savedStatePath);
|
1494 | }
|
1495 |
|
1496 | this.$__set(pathToMark, path, options, constructing, parts, schema, val, priorVal);
|
1497 |
|
1498 | const isInTransaction = !!this.$__.session?.transaction;
|
1499 | const isModifiedWithinTransaction = this.$__.session &&
|
1500 | this.$__.session[sessionNewDocuments] &&
|
1501 | this.$__.session[sessionNewDocuments].has(this) &&
|
1502 | this.$__.session[sessionNewDocuments].get(this).modifiedPaths &&
|
1503 | !this.$__.session[sessionNewDocuments].get(this).modifiedPaths.has(savedStatePath);
|
1504 | if (savedState != null &&
|
1505 | savedState.hasOwnProperty(savedStatePath) &&
|
1506 | (!isInTransaction || isModifiedWithinTransaction) &&
|
1507 | utils.deepEqual(val, savedState[savedStatePath])) {
|
1508 | this.unmarkModified(path);
|
1509 | }
|
1510 | }
|
1511 |
|
1512 | if (schema.$isSingleNested && (this.isDirectModified(path) || val == null)) {
|
1513 | cleanModifiedSubpaths(this, path);
|
1514 | }
|
1515 |
|
1516 | return this;
|
1517 | };
|
1518 |
|
1519 |
|
1520 |
|
1521 |
|
1522 |
|
1523 | function _isManuallyPopulatedArray(val, ref) {
|
1524 | if (!Array.isArray(val)) {
|
1525 | return false;
|
1526 | }
|
1527 | if (val.length === 0) {
|
1528 | return false;
|
1529 | }
|
1530 |
|
1531 | for (const el of val) {
|
1532 | if (!(el instanceof Document)) {
|
1533 | return false;
|
1534 | }
|
1535 | const modelName = el.constructor.modelName;
|
1536 | if (modelName == null) {
|
1537 | return false;
|
1538 | }
|
1539 | if (el.constructor.modelName != ref && el.constructor.baseModelName != ref) {
|
1540 | return false;
|
1541 | }
|
1542 | }
|
1543 |
|
1544 | return true;
|
1545 | }
|
1546 |
|
1547 |
|
1548 |
|
1549 |
|
1550 |
|
1551 |
|
1552 |
|
1553 |
|
1554 |
|
1555 |
|
1556 |
|
1557 |
|
1558 |
|
1559 |
|
1560 |
|
1561 |
|
1562 |
|
1563 |
|
1564 |
|
1565 |
|
1566 |
|
1567 |
|
1568 |
|
1569 |
|
1570 |
|
1571 |
|
1572 |
|
1573 |
|
1574 |
|
1575 |
|
1576 |
|
1577 |
|
1578 |
|
1579 |
|
1580 |
|
1581 |
|
1582 |
|
1583 |
|
1584 | Document.prototype.set = Document.prototype.$set;
|
1585 |
|
1586 | /**
|
1587 | * Determine if we should mark this change as modified.
|
1588 | *
|
1589 | * @param {never} pathToMark UNUSED
|
1590 | * @param {String|Symbol} path
|
1591 | * @param {Object} options
|
1592 | * @param {Any} constructing
|
1593 | * @param {never} parts UNUSED
|
1594 | * @param {Schema} schema
|
1595 | * @param {Any} val
|
1596 | * @param {Any} priorVal
|
1597 | * @return {Boolean}
|
1598 | * @api private
|
1599 | * @method $__shouldModify
|
1600 | * @memberOf Document
|
1601 | * @instance
|
1602 | */
|
1603 |
|
1604 | Document.prototype.$__shouldModify = function(pathToMark, path, options, constructing, parts, schema, val, priorVal) {
|
1605 | if (options && options._skipMarkModified) {
|
1606 | return false;
|
1607 | }
|
1608 | if (this.$isNew) {
|
1609 | return true;
|
1610 | }
|
1611 |
|
1612 | if (path in this.$__.activePaths.getStatePaths('modify')) {
|
1613 | return true;
|
1614 | }
|
1615 |
|
1616 | if (val === void 0 && !this.$__isSelected(path)) {
|
1617 |
|
1618 |
|
1619 | return true;
|
1620 | }
|
1621 |
|
1622 | if (val === void 0 && path in this.$__.activePaths.getStatePaths('default')) {
|
1623 |
|
1624 | return false;
|
1625 | }
|
1626 |
|
1627 |
|
1628 |
|
1629 | if (this.$populated(path) &&
|
1630 | val instanceof Document &&
|
1631 | deepEqual(val._doc._id, priorVal)) {
|
1632 | return false;
|
1633 | }
|
1634 |
|
1635 | if (!deepEqual(val, priorVal !== undefined ? priorVal : utils.getValue(path, this))) {
|
1636 | return true;
|
1637 | }
|
1638 |
|
1639 | if (!constructing &&
|
1640 | val !== null &&
|
1641 | val !== undefined &&
|
1642 | path in this.$__.activePaths.getStatePaths('default') &&
|
1643 | deepEqual(val, schema.getDefault(this, constructing))) {
|
1644 |
|
1645 |
|
1646 | return true;
|
1647 | }
|
1648 | return false;
|
1649 | };
|
1650 |
|
1651 |
|
1652 |
|
1653 |
|
1654 |
|
1655 |
|
1656 |
|
1657 |
|
1658 |
|
1659 |
|
1660 |
|
1661 |
|
1662 |
|
1663 |
|
1664 |
|
1665 |
|
1666 |
|
1667 |
|
1668 | Document.prototype.$__set = function(pathToMark, path, options, constructing, parts, schema, val, priorVal) {
|
1669 | Embedded = Embedded || require('./types/arraySubdocument');
|
1670 |
|
1671 | const shouldModify = this.$__shouldModify(pathToMark, path, options, constructing, parts,
|
1672 | schema, val, priorVal);
|
1673 |
|
1674 | if (shouldModify) {
|
1675 | if (this.$__.primitiveAtomics && this.$__.primitiveAtomics[path]) {
|
1676 | delete this.$__.primitiveAtomics[path];
|
1677 | if (Object.keys(this.$__.primitiveAtomics).length === 0) {
|
1678 | delete this.$__.primitiveAtomics;
|
1679 | }
|
1680 | }
|
1681 | this.markModified(pathToMark);
|
1682 |
|
1683 |
|
1684 | MongooseArray || (MongooseArray = require('./types/array'));
|
1685 | if (val && utils.isMongooseArray(val)) {
|
1686 | val._registerAtomic('$set', val);
|
1687 |
|
1688 |
|
1689 | if (utils.isMongooseDocumentArray(val)) {
|
1690 | val.forEach(function(item) {
|
1691 | item && item.__parentArray && (item.__parentArray = val);
|
1692 | });
|
1693 | }
|
1694 | }
|
1695 | } else if (Array.isArray(val) && Array.isArray(priorVal) && utils.isMongooseArray(val) && utils.isMongooseArray(priorVal)) {
|
1696 | val[arrayAtomicsSymbol] = priorVal[arrayAtomicsSymbol];
|
1697 | val[arrayAtomicsBackupSymbol] = priorVal[arrayAtomicsBackupSymbol];
|
1698 | if (utils.isMongooseDocumentArray(val)) {
|
1699 | val.forEach(doc => {
|
1700 | if (doc != null) {
|
1701 | doc.$isNew = false;
|
1702 | }
|
1703 | });
|
1704 | }
|
1705 | }
|
1706 |
|
1707 | let obj = this._doc;
|
1708 | let i = 0;
|
1709 | const l = parts.length;
|
1710 | let cur = '';
|
1711 |
|
1712 | for (; i < l; i++) {
|
1713 | const next = i + 1;
|
1714 | const last = next === l;
|
1715 | cur += (cur ? '.' + parts[i] : parts[i]);
|
1716 | if (specialProperties.has(parts[i])) {
|
1717 | return;
|
1718 | }
|
1719 |
|
1720 | if (last) {
|
1721 | if (obj instanceof Map) {
|
1722 | obj.set(parts[i], val);
|
1723 | } else if (obj.$isSingleNested) {
|
1724 | if (!(parts[i] in obj)) {
|
1725 | obj[parts[i]] = val;
|
1726 | obj._doc[parts[i]] = val;
|
1727 | } else {
|
1728 | obj._doc[parts[i]] = val;
|
1729 | }
|
1730 | if (shouldModify) {
|
1731 | obj.markModified(parts[i]);
|
1732 | }
|
1733 | } else {
|
1734 | obj[parts[i]] = val;
|
1735 | }
|
1736 | } else {
|
1737 | const isMap = obj instanceof Map;
|
1738 | let value = isMap ? obj.get(parts[i]) : obj[parts[i]];
|
1739 | if (utils.isPOJO(value)) {
|
1740 | obj = value;
|
1741 | } else if (value && value instanceof Embedded) {
|
1742 | obj = value;
|
1743 | } else if (value && !Array.isArray(value) && value.$isSingleNested) {
|
1744 | obj = value;
|
1745 | } else if (value && Array.isArray(value)) {
|
1746 | obj = value;
|
1747 | } else if (value == null) {
|
1748 | value = {};
|
1749 | if (isMap) {
|
1750 | obj.set(parts[i], value);
|
1751 | } else {
|
1752 | obj[parts[i]] = value;
|
1753 | }
|
1754 | obj = value;
|
1755 | } else {
|
1756 | obj = value;
|
1757 | }
|
1758 | }
|
1759 | }
|
1760 | };
|
1761 |
|
1762 |
|
1763 |
|
1764 |
|
1765 |
|
1766 |
|
1767 |
|
1768 |
|
1769 |
|
1770 | Document.prototype.$__getValue = function(path) {
|
1771 | return utils.getValue(path, this._doc);
|
1772 | };
|
1773 |
|
1774 |
|
1775 |
|
1776 |
|
1777 |
|
1778 |
|
1779 |
|
1780 |
|
1781 |
|
1782 |
|
1783 |
|
1784 |
|
1785 |
|
1786 |
|
1787 |
|
1788 |
|
1789 |
|
1790 |
|
1791 |
|
1792 |
|
1793 |
|
1794 |
|
1795 |
|
1796 |
|
1797 |
|
1798 | Document.prototype.$inc = function $inc(path, val) {
|
1799 | if (val == null) {
|
1800 | val = 1;
|
1801 | }
|
1802 |
|
1803 | if (Array.isArray(path)) {
|
1804 | path.forEach((p) => this.$inc(p, val));
|
1805 | return this;
|
1806 | }
|
1807 |
|
1808 | const schemaType = this.$__path(path);
|
1809 | if (schemaType == null) {
|
1810 | if (this.$__.strictMode === 'throw') {
|
1811 | throw new StrictModeError(path);
|
1812 | } else if (this.$__.strictMode === true) {
|
1813 | return this;
|
1814 | }
|
1815 | } else if (schemaType.instance !== 'Number') {
|
1816 | this.invalidate(path, new MongooseError.CastError(schemaType.instance, val, path));
|
1817 | return this;
|
1818 | }
|
1819 |
|
1820 | const currentValue = this.$__getValue(path) || 0;
|
1821 | let shouldSet = false;
|
1822 | let valToSet = null;
|
1823 | let valToInc = val;
|
1824 |
|
1825 | try {
|
1826 | val = schemaType.cast(val);
|
1827 | valToSet = schemaType.applySetters(currentValue + val, this);
|
1828 | valToInc = valToSet - currentValue;
|
1829 | shouldSet = true;
|
1830 | } catch (err) {
|
1831 | this.invalidate(path, new MongooseError.CastError('number', val, path, err));
|
1832 | }
|
1833 |
|
1834 | if (shouldSet) {
|
1835 | this.$__.primitiveAtomics = this.$__.primitiveAtomics || {};
|
1836 | if (this.$__.primitiveAtomics[path] == null) {
|
1837 | this.$__.primitiveAtomics[path] = { $inc: valToInc };
|
1838 | } else {
|
1839 | this.$__.primitiveAtomics[path].$inc += valToInc;
|
1840 | }
|
1841 | this.markModified(path);
|
1842 | this.$__setValue(path, valToSet);
|
1843 | }
|
1844 |
|
1845 | return this;
|
1846 | };
|
1847 |
|
1848 |
|
1849 |
|
1850 |
|
1851 |
|
1852 |
|
1853 |
|
1854 |
|
1855 |
|
1856 |
|
1857 | Document.prototype.$__setValue = function(path, val) {
|
1858 | utils.setValue(path, val, this._doc);
|
1859 | return this;
|
1860 | };
|
1861 |
|
1862 |
|
1863 |
|
1864 |
|
1865 |
|
1866 |
|
1867 |
|
1868 |
|
1869 |
|
1870 |
|
1871 |
|
1872 |
|
1873 |
|
1874 |
|
1875 |
|
1876 |
|
1877 |
|
1878 |
|
1879 |
|
1880 |
|
1881 |
|
1882 | Document.prototype.get = function(path, type, options) {
|
1883 | let adhoc;
|
1884 | if (options == null) {
|
1885 | options = {};
|
1886 | }
|
1887 | if (type) {
|
1888 | adhoc = this.$__schema.interpretAsType(path, type, this.$__schema.options);
|
1889 | }
|
1890 | const noDottedPath = options.noDottedPath;
|
1891 |
|
1892 |
|
1893 |
|
1894 | let schema = noDottedPath ? this.$__schema.paths[path] : this.$__path(path);
|
1895 | if (schema == null) {
|
1896 | schema = this.$__schema.virtualpath(path);
|
1897 |
|
1898 | if (schema != null) {
|
1899 | return schema.applyGetters(void 0, this);
|
1900 | }
|
1901 | }
|
1902 |
|
1903 | if (noDottedPath) {
|
1904 | let obj = this._doc[path];
|
1905 | if (adhoc) {
|
1906 | obj = adhoc.cast(obj);
|
1907 | }
|
1908 | if (schema != null && options.getters !== false) {
|
1909 | return schema.applyGetters(obj, this);
|
1910 | }
|
1911 | return obj;
|
1912 | }
|
1913 |
|
1914 | if (schema != null && schema.instance === 'Mixed') {
|
1915 | const virtual = this.$__schema.virtualpath(path);
|
1916 | if (virtual != null) {
|
1917 | schema = virtual;
|
1918 | }
|
1919 | }
|
1920 |
|
1921 | const hasDot = path.indexOf('.') !== -1;
|
1922 | let obj = this._doc;
|
1923 |
|
1924 | const pieces = hasDot ? path.split('.') : [path];
|
1925 |
|
1926 | if (typeof this.$__schema.aliases[pieces[0]] === 'string') {
|
1927 | pieces[0] = this.$__schema.aliases[pieces[0]];
|
1928 | }
|
1929 |
|
1930 | for (let i = 0, l = pieces.length; i < l; i++) {
|
1931 | if (obj && obj._doc) {
|
1932 | obj = obj._doc;
|
1933 | }
|
1934 |
|
1935 | if (obj == null) {
|
1936 | obj = void 0;
|
1937 | } else if (obj instanceof Map) {
|
1938 | obj = obj.get(pieces[i], { getters: false });
|
1939 | } else if (i === l - 1) {
|
1940 | obj = utils.getValue(pieces[i], obj);
|
1941 | } else {
|
1942 | obj = obj[pieces[i]];
|
1943 | }
|
1944 | }
|
1945 |
|
1946 | if (adhoc) {
|
1947 | obj = adhoc.cast(obj);
|
1948 | }
|
1949 |
|
1950 | if (schema != null && options.getters !== false) {
|
1951 | obj = schema.applyGetters(obj, this);
|
1952 | } else if (this.$__schema.nested[path] && options.virtuals) {
|
1953 |
|
1954 | return applyVirtuals(this, clone(obj) || {}, { path: path });
|
1955 | }
|
1956 |
|
1957 | return obj;
|
1958 | };
|
1959 |
|
1960 |
|
1961 |
|
1962 |
|
1963 |
|
1964 | Document.prototype[getSymbol] = Document.prototype.get;
|
1965 | Document.prototype.$get = Document.prototype.get;
|
1966 |
|
1967 | /**
|
1968 | * Returns the schematype for the given `path`.
|
1969 | *
|
1970 | * @param {String} path
|
1971 | * @return {SchemaPath}
|
1972 | * @api private
|
1973 | * @method $__path
|
1974 | * @memberOf Document
|
1975 | * @instance
|
1976 | */
|
1977 |
|
1978 | Document.prototype.$__path = function(path) {
|
1979 | const adhocs = this.$__.adhocPaths;
|
1980 | const adhocType = adhocs && adhocs.hasOwnProperty(path) ? adhocs[path] : null;
|
1981 |
|
1982 | if (adhocType) {
|
1983 | return adhocType;
|
1984 | }
|
1985 | return this.$__schema.path(path);
|
1986 | };
|
1987 |
|
1988 |
|
1989 |
|
1990 |
|
1991 |
|
1992 |
|
1993 |
|
1994 |
|
1995 |
|
1996 |
|
1997 |
|
1998 |
|
1999 |
|
2000 |
|
2001 |
|
2002 |
|
2003 |
|
2004 | Document.prototype.markModified = function(path, scope) {
|
2005 | this.$__saveInitialState(path);
|
2006 |
|
2007 | this.$__.activePaths.modify(path);
|
2008 | if (scope != null && !this.$isSubdocument) {
|
2009 | this.$__.pathsToScopes = this.$__pathsToScopes || {};
|
2010 | this.$__.pathsToScopes[path] = scope;
|
2011 | }
|
2012 | };
|
2013 |
|
2014 |
|
2015 |
|
2016 |
|
2017 |
|
2018 | Document.prototype.$__saveInitialState = function $__saveInitialState(path) {
|
2019 | const savedState = this.$__.savedState;
|
2020 | const savedStatePath = path;
|
2021 | if (savedState != null) {
|
2022 | const firstDot = savedStatePath.indexOf('.');
|
2023 | const topLevelPath = firstDot === -1 ? savedStatePath : savedStatePath.slice(0, firstDot);
|
2024 | if (!savedState.hasOwnProperty(topLevelPath)) {
|
2025 | savedState[topLevelPath] = clone(this.$__getValue(topLevelPath));
|
2026 | }
|
2027 | }
|
2028 | };
|
2029 |
|
2030 |
|
2031 |
|
2032 |
|
2033 |
|
2034 |
|
2035 |
|
2036 |
|
2037 |
|
2038 |
|
2039 |
|
2040 |
|
2041 |
|
2042 |
|
2043 | Document.prototype.unmarkModified = function(path) {
|
2044 | this.$__.activePaths.init(path);
|
2045 | if (this.$__.pathsToScopes != null) {
|
2046 | delete this.$__.pathsToScopes[path];
|
2047 | }
|
2048 | };
|
2049 |
|
2050 |
|
2051 |
|
2052 |
|
2053 |
|
2054 |
|
2055 |
|
2056 |
|
2057 |
|
2058 |
|
2059 |
|
2060 |
|
2061 |
|
2062 |
|
2063 |
|
2064 |
|
2065 |
|
2066 | Document.prototype.$ignore = function(path) {
|
2067 | this.$__.activePaths.ignore(path);
|
2068 | };
|
2069 |
|
2070 |
|
2071 |
|
2072 |
|
2073 |
|
2074 |
|
2075 |
|
2076 |
|
2077 |
|
2078 |
|
2079 |
|
2080 |
|
2081 |
|
2082 |
|
2083 |
|
2084 |
|
2085 |
|
2086 |
|
2087 |
|
2088 |
|
2089 |
|
2090 |
|
2091 |
|
2092 |
|
2093 | Document.prototype.directModifiedPaths = function() {
|
2094 | return Object.keys(this.$__.activePaths.getStatePaths('modify'));
|
2095 | };
|
2096 |
|
2097 |
|
2098 |
|
2099 |
|
2100 |
|
2101 |
|
2102 |
|
2103 |
|
2104 |
|
2105 |
|
2106 |
|
2107 |
|
2108 |
|
2109 |
|
2110 |
|
2111 |
|
2112 |
|
2113 |
|
2114 |
|
2115 |
|
2116 |
|
2117 |
|
2118 |
|
2119 |
|
2120 |
|
2121 |
|
2122 | Document.prototype.$isEmpty = function(path) {
|
2123 | const isEmptyOptions = {
|
2124 | minimize: true,
|
2125 | virtuals: false,
|
2126 | getters: false,
|
2127 | transform: false
|
2128 | };
|
2129 |
|
2130 | if (arguments.length !== 0) {
|
2131 | const v = this.$get(path);
|
2132 | if (v == null) {
|
2133 | return true;
|
2134 | }
|
2135 | if (typeof v !== 'object') {
|
2136 | return false;
|
2137 | }
|
2138 | if (utils.isPOJO(v)) {
|
2139 | return _isEmpty(v);
|
2140 | }
|
2141 | return Object.keys(v.toObject(isEmptyOptions)).length === 0;
|
2142 | }
|
2143 |
|
2144 | return Object.keys(this.toObject(isEmptyOptions)).length === 0;
|
2145 | };
|
2146 |
|
2147 |
|
2148 |
|
2149 |
|
2150 |
|
2151 | function _isEmpty(v) {
|
2152 | if (v == null) {
|
2153 | return true;
|
2154 | }
|
2155 | if (typeof v !== 'object' || Array.isArray(v)) {
|
2156 | return false;
|
2157 | }
|
2158 | for (const key of Object.keys(v)) {
|
2159 | if (!_isEmpty(v[key])) {
|
2160 | return false;
|
2161 | }
|
2162 | }
|
2163 | return true;
|
2164 | }
|
2165 |
|
2166 |
|
2167 |
|
2168 |
|
2169 |
|
2170 |
|
2171 |
|
2172 |
|
2173 |
|
2174 |
|
2175 | Document.prototype.modifiedPaths = function(options) {
|
2176 | options = options || {};
|
2177 |
|
2178 | const directModifiedPaths = Object.keys(this.$__.activePaths.getStatePaths('modify'));
|
2179 | const result = new Set();
|
2180 |
|
2181 | let i = 0;
|
2182 | let j = 0;
|
2183 | const len = directModifiedPaths.length;
|
2184 |
|
2185 | for (i = 0; i < len; ++i) {
|
2186 | const path = directModifiedPaths[i];
|
2187 | const parts = parentPaths(path);
|
2188 | const pLen = parts.length;
|
2189 |
|
2190 | for (j = 0; j < pLen; ++j) {
|
2191 | result.add(parts[j]);
|
2192 | }
|
2193 |
|
2194 | if (!options.includeChildren) {
|
2195 | continue;
|
2196 | }
|
2197 |
|
2198 | let ii = 0;
|
2199 | let cur = this.$get(path);
|
2200 | if (typeof cur === 'object' && cur !== null) {
|
2201 | if (cur._doc) {
|
2202 | cur = cur._doc;
|
2203 | }
|
2204 | const len = cur.length;
|
2205 | if (Array.isArray(cur)) {
|
2206 | for (ii = 0; ii < len; ++ii) {
|
2207 | const subPath = path + '.' + ii;
|
2208 | if (!result.has(subPath)) {
|
2209 | result.add(subPath);
|
2210 | if (cur[ii] != null && cur[ii].$__) {
|
2211 | const modified = cur[ii].modifiedPaths();
|
2212 | let iii = 0;
|
2213 | const iiiLen = modified.length;
|
2214 | for (iii = 0; iii < iiiLen; ++iii) {
|
2215 | result.add(subPath + '.' + modified[iii]);
|
2216 | }
|
2217 | }
|
2218 | }
|
2219 | }
|
2220 | } else {
|
2221 | const keys = Object.keys(cur);
|
2222 | let ii = 0;
|
2223 | const len = keys.length;
|
2224 | for (ii = 0; ii < len; ++ii) {
|
2225 | result.add(path + '.' + keys[ii]);
|
2226 | }
|
2227 | }
|
2228 | }
|
2229 | }
|
2230 | return Array.from(result);
|
2231 | };
|
2232 |
|
2233 | Document.prototype[documentModifiedPaths] = Document.prototype.modifiedPaths;
|
2234 |
|
2235 |
|
2236 |
|
2237 |
|
2238 |
|
2239 |
|
2240 |
|
2241 |
|
2242 |
|
2243 |
|
2244 |
|
2245 |
|
2246 |
|
2247 |
|
2248 |
|
2249 |
|
2250 |
|
2251 |
|
2252 |
|
2253 |
|
2254 |
|
2255 |
|
2256 |
|
2257 | Document.prototype.isModified = function(paths, options, modifiedPaths) {
|
2258 | if (paths) {
|
2259 | const ignoreAtomics = options && options.ignoreAtomics;
|
2260 | const directModifiedPathsObj = this.$__.activePaths.states.modify;
|
2261 | if (directModifiedPathsObj == null) {
|
2262 | return false;
|
2263 | }
|
2264 |
|
2265 | if (typeof paths === 'string') {
|
2266 | paths = paths.indexOf(' ') === -1 ? [paths] : paths.split(' ');
|
2267 | }
|
2268 |
|
2269 | for (const path of paths) {
|
2270 | if (directModifiedPathsObj[path] != null) {
|
2271 | return true;
|
2272 | }
|
2273 | }
|
2274 |
|
2275 | const modified = modifiedPaths || this[documentModifiedPaths]();
|
2276 | const isModifiedChild = paths.some(function(path) {
|
2277 | return !!~modified.indexOf(path);
|
2278 | });
|
2279 |
|
2280 | let directModifiedPaths = Object.keys(directModifiedPathsObj);
|
2281 | if (ignoreAtomics) {
|
2282 | directModifiedPaths = directModifiedPaths.filter(path => {
|
2283 | const value = this.$__getValue(path);
|
2284 | if (value != null && value[arrayAtomicsSymbol] != null && value[arrayAtomicsSymbol].$set === undefined) {
|
2285 | return false;
|
2286 | }
|
2287 | return true;
|
2288 | });
|
2289 | }
|
2290 | return isModifiedChild || paths.some(function(path) {
|
2291 | return directModifiedPaths.some(function(mod) {
|
2292 | return mod === path || path.startsWith(mod + '.');
|
2293 | });
|
2294 | });
|
2295 | }
|
2296 |
|
2297 | return this.$__.activePaths.some('modify');
|
2298 | };
|
2299 |
|
2300 |
|
2301 |
|
2302 |
|
2303 |
|
2304 |
|
2305 |
|
2306 |
|
2307 |
|
2308 | Document.prototype.$isModified = Document.prototype.isModified;
|
2309 |
|
2310 | Document.prototype[documentIsModified] = Document.prototype.isModified;
|
2311 |
|
2312 |
|
2313 |
|
2314 |
|
2315 |
|
2316 |
|
2317 |
|
2318 |
|
2319 |
|
2320 |
|
2321 |
|
2322 |
|
2323 |
|
2324 |
|
2325 |
|
2326 |
|
2327 |
|
2328 |
|
2329 | Document.prototype.$isDefault = function(path) {
|
2330 | if (path == null) {
|
2331 | return this.$__.activePaths.some('default');
|
2332 | }
|
2333 |
|
2334 | if (typeof path === 'string' && path.indexOf(' ') === -1) {
|
2335 | return this.$__.activePaths.getStatePaths('default').hasOwnProperty(path);
|
2336 | }
|
2337 |
|
2338 | let paths = path;
|
2339 | if (!Array.isArray(paths)) {
|
2340 | paths = paths.split(' ');
|
2341 | }
|
2342 |
|
2343 | return paths.some(path => this.$__.activePaths.getStatePaths('default').hasOwnProperty(path));
|
2344 | };
|
2345 |
|
2346 |
|
2347 |
|
2348 |
|
2349 |
|
2350 |
|
2351 |
|
2352 |
|
2353 |
|
2354 |
|
2355 |
|
2356 |
|
2357 |
|
2358 |
|
2359 |
|
2360 |
|
2361 |
|
2362 |
|
2363 |
|
2364 |
|
2365 |
|
2366 |
|
2367 |
|
2368 | Document.prototype.$isDeleted = function(val) {
|
2369 | if (arguments.length === 0) {
|
2370 | return !!this.$__.isDeleted;
|
2371 | }
|
2372 |
|
2373 | this.$__.isDeleted = !!val;
|
2374 | return this;
|
2375 | };
|
2376 |
|
2377 |
|
2378 |
|
2379 |
|
2380 |
|
2381 |
|
2382 |
|
2383 |
|
2384 |
|
2385 |
|
2386 |
|
2387 |
|
2388 |
|
2389 |
|
2390 |
|
2391 | Document.prototype.isDirectModified = function(path) {
|
2392 | if (path == null) {
|
2393 | return this.$__.activePaths.some('modify');
|
2394 | }
|
2395 |
|
2396 | if (typeof path === 'string' && path.indexOf(' ') === -1) {
|
2397 | const res = this.$__.activePaths.getStatePaths('modify').hasOwnProperty(path);
|
2398 | if (res || path.indexOf('.') === -1) {
|
2399 | return res;
|
2400 | }
|
2401 |
|
2402 | const pieces = path.split('.');
|
2403 | for (let i = 0; i < pieces.length - 1; ++i) {
|
2404 | const subpath = pieces.slice(0, i + 1).join('.');
|
2405 | const subdoc = this.$get(subpath);
|
2406 | if (subdoc != null && subdoc.$__ != null && subdoc.isDirectModified(pieces.slice(i + 1).join('.'))) {
|
2407 | return true;
|
2408 | }
|
2409 | }
|
2410 |
|
2411 | return false;
|
2412 | }
|
2413 |
|
2414 | let paths = path;
|
2415 | if (typeof paths === 'string') {
|
2416 | paths = paths.split(' ');
|
2417 | }
|
2418 |
|
2419 | return paths.some(path => this.isDirectModified(path));
|
2420 | };
|
2421 |
|
2422 |
|
2423 |
|
2424 |
|
2425 |
|
2426 |
|
2427 |
|
2428 |
|
2429 |
|
2430 | Document.prototype.isInit = function(path) {
|
2431 | if (path == null) {
|
2432 | return this.$__.activePaths.some('init');
|
2433 | }
|
2434 |
|
2435 | if (typeof path === 'string' && path.indexOf(' ') === -1) {
|
2436 | return this.$__.activePaths.getStatePaths('init').hasOwnProperty(path);
|
2437 | }
|
2438 |
|
2439 | let paths = path;
|
2440 | if (!Array.isArray(paths)) {
|
2441 | paths = paths.split(' ');
|
2442 | }
|
2443 |
|
2444 | return paths.some(path => this.$__.activePaths.getStatePaths('init').hasOwnProperty(path));
|
2445 | };
|
2446 |
|
2447 |
|
2448 |
|
2449 |
|
2450 |
|
2451 |
|
2452 |
|
2453 |
|
2454 |
|
2455 |
|
2456 |
|
2457 |
|
2458 |
|
2459 |
|
2460 |
|
2461 | Document.prototype.isSelected = function isSelected(path) {
|
2462 | if (this.$__.selected == null) {
|
2463 | return true;
|
2464 | }
|
2465 | if (!path) {
|
2466 | return false;
|
2467 | }
|
2468 | if (path === '_id') {
|
2469 | return this.$__.selected._id !== 0;
|
2470 | }
|
2471 |
|
2472 | if (path.indexOf(' ') !== -1) {
|
2473 | path = path.split(' ');
|
2474 | }
|
2475 | if (Array.isArray(path)) {
|
2476 | return path.some(p => this.$__isSelected(p));
|
2477 | }
|
2478 |
|
2479 | const paths = Object.keys(this.$__.selected);
|
2480 | let inclusive = null;
|
2481 |
|
2482 | if (paths.length === 1 && paths[0] === '_id') {
|
2483 |
|
2484 | return this.$__.selected._id === 0;
|
2485 | }
|
2486 |
|
2487 | for (const cur of paths) {
|
2488 | if (cur === '_id') {
|
2489 | continue;
|
2490 | }
|
2491 | if (!isDefiningProjection(this.$__.selected[cur])) {
|
2492 | continue;
|
2493 | }
|
2494 | inclusive = !!this.$__.selected[cur];
|
2495 | break;
|
2496 | }
|
2497 |
|
2498 | if (inclusive === null) {
|
2499 | return true;
|
2500 | }
|
2501 |
|
2502 | if (path in this.$__.selected) {
|
2503 | return inclusive;
|
2504 | }
|
2505 |
|
2506 | const pathDot = path + '.';
|
2507 |
|
2508 | for (const cur of paths) {
|
2509 | if (cur === '_id') {
|
2510 | continue;
|
2511 | }
|
2512 |
|
2513 | if (cur.startsWith(pathDot)) {
|
2514 | return inclusive || cur !== pathDot;
|
2515 | }
|
2516 |
|
2517 | if (pathDot.startsWith(cur + '.')) {
|
2518 | return inclusive;
|
2519 | }
|
2520 | }
|
2521 | return !inclusive;
|
2522 | };
|
2523 |
|
2524 | Document.prototype.$__isSelected = Document.prototype.isSelected;
|
2525 |
|
2526 |
|
2527 |
|
2528 |
|
2529 |
|
2530 |
|
2531 |
|
2532 |
|
2533 |
|
2534 |
|
2535 |
|
2536 |
|
2537 |
|
2538 |
|
2539 |
|
2540 |
|
2541 |
|
2542 |
|
2543 | Document.prototype.isDirectSelected = function isDirectSelected(path) {
|
2544 | if (this.$__.selected == null) {
|
2545 | return true;
|
2546 | }
|
2547 |
|
2548 | if (path === '_id') {
|
2549 | return this.$__.selected._id !== 0;
|
2550 | }
|
2551 |
|
2552 | if (path.indexOf(' ') !== -1) {
|
2553 | path = path.split(' ');
|
2554 | }
|
2555 | if (Array.isArray(path)) {
|
2556 | return path.some(p => this.isDirectSelected(p));
|
2557 | }
|
2558 |
|
2559 | const paths = Object.keys(this.$__.selected);
|
2560 | let inclusive = null;
|
2561 |
|
2562 | if (paths.length === 1 && paths[0] === '_id') {
|
2563 |
|
2564 | return this.$__.selected._id === 0;
|
2565 | }
|
2566 |
|
2567 | for (const cur of paths) {
|
2568 | if (cur === '_id') {
|
2569 | continue;
|
2570 | }
|
2571 | if (!isDefiningProjection(this.$__.selected[cur])) {
|
2572 | continue;
|
2573 | }
|
2574 | inclusive = !!this.$__.selected[cur];
|
2575 | break;
|
2576 | }
|
2577 |
|
2578 | if (inclusive === null) {
|
2579 | return true;
|
2580 | }
|
2581 |
|
2582 | if (this.$__.selected.hasOwnProperty(path)) {
|
2583 | return inclusive;
|
2584 | }
|
2585 |
|
2586 | return !inclusive;
|
2587 | };
|
2588 |
|
2589 |
|
2590 |
|
2591 |
|
2592 |
|
2593 |
|
2594 |
|
2595 |
|
2596 |
|
2597 |
|
2598 |
|
2599 |
|
2600 |
|
2601 |
|
2602 |
|
2603 |
|
2604 |
|
2605 |
|
2606 |
|
2607 |
|
2608 | Document.prototype.validate = async function validate(pathsToValidate, options) {
|
2609 | if (typeof pathsToValidate === 'function' || typeof options === 'function' || typeof arguments[2] === 'function') {
|
2610 | throw new MongooseError('Document.prototype.validate() no longer accepts a callback');
|
2611 | }
|
2612 | let parallelValidate;
|
2613 | this.$op = 'validate';
|
2614 |
|
2615 | if (arguments.length === 1) {
|
2616 | if (typeof arguments[0] === 'object' && !Array.isArray(arguments[0])) {
|
2617 | options = arguments[0];
|
2618 | pathsToValidate = null;
|
2619 | }
|
2620 | }
|
2621 | if (options && typeof options.pathsToSkip === 'string') {
|
2622 | const isOnePathOnly = options.pathsToSkip.indexOf(' ') === -1;
|
2623 | options.pathsToSkip = isOnePathOnly ? [options.pathsToSkip] : options.pathsToSkip.split(' ');
|
2624 | }
|
2625 | const _skipParallelValidateCheck = options && options._skipParallelValidateCheck;
|
2626 |
|
2627 | if (this.$isSubdocument != null) {
|
2628 |
|
2629 | } else if (this.$__.validating && !_skipParallelValidateCheck) {
|
2630 | parallelValidate = new ParallelValidateError(this, {
|
2631 | parentStack: options && options.parentStack,
|
2632 | conflictStack: this.$__.validating.stack
|
2633 | });
|
2634 | } else if (!_skipParallelValidateCheck) {
|
2635 | this.$__.validating = new ParallelValidateError(this, { parentStack: options && options.parentStack });
|
2636 | }
|
2637 |
|
2638 | if (parallelValidate != null) {
|
2639 | throw parallelValidate;
|
2640 | }
|
2641 |
|
2642 | return new Promise((resolve, reject) => {
|
2643 | this.$__validate(pathsToValidate, options, (error) => {
|
2644 | this.$op = null;
|
2645 | this.$__.validating = null;
|
2646 | if (error != null) {
|
2647 | return reject(error);
|
2648 | }
|
2649 | resolve();
|
2650 | });
|
2651 | });
|
2652 | };
|
2653 |
|
2654 |
|
2655 |
|
2656 |
|
2657 |
|
2658 |
|
2659 |
|
2660 |
|
2661 |
|
2662 | Document.prototype.$validate = Document.prototype.validate;
|
2663 |
|
2664 |
|
2665 |
|
2666 |
|
2667 |
|
2668 | function _evaluateRequiredFunctions(doc) {
|
2669 | const requiredFields = Object.keys(doc.$__.activePaths.getStatePaths('require'));
|
2670 | let i = 0;
|
2671 | const len = requiredFields.length;
|
2672 | for (i = 0; i < len; ++i) {
|
2673 | const path = requiredFields[i];
|
2674 |
|
2675 | const p = doc.$__schema.path(path);
|
2676 |
|
2677 | if (p != null && typeof p.originalRequiredValue === 'function') {
|
2678 | doc.$__.cachedRequired = doc.$__.cachedRequired || {};
|
2679 | try {
|
2680 | doc.$__.cachedRequired[path] = p.originalRequiredValue.call(doc, doc);
|
2681 | } catch (err) {
|
2682 | doc.invalidate(path, err);
|
2683 | }
|
2684 | }
|
2685 | }
|
2686 | }
|
2687 |
|
2688 |
|
2689 |
|
2690 |
|
2691 |
|
2692 | function _getPathsToValidate(doc, pathsToValidate, pathsToSkip) {
|
2693 | const doValidateOptions = {};
|
2694 |
|
2695 | _evaluateRequiredFunctions(doc);
|
2696 |
|
2697 | let paths = new Set(Object.keys(doc.$__.activePaths.getStatePaths('require')).filter(function(path) {
|
2698 | if (!doc.$__isSelected(path) && !doc.$isModified(path)) {
|
2699 | return false;
|
2700 | }
|
2701 | if (doc.$__.cachedRequired != null && path in doc.$__.cachedRequired) {
|
2702 | return doc.$__.cachedRequired[path];
|
2703 | }
|
2704 | return true;
|
2705 | }));
|
2706 |
|
2707 | Object.keys(doc.$__.activePaths.getStatePaths('init')).forEach(addToPaths);
|
2708 | Object.keys(doc.$__.activePaths.getStatePaths('modify')).forEach(addToPaths);
|
2709 | Object.keys(doc.$__.activePaths.getStatePaths('default')).forEach(addToPaths);
|
2710 | function addToPaths(p) { paths.add(p); }
|
2711 |
|
2712 | const subdocs = doc.$getAllSubdocs();
|
2713 | const modifiedPaths = doc.modifiedPaths();
|
2714 | for (const subdoc of subdocs) {
|
2715 | if (subdoc.$basePath) {
|
2716 | const fullPathToSubdoc = subdoc.$isSingleNested ? subdoc.$__pathRelativeToParent() : subdoc.$__fullPathWithIndexes();
|
2717 |
|
2718 |
|
2719 |
|
2720 |
|
2721 |
|
2722 | for (const modifiedPath of subdoc.modifiedPaths()) {
|
2723 | paths.delete(fullPathToSubdoc + '.' + modifiedPath);
|
2724 | }
|
2725 |
|
2726 | if (doc.$isModified(fullPathToSubdoc, null, modifiedPaths) &&
|
2727 | !doc.isDirectModified(fullPathToSubdoc) &&
|
2728 | !doc.$isDefault(fullPathToSubdoc)) {
|
2729 | paths.add(fullPathToSubdoc);
|
2730 |
|
2731 | if (doc.$__.pathsToScopes == null) {
|
2732 | doc.$__.pathsToScopes = {};
|
2733 | }
|
2734 | doc.$__.pathsToScopes[fullPathToSubdoc] = subdoc.$isDocumentArrayElement ?
|
2735 | subdoc.__parentArray :
|
2736 | subdoc.$parent();
|
2737 |
|
2738 | doValidateOptions[fullPathToSubdoc] = { skipSchemaValidators: true };
|
2739 | if (subdoc.$isDocumentArrayElement && subdoc.__index != null) {
|
2740 | doValidateOptions[fullPathToSubdoc].index = subdoc.__index;
|
2741 | }
|
2742 | }
|
2743 | }
|
2744 | }
|
2745 |
|
2746 | for (const path of paths) {
|
2747 | const _pathType = doc.$__schema.path(path);
|
2748 | if (!_pathType) {
|
2749 | continue;
|
2750 | }
|
2751 |
|
2752 | if (_pathType.$isMongooseDocumentArray) {
|
2753 | for (const p of paths) {
|
2754 | if (p == null || p.startsWith(_pathType.path + '.')) {
|
2755 | paths.delete(p);
|
2756 | }
|
2757 | }
|
2758 | }
|
2759 |
|
2760 |
|
2761 |
|
2762 | if (!_pathType.caster && _pathType.validators.length === 0 && !_pathType.$parentSchemaDocArray) {
|
2763 | paths.delete(path);
|
2764 | } else if (_pathType.$isMongooseArray &&
|
2765 | !_pathType.$isMongooseDocumentArray &&
|
2766 | !_pathType.$embeddedSchemaType.$isMongooseArray &&
|
2767 | _pathType.validators.length === 0 &&
|
2768 | _pathType.$embeddedSchemaType.validators.length === 0) {
|
2769 | paths.delete(path);
|
2770 | }
|
2771 | }
|
2772 |
|
2773 |
|
2774 | if (Array.isArray(pathsToValidate)) {
|
2775 | paths = _handlePathsToValidate(paths, pathsToValidate);
|
2776 | } else if (Array.isArray(pathsToSkip)) {
|
2777 | paths = _handlePathsToSkip(paths, pathsToSkip);
|
2778 | }
|
2779 |
|
2780 |
|
2781 |
|
2782 |
|
2783 |
|
2784 | _addArrayPathsToValidate(doc, paths);
|
2785 |
|
2786 | const flattenOptions = { skipArrays: true };
|
2787 | for (const pathToCheck of paths) {
|
2788 | if (doc.$__schema.nested[pathToCheck]) {
|
2789 | let _v = doc.$__getValue(pathToCheck);
|
2790 | if (isMongooseObject(_v)) {
|
2791 | _v = _v.toObject({ transform: false });
|
2792 | }
|
2793 | const flat = flatten(_v, pathToCheck, flattenOptions, doc.$__schema);
|
2794 |
|
2795 |
|
2796 |
|
2797 | Object.keys(flat).filter(path => !doc.$__schema.singleNestedPaths.hasOwnProperty(path)).forEach(addToPaths);
|
2798 | }
|
2799 | }
|
2800 |
|
2801 | for (const path of paths) {
|
2802 | const _pathType = doc.$__schema.path(path);
|
2803 |
|
2804 | if (!_pathType) {
|
2805 | continue;
|
2806 | }
|
2807 |
|
2808 |
|
2809 |
|
2810 |
|
2811 | if (_pathType.$parentSchemaDocArray && typeof _pathType.$parentSchemaDocArray.path === 'string') {
|
2812 | paths.add(_pathType.$parentSchemaDocArray.path);
|
2813 | }
|
2814 |
|
2815 | if (!_pathType.$isSchemaMap) {
|
2816 | continue;
|
2817 | }
|
2818 |
|
2819 | const val = doc.$__getValue(path);
|
2820 | if (val == null) {
|
2821 | continue;
|
2822 | }
|
2823 | for (const key of val.keys()) {
|
2824 | paths.add(path + '.' + key);
|
2825 | }
|
2826 | }
|
2827 |
|
2828 | paths = Array.from(paths);
|
2829 | return [paths, doValidateOptions];
|
2830 | }
|
2831 |
|
2832 | function _addArrayPathsToValidate(doc, paths) {
|
2833 | for (const path of paths) {
|
2834 | const _pathType = doc.$__schema.path(path);
|
2835 | if (!_pathType) {
|
2836 | continue;
|
2837 | }
|
2838 |
|
2839 | if (!_pathType.$isMongooseArray ||
|
2840 |
|
2841 |
|
2842 |
|
2843 | (!Array.isArray(_pathType) &&
|
2844 | _pathType.$isMongooseDocumentArray &&
|
2845 | !(_pathType && _pathType.schemaOptions && _pathType.schemaOptions.required))) {
|
2846 | continue;
|
2847 | }
|
2848 |
|
2849 |
|
2850 |
|
2851 | if (_pathType.$isMongooseArray &&
|
2852 | !_pathType.$isMongooseDocumentArray &&
|
2853 | !_pathType.$embeddedSchemaType.$isMongooseArray &&
|
2854 | _pathType.$embeddedSchemaType.validators.length === 0) {
|
2855 | continue;
|
2856 | }
|
2857 |
|
2858 | const val = doc.$__getValue(path);
|
2859 | _pushNestedArrayPaths(val, paths, path);
|
2860 | }
|
2861 | }
|
2862 |
|
2863 | function _pushNestedArrayPaths(val, paths, path) {
|
2864 | if (val != null) {
|
2865 | const numElements = val.length;
|
2866 | for (let j = 0; j < numElements; ++j) {
|
2867 | if (Array.isArray(val[j])) {
|
2868 | _pushNestedArrayPaths(val[j], paths, path + '.' + j);
|
2869 | } else {
|
2870 | paths.add(path + '.' + j);
|
2871 | }
|
2872 | }
|
2873 | }
|
2874 | }
|
2875 |
|
2876 |
|
2877 |
|
2878 |
|
2879 |
|
2880 | Document.prototype.$__validate = function(pathsToValidate, options, callback) {
|
2881 | if (this.$__.saveOptions && this.$__.saveOptions.pathsToSave && !pathsToValidate) {
|
2882 | pathsToValidate = [...this.$__.saveOptions.pathsToSave];
|
2883 | } else if (typeof pathsToValidate === 'function') {
|
2884 | callback = pathsToValidate;
|
2885 | options = null;
|
2886 | pathsToValidate = null;
|
2887 | } else if (typeof options === 'function') {
|
2888 | callback = options;
|
2889 | options = null;
|
2890 | }
|
2891 |
|
2892 | const hasValidateModifiedOnlyOption = options &&
|
2893 | (typeof options === 'object') &&
|
2894 | ('validateModifiedOnly' in options);
|
2895 |
|
2896 | const pathsToSkip = (options && options.pathsToSkip) || null;
|
2897 |
|
2898 | let shouldValidateModifiedOnly;
|
2899 | if (hasValidateModifiedOnlyOption) {
|
2900 | shouldValidateModifiedOnly = !!options.validateModifiedOnly;
|
2901 | } else {
|
2902 | shouldValidateModifiedOnly = this.$__schema.options.validateModifiedOnly;
|
2903 | }
|
2904 |
|
2905 | const validateAllPaths = options && options.validateAllPaths;
|
2906 | if (validateAllPaths) {
|
2907 | if (pathsToSkip) {
|
2908 | throw new TypeError('Cannot set both `validateAllPaths` and `pathsToSkip`');
|
2909 | }
|
2910 | if (pathsToValidate) {
|
2911 | throw new TypeError('Cannot set both `validateAllPaths` and `pathsToValidate`');
|
2912 | }
|
2913 | if (hasValidateModifiedOnlyOption && shouldValidateModifiedOnly) {
|
2914 | throw new TypeError('Cannot set both `validateAllPaths` and `validateModifiedOnly`');
|
2915 | }
|
2916 | }
|
2917 |
|
2918 | const _this = this;
|
2919 | const _complete = () => {
|
2920 | let validationError = this.$__.validationError;
|
2921 | this.$__.validationError = null;
|
2922 | this.$__.validating = null;
|
2923 |
|
2924 | if (shouldValidateModifiedOnly && validationError != null) {
|
2925 |
|
2926 | const errors = Object.keys(validationError.errors);
|
2927 | for (const errPath of errors) {
|
2928 | if (!this.$isModified(errPath)) {
|
2929 | delete validationError.errors[errPath];
|
2930 | }
|
2931 | }
|
2932 | if (Object.keys(validationError.errors).length === 0) {
|
2933 | validationError = void 0;
|
2934 | }
|
2935 | }
|
2936 |
|
2937 | this.$__.cachedRequired = {};
|
2938 | this.$emit('validate', _this);
|
2939 | this.constructor.emit('validate', _this);
|
2940 |
|
2941 | if (validationError) {
|
2942 | for (const key in validationError.errors) {
|
2943 |
|
2944 | if (!this[documentArrayParent] &&
|
2945 | validationError.errors[key] instanceof MongooseError.CastError) {
|
2946 | this.invalidate(key, validationError.errors[key]);
|
2947 | }
|
2948 | }
|
2949 |
|
2950 | return validationError;
|
2951 | }
|
2952 | };
|
2953 |
|
2954 |
|
2955 | let paths;
|
2956 | let doValidateOptionsByPath;
|
2957 | if (validateAllPaths) {
|
2958 | paths = new Set(Object.keys(this.$__schema.paths));
|
2959 |
|
2960 |
|
2961 | for (const path of paths) {
|
2962 | const schemaType = this.$__schema.path(path);
|
2963 | if (!schemaType || !schemaType.$isMongooseArray) {
|
2964 | continue;
|
2965 | }
|
2966 | const val = this.$__getValue(path);
|
2967 | if (!val) {
|
2968 | continue;
|
2969 | }
|
2970 | _pushNestedArrayPaths(val, paths, path);
|
2971 | }
|
2972 | paths = [...paths];
|
2973 | doValidateOptionsByPath = {};
|
2974 | } else {
|
2975 | const pathDetails = _getPathsToValidate(this, pathsToValidate, pathsToSkip);
|
2976 | paths = shouldValidateModifiedOnly ?
|
2977 | pathDetails[0].filter((path) => this.$isModified(path)) :
|
2978 | pathDetails[0];
|
2979 | doValidateOptionsByPath = pathDetails[1];
|
2980 | }
|
2981 |
|
2982 | if (typeof pathsToValidate === 'string') {
|
2983 | pathsToValidate = pathsToValidate.split(' ');
|
2984 | }
|
2985 |
|
2986 | if (paths.length === 0) {
|
2987 | return immediate(function() {
|
2988 | const error = _complete();
|
2989 | if (error) {
|
2990 | return _this.$__schema.s.hooks.execPost('validate:error', _this, [_this], { error: error }, function(error) {
|
2991 | callback(error);
|
2992 | });
|
2993 | }
|
2994 | callback(null, _this);
|
2995 | });
|
2996 | }
|
2997 |
|
2998 | const validated = {};
|
2999 | let total = 0;
|
3000 |
|
3001 | let pathsToSave = this.$__.saveOptions?.pathsToSave;
|
3002 | if (Array.isArray(pathsToSave)) {
|
3003 | pathsToSave = new Set(pathsToSave);
|
3004 | for (const path of paths) {
|
3005 | if (!pathsToSave.has(path)) {
|
3006 | continue;
|
3007 | }
|
3008 | validatePath(path);
|
3009 | }
|
3010 | } else {
|
3011 | for (const path of paths) {
|
3012 | validatePath(path);
|
3013 | }
|
3014 | }
|
3015 |
|
3016 | function validatePath(path) {
|
3017 | if (path == null || validated[path]) {
|
3018 | return;
|
3019 | }
|
3020 |
|
3021 | validated[path] = true;
|
3022 | total++;
|
3023 |
|
3024 | immediate(function() {
|
3025 | const schemaType = _this.$__schema.path(path);
|
3026 |
|
3027 | if (!schemaType) {
|
3028 | return --total || complete();
|
3029 | }
|
3030 |
|
3031 |
|
3032 | if (!_this.$isValid(path)) {
|
3033 | --total || complete();
|
3034 | return;
|
3035 | }
|
3036 |
|
3037 |
|
3038 | if (schemaType[schemaMixedSymbol] != null && path !== schemaType.path) {
|
3039 | return --total || complete();
|
3040 | }
|
3041 |
|
3042 | let val = _this.$__getValue(path);
|
3043 |
|
3044 |
|
3045 |
|
3046 |
|
3047 | let pop;
|
3048 | if ((pop = _this.$populated(path))) {
|
3049 | val = pop;
|
3050 | } else if (val != null && val.$__ != null && val.$__.wasPopulated) {
|
3051 |
|
3052 |
|
3053 | val = val._id;
|
3054 | }
|
3055 | const scope = _this.$__.pathsToScopes != null && path in _this.$__.pathsToScopes ?
|
3056 | _this.$__.pathsToScopes[path] :
|
3057 | _this;
|
3058 |
|
3059 | const doValidateOptions = {
|
3060 | ...doValidateOptionsByPath[path],
|
3061 | path: path,
|
3062 | validateAllPaths
|
3063 | };
|
3064 |
|
3065 | schemaType.doValidate(val, function(err) {
|
3066 | if (err) {
|
3067 | const isSubdoc = schemaType.$isSingleNested ||
|
3068 | schemaType.$isArraySubdocument ||
|
3069 | schemaType.$isMongooseDocumentArray;
|
3070 | if (isSubdoc && err instanceof ValidationError) {
|
3071 | return --total || complete();
|
3072 | }
|
3073 | _this.invalidate(path, err, undefined, true);
|
3074 | }
|
3075 | --total || complete();
|
3076 | }, scope, doValidateOptions);
|
3077 | });
|
3078 | }
|
3079 |
|
3080 | function complete() {
|
3081 | const error = _complete();
|
3082 | if (error) {
|
3083 | return _this.$__schema.s.hooks.execPost('validate:error', _this, [_this], { error: error }, function(error) {
|
3084 | callback(error);
|
3085 | });
|
3086 | }
|
3087 | callback(null, _this);
|
3088 | }
|
3089 |
|
3090 | };
|
3091 |
|
3092 |
|
3093 |
|
3094 |
|
3095 |
|
3096 | function _handlePathsToValidate(paths, pathsToValidate) {
|
3097 | const _pathsToValidate = new Set(pathsToValidate);
|
3098 | const parentPaths = new Map([]);
|
3099 | for (const path of pathsToValidate) {
|
3100 | if (path.indexOf('.') === -1) {
|
3101 | continue;
|
3102 | }
|
3103 | const pieces = path.split('.');
|
3104 | let cur = pieces[0];
|
3105 | for (let i = 1; i < pieces.length; ++i) {
|
3106 |
|
3107 |
|
3108 |
|
3109 | parentPaths.set(cur, path);
|
3110 | cur = cur + '.' + pieces[i];
|
3111 | }
|
3112 | }
|
3113 |
|
3114 | const ret = new Set();
|
3115 | for (const path of paths) {
|
3116 | if (_pathsToValidate.has(path)) {
|
3117 | ret.add(path);
|
3118 | } else if (parentPaths.has(path)) {
|
3119 | ret.add(parentPaths.get(path));
|
3120 | }
|
3121 | }
|
3122 | return ret;
|
3123 | }
|
3124 |
|
3125 |
|
3126 |
|
3127 |
|
3128 |
|
3129 | function _handlePathsToSkip(paths, pathsToSkip) {
|
3130 | pathsToSkip = new Set(pathsToSkip);
|
3131 | paths = Array.from(paths).filter(p => !pathsToSkip.has(p));
|
3132 | return new Set(paths);
|
3133 | }
|
3134 |
|
3135 |
|
3136 |
|
3137 |
|
3138 |
|
3139 |
|
3140 |
|
3141 |
|
3142 |
|
3143 |
|
3144 |
|
3145 |
|
3146 |
|
3147 |
|
3148 |
|
3149 |
|
3150 |
|
3151 |
|
3152 |
|
3153 |
|
3154 |
|
3155 |
|
3156 |
|
3157 |
|
3158 |
|
3159 | Document.prototype.validateSync = function(pathsToValidate, options) {
|
3160 | const _this = this;
|
3161 |
|
3162 | if (arguments.length === 1 && typeof arguments[0] === 'object' && !Array.isArray(arguments[0])) {
|
3163 | options = arguments[0];
|
3164 | pathsToValidate = null;
|
3165 | }
|
3166 |
|
3167 | const hasValidateModifiedOnlyOption = options &&
|
3168 | (typeof options === 'object') &&
|
3169 | ('validateModifiedOnly' in options);
|
3170 |
|
3171 | let shouldValidateModifiedOnly;
|
3172 | if (hasValidateModifiedOnlyOption) {
|
3173 | shouldValidateModifiedOnly = !!options.validateModifiedOnly;
|
3174 | } else {
|
3175 | shouldValidateModifiedOnly = this.$__schema.options.validateModifiedOnly;
|
3176 | }
|
3177 |
|
3178 | let pathsToSkip = options && options.pathsToSkip;
|
3179 |
|
3180 | const validateAllPaths = options && options.validateAllPaths;
|
3181 | if (validateAllPaths) {
|
3182 | if (pathsToSkip) {
|
3183 | throw new TypeError('Cannot set both `validateAllPaths` and `pathsToSkip`');
|
3184 | }
|
3185 | if (pathsToValidate) {
|
3186 | throw new TypeError('Cannot set both `validateAllPaths` and `pathsToValidate`');
|
3187 | }
|
3188 | }
|
3189 |
|
3190 | if (typeof pathsToValidate === 'string') {
|
3191 | const isOnePathOnly = pathsToValidate.indexOf(' ') === -1;
|
3192 | pathsToValidate = isOnePathOnly ? [pathsToValidate] : pathsToValidate.split(' ');
|
3193 | } else if (typeof pathsToSkip === 'string' && pathsToSkip.indexOf(' ') !== -1) {
|
3194 | pathsToSkip = pathsToSkip.split(' ');
|
3195 | }
|
3196 |
|
3197 |
|
3198 | let paths;
|
3199 | let skipSchemaValidators;
|
3200 | if (validateAllPaths) {
|
3201 | paths = new Set(Object.keys(this.$__schema.paths));
|
3202 |
|
3203 |
|
3204 | for (const path of paths) {
|
3205 | const schemaType = this.$__schema.path(path);
|
3206 | if (!schemaType || !schemaType.$isMongooseArray) {
|
3207 | continue;
|
3208 | }
|
3209 | const val = this.$__getValue(path);
|
3210 | if (!val) {
|
3211 | continue;
|
3212 | }
|
3213 | _pushNestedArrayPaths(val, paths, path);
|
3214 | }
|
3215 | paths = [...paths];
|
3216 | skipSchemaValidators = {};
|
3217 | } else {
|
3218 | const pathDetails = _getPathsToValidate(this, pathsToValidate, pathsToSkip);
|
3219 | paths = shouldValidateModifiedOnly ?
|
3220 | pathDetails[0].filter((path) => this.$isModified(path)) :
|
3221 | pathDetails[0];
|
3222 | skipSchemaValidators = pathDetails[1];
|
3223 | }
|
3224 |
|
3225 | const validating = {};
|
3226 |
|
3227 | for (let i = 0, len = paths.length; i < len; ++i) {
|
3228 | const path = paths[i];
|
3229 |
|
3230 | if (validating[path]) {
|
3231 | continue;
|
3232 | }
|
3233 |
|
3234 | validating[path] = true;
|
3235 |
|
3236 | const p = _this.$__schema.path(path);
|
3237 | if (!p) {
|
3238 | continue;
|
3239 | }
|
3240 | if (!_this.$isValid(path)) {
|
3241 | continue;
|
3242 | }
|
3243 |
|
3244 | const val = _this.$__getValue(path);
|
3245 | const err = p.doValidateSync(val, _this, {
|
3246 | skipSchemaValidators: skipSchemaValidators[path],
|
3247 | path: path,
|
3248 | validateModifiedOnly: shouldValidateModifiedOnly,
|
3249 | validateAllPaths
|
3250 | });
|
3251 | if (err) {
|
3252 | const isSubdoc = p.$isSingleNested ||
|
3253 | p.$isArraySubdocument ||
|
3254 | p.$isMongooseDocumentArray;
|
3255 | if (isSubdoc && err instanceof ValidationError) {
|
3256 | continue;
|
3257 | }
|
3258 | _this.invalidate(path, err, undefined, true);
|
3259 | }
|
3260 | }
|
3261 |
|
3262 | const err = _this.$__.validationError;
|
3263 | _this.$__.validationError = undefined;
|
3264 | _this.$emit('validate', _this);
|
3265 | _this.constructor.emit('validate', _this);
|
3266 |
|
3267 | if (err) {
|
3268 | for (const key in err.errors) {
|
3269 |
|
3270 | if (err.errors[key] instanceof MongooseError.CastError) {
|
3271 | _this.invalidate(key, err.errors[key]);
|
3272 | }
|
3273 | }
|
3274 | }
|
3275 |
|
3276 | return err;
|
3277 | };
|
3278 |
|
3279 |
|
3280 |
|
3281 |
|
3282 |
|
3283 |
|
3284 |
|
3285 |
|
3286 |
|
3287 |
|
3288 |
|
3289 |
|
3290 |
|
3291 |
|
3292 |
|
3293 |
|
3294 |
|
3295 |
|
3296 |
|
3297 |
|
3298 |
|
3299 |
|
3300 |
|
3301 |
|
3302 |
|
3303 |
|
3304 |
|
3305 |
|
3306 |
|
3307 |
|
3308 |
|
3309 |
|
3310 | Document.prototype.invalidate = function(path, err, val, kind) {
|
3311 | if (!this.$__.validationError) {
|
3312 | this.$__.validationError = new ValidationError(this);
|
3313 | }
|
3314 |
|
3315 | if (this.$__.validationError.errors[path]) {
|
3316 | return;
|
3317 | }
|
3318 |
|
3319 | if (!err || typeof err === 'string') {
|
3320 | err = new ValidatorError({
|
3321 | path: path,
|
3322 | message: err,
|
3323 | type: kind || 'user defined',
|
3324 | value: val
|
3325 | });
|
3326 | }
|
3327 |
|
3328 | if (this.$__.validationError === err) {
|
3329 | return this.$__.validationError;
|
3330 | }
|
3331 |
|
3332 | this.$__.validationError.addError(path, err);
|
3333 | return this.$__.validationError;
|
3334 | };
|
3335 |
|
3336 |
|
3337 |
|
3338 |
|
3339 |
|
3340 |
|
3341 |
|
3342 |
|
3343 |
|
3344 |
|
3345 |
|
3346 | Document.prototype.$markValid = function(path) {
|
3347 | if (!this.$__.validationError || !this.$__.validationError.errors[path]) {
|
3348 | return;
|
3349 | }
|
3350 |
|
3351 | delete this.$__.validationError.errors[path];
|
3352 | if (Object.keys(this.$__.validationError.errors).length === 0) {
|
3353 | this.$__.validationError = null;
|
3354 | }
|
3355 | };
|
3356 |
|
3357 |
|
3358 |
|
3359 |
|
3360 |
|
3361 | function _markValidSubpaths(doc, path) {
|
3362 | if (!doc.$__.validationError) {
|
3363 | return;
|
3364 | }
|
3365 |
|
3366 | const keys = Object.keys(doc.$__.validationError.errors);
|
3367 | for (const key of keys) {
|
3368 | if (key.startsWith(path + '.')) {
|
3369 | delete doc.$__.validationError.errors[key];
|
3370 | }
|
3371 | }
|
3372 | if (Object.keys(doc.$__.validationError.errors).length === 0) {
|
3373 | doc.$__.validationError = null;
|
3374 | }
|
3375 | }
|
3376 |
|
3377 |
|
3378 |
|
3379 |
|
3380 |
|
3381 | function _checkImmutableSubpaths(subdoc, schematype, priorVal) {
|
3382 | const schema = schematype.schema;
|
3383 | if (schema == null) {
|
3384 | return;
|
3385 | }
|
3386 |
|
3387 | for (const key of Object.keys(schema.paths)) {
|
3388 | const path = schema.paths[key];
|
3389 | if (path.$immutableSetter == null) {
|
3390 | continue;
|
3391 | }
|
3392 | const oldVal = priorVal == null ? void 0 : priorVal.$__getValue(key);
|
3393 |
|
3394 |
|
3395 |
|
3396 | path.$immutableSetter.call(subdoc, oldVal);
|
3397 | }
|
3398 | }
|
3399 |
|
3400 |
|
3401 |
|
3402 |
|
3403 |
|
3404 |
|
3405 |
|
3406 |
|
3407 |
|
3408 |
|
3409 |
|
3410 |
|
3411 |
|
3412 |
|
3413 |
|
3414 |
|
3415 |
|
3416 |
|
3417 |
|
3418 |
|
3419 |
|
3420 |
|
3421 |
|
3422 |
|
3423 |
|
3424 |
|
3425 |
|
3426 |
|
3427 |
|
3428 |
|
3429 |
|
3430 |
|
3431 |
|
3432 |
|
3433 |
|
3434 |
|
3435 |
|
3436 |
|
3437 |
|
3438 |
|
3439 |
|
3440 |
|
3441 |
|
3442 |
|
3443 |
|
3444 |
|
3445 |
|
3446 |
|
3447 | Document.prototype.$isValid = function(path) {
|
3448 | if (this.$__.validationError == null || Object.keys(this.$__.validationError.errors).length === 0) {
|
3449 | return true;
|
3450 | }
|
3451 | if (path == null) {
|
3452 | return false;
|
3453 | }
|
3454 |
|
3455 | if (path.indexOf(' ') !== -1) {
|
3456 | path = path.split(' ');
|
3457 | }
|
3458 | if (Array.isArray(path)) {
|
3459 | return path.some(p => this.$__.validationError.errors[p] == null);
|
3460 | }
|
3461 |
|
3462 | return this.$__.validationError.errors[path] == null;
|
3463 | };
|
3464 |
|
3465 |
|
3466 |
|
3467 |
|
3468 |
|
3469 |
|
3470 |
|
3471 |
|
3472 |
|
3473 |
|
3474 |
|
3475 | Document.prototype.$__reset = function reset() {
|
3476 | let _this = this;
|
3477 |
|
3478 |
|
3479 | const subdocs = !this.$isSubdocument ? this.$getAllSubdocs() : null;
|
3480 | if (subdocs && subdocs.length > 0) {
|
3481 | const resetArrays = new Set();
|
3482 | for (const subdoc of subdocs) {
|
3483 | const fullPathWithIndexes = subdoc.$__fullPathWithIndexes();
|
3484 | subdoc.$__reset();
|
3485 | if (this.isModified(fullPathWithIndexes) || isParentInit(fullPathWithIndexes)) {
|
3486 | if (subdoc.$isDocumentArrayElement) {
|
3487 | resetArrays.add(subdoc.parentArray());
|
3488 | } else {
|
3489 | const parent = subdoc.$parent();
|
3490 | if (parent === this) {
|
3491 | this.$__.activePaths.clearPath(subdoc.$basePath);
|
3492 | } else if (parent != null && parent.$isSubdocument) {
|
3493 |
|
3494 |
|
3495 | parent.$__reset();
|
3496 | }
|
3497 | }
|
3498 | }
|
3499 | }
|
3500 |
|
3501 | for (const array of resetArrays) {
|
3502 | this.$__.activePaths.clearPath(array.$path());
|
3503 | array[arrayAtomicsBackupSymbol] = array[arrayAtomicsSymbol];
|
3504 | array[arrayAtomicsSymbol] = {};
|
3505 | }
|
3506 | }
|
3507 |
|
3508 | function isParentInit(path) {
|
3509 | path = path.indexOf('.') === -1 ? [path] : path.split('.');
|
3510 | let cur = '';
|
3511 | for (let i = 0; i < path.length; ++i) {
|
3512 | cur += (cur.length ? '.' : '') + path[i];
|
3513 | if (_this.$__.activePaths[cur] === 'init') {
|
3514 | return true;
|
3515 | }
|
3516 | }
|
3517 |
|
3518 | return false;
|
3519 | }
|
3520 |
|
3521 |
|
3522 | this.$__dirty().forEach(function(dirt) {
|
3523 | const type = dirt.value;
|
3524 |
|
3525 | if (type && type[arrayAtomicsSymbol]) {
|
3526 | type[arrayAtomicsBackupSymbol] = type[arrayAtomicsSymbol];
|
3527 | type[arrayAtomicsSymbol] = {};
|
3528 | }
|
3529 | });
|
3530 |
|
3531 | this.$__.backup = {};
|
3532 | this.$__.backup.activePaths = {
|
3533 | modify: Object.assign({}, this.$__.activePaths.getStatePaths('modify')),
|
3534 | default: Object.assign({}, this.$__.activePaths.getStatePaths('default'))
|
3535 | };
|
3536 | this.$__.backup.validationError = this.$__.validationError;
|
3537 | this.$__.backup.errors = this.$errors;
|
3538 |
|
3539 |
|
3540 | this.$__.activePaths.clear('modify');
|
3541 | this.$__.activePaths.clear('default');
|
3542 | this.$__.validationError = undefined;
|
3543 | this.$errors = undefined;
|
3544 | _this = this;
|
3545 | this.$__schema.requiredPaths().forEach(function(path) {
|
3546 | _this.$__.activePaths.require(path);
|
3547 | });
|
3548 |
|
3549 | return this;
|
3550 | };
|
3551 |
|
3552 |
|
3553 |
|
3554 |
|
3555 |
|
3556 | Document.prototype.$__undoReset = function $__undoReset() {
|
3557 | if (this.$__.backup == null || this.$__.backup.activePaths == null) {
|
3558 | return;
|
3559 | }
|
3560 |
|
3561 | this.$__.activePaths.states.modify = this.$__.backup.activePaths.modify;
|
3562 | this.$__.activePaths.states.default = this.$__.backup.activePaths.default;
|
3563 |
|
3564 | this.$__.validationError = this.$__.backup.validationError;
|
3565 | this.$errors = this.$__.backup.errors;
|
3566 |
|
3567 | for (const dirt of this.$__dirty()) {
|
3568 | const type = dirt.value;
|
3569 |
|
3570 | if (type && type[arrayAtomicsSymbol] && type[arrayAtomicsBackupSymbol]) {
|
3571 | type[arrayAtomicsSymbol] = type[arrayAtomicsBackupSymbol];
|
3572 | }
|
3573 | }
|
3574 |
|
3575 | for (const subdoc of this.$getAllSubdocs()) {
|
3576 | subdoc.$__undoReset();
|
3577 | }
|
3578 | };
|
3579 |
|
3580 |
|
3581 |
|
3582 |
|
3583 |
|
3584 |
|
3585 |
|
3586 |
|
3587 |
|
3588 |
|
3589 |
|
3590 | Document.prototype.$__dirty = function() {
|
3591 | const _this = this;
|
3592 | let all = this.$__.activePaths.map('modify', function(path) {
|
3593 | return {
|
3594 | path: path,
|
3595 | value: _this.$__getValue(path),
|
3596 | schema: _this.$__path(path)
|
3597 | };
|
3598 | });
|
3599 |
|
3600 |
|
3601 |
|
3602 | all = all.concat(this.$__.activePaths.map('default', function(path) {
|
3603 | if (path === '_id' || _this.$__getValue(path) == null) {
|
3604 | return;
|
3605 | }
|
3606 | return {
|
3607 | path: path,
|
3608 | value: _this.$__getValue(path),
|
3609 | schema: _this.$__path(path)
|
3610 | };
|
3611 | }));
|
3612 |
|
3613 | const allPaths = new Map(all.filter((el) => el != null).map((el) => [el.path, el.value]));
|
3614 |
|
3615 | const minimal = [];
|
3616 |
|
3617 | all.forEach(function(item) {
|
3618 | if (!item) {
|
3619 | return;
|
3620 | }
|
3621 |
|
3622 | let top = null;
|
3623 |
|
3624 | const array = parentPaths(item.path);
|
3625 | for (let i = 0; i < array.length - 1; i++) {
|
3626 | if (allPaths.has(array[i])) {
|
3627 | top = allPaths.get(array[i]);
|
3628 | break;
|
3629 | }
|
3630 | }
|
3631 | if (top == null) {
|
3632 | minimal.push(item);
|
3633 | } else if (top != null &&
|
3634 | top[arrayAtomicsSymbol] != null &&
|
3635 | top.hasAtomics()) {
|
3636 |
|
3637 |
|
3638 |
|
3639 |
|
3640 | top[arrayAtomicsSymbol] = {};
|
3641 | top[arrayAtomicsSymbol].$set = top;
|
3642 | }
|
3643 | });
|
3644 | return minimal;
|
3645 | };
|
3646 |
|
3647 | /**
|
3648 | * Assigns/compiles `schema` into this documents prototype.
|
3649 | *
|
3650 | * @param {Schema} schema
|
3651 | * @api private
|
3652 | * @method $__setSchema
|
3653 | * @memberOf Document
|
3654 | * @instance
|
3655 | */
|
3656 |
|
3657 | Document.prototype.$__setSchema = function(schema) {
|
3658 | compile(schema.tree, this, undefined, schema.options);
|
3659 |
|
3660 |
|
3661 | for (const key of Object.keys(schema.virtuals)) {
|
3662 | schema.virtuals[key]._applyDefaultGetters();
|
3663 | }
|
3664 | if (schema.path('schema') == null) {
|
3665 | this.schema = schema;
|
3666 | }
|
3667 | this.$__schema = schema;
|
3668 | this[documentSchemaSymbol] = schema;
|
3669 | };
|
3670 |
|
3671 |
|
3672 |
|
3673 |
|
3674 |
|
3675 |
|
3676 |
|
3677 |
|
3678 |
|
3679 |
|
3680 |
|
3681 |
|
3682 | Document.prototype.$__getArrayPathsToValidate = function() {
|
3683 | DocumentArray || (DocumentArray = require('./types/documentArray'));
|
3684 |
|
3685 |
|
3686 | return this.$__.activePaths
|
3687 | .map('init', 'modify', function(i) {
|
3688 | return this.$__getValue(i);
|
3689 | }.bind(this))
|
3690 | .filter(function(val) {
|
3691 | return val && Array.isArray(val) && utils.isMongooseDocumentArray(val) && val.length;
|
3692 | }).reduce(function(seed, array) {
|
3693 | return seed.concat(array);
|
3694 | }, [])
|
3695 | .filter(function(doc) {
|
3696 | return doc;
|
3697 | });
|
3698 | };
|
3699 |
|
3700 |
|
3701 |
|
3702 |
|
3703 |
|
3704 |
|
3705 |
|
3706 |
|
3707 |
|
3708 |
|
3709 |
|
3710 |
|
3711 | Document.prototype.$getAllSubdocs = function() {
|
3712 | DocumentArray || (DocumentArray = require('./types/documentArray'));
|
3713 | Embedded = Embedded || require('./types/arraySubdocument');
|
3714 |
|
3715 | function docReducer(doc, seed, path) {
|
3716 | let val = doc;
|
3717 | let isNested = false;
|
3718 | if (path) {
|
3719 | if (doc instanceof Document && doc[documentSchemaSymbol].paths[path]) {
|
3720 | val = doc._doc[path];
|
3721 | } else if (doc instanceof Document && doc[documentSchemaSymbol].nested[path]) {
|
3722 | val = doc._doc[path];
|
3723 | isNested = true;
|
3724 | } else {
|
3725 | val = doc[path];
|
3726 | }
|
3727 | }
|
3728 | if (val instanceof Embedded) {
|
3729 | seed.push(val);
|
3730 | } else if (val instanceof Map) {
|
3731 | seed = Array.from(val.keys()).reduce(function(seed, path) {
|
3732 | return docReducer(val.get(path), seed, null);
|
3733 | }, seed);
|
3734 | } else if (val && !Array.isArray(val) && val.$isSingleNested) {
|
3735 | seed = Object.keys(val._doc).reduce(function(seed, path) {
|
3736 | return docReducer(val, seed, path);
|
3737 | }, seed);
|
3738 | seed.push(val);
|
3739 | } else if (val && utils.isMongooseDocumentArray(val)) {
|
3740 | val.forEach(function _docReduce(doc) {
|
3741 | if (!doc || !doc._doc) {
|
3742 | return;
|
3743 | }
|
3744 | seed = Object.keys(doc._doc).reduce(function(seed, path) {
|
3745 | return docReducer(doc._doc, seed, path);
|
3746 | }, seed);
|
3747 | if (doc instanceof Embedded) {
|
3748 | seed.push(doc);
|
3749 | }
|
3750 | });
|
3751 | } else if (isNested && val != null) {
|
3752 | for (const path of Object.keys(val)) {
|
3753 | docReducer(val, seed, path);
|
3754 | }
|
3755 | }
|
3756 | return seed;
|
3757 | }
|
3758 |
|
3759 | const subDocs = [];
|
3760 | for (const path of Object.keys(this._doc)) {
|
3761 | docReducer(this, subDocs, path);
|
3762 | }
|
3763 |
|
3764 | return subDocs;
|
3765 | };
|
3766 |
|
3767 |
|
3768 |
|
3769 |
|
3770 |
|
3771 | function applyQueue(doc) {
|
3772 | const q = doc.$__schema && doc.$__schema.callQueue;
|
3773 | if (!q.length) {
|
3774 | return;
|
3775 | }
|
3776 |
|
3777 | for (const pair of q) {
|
3778 | if (pair[0] !== 'pre' && pair[0] !== 'post' && pair[0] !== 'on') {
|
3779 | doc[pair[0]].apply(doc, pair[1]);
|
3780 | }
|
3781 | }
|
3782 | }
|
3783 |
|
3784 |
|
3785 |
|
3786 |
|
3787 |
|
3788 | Document.prototype.$__handleReject = function handleReject(err) {
|
3789 |
|
3790 | if (this.$listeners('error').length) {
|
3791 | this.$emit('error', err);
|
3792 | } else if (this.constructor.listeners && this.constructor.listeners('error').length) {
|
3793 | this.constructor.emit('error', err);
|
3794 | }
|
3795 | };
|
3796 |
|
3797 |
|
3798 |
|
3799 |
|
3800 |
|
3801 |
|
3802 |
|
3803 |
|
3804 |
|
3805 |
|
3806 |
|
3807 | Document.prototype.$toObject = function(options, json) {
|
3808 | const defaultOptions = this.$__schema._defaultToObjectOptions(json);
|
3809 |
|
3810 | const hasOnlyPrimitiveValues = this.$__hasOnlyPrimitiveValues();
|
3811 |
|
3812 |
|
3813 | options = utils.isPOJO(options) ? { ...options } : {};
|
3814 | options._calledWithOptions = options._calledWithOptions || { ...options };
|
3815 |
|
3816 | let _minimize;
|
3817 | if (options._calledWithOptions.minimize != null) {
|
3818 | _minimize = options.minimize;
|
3819 | } else if (defaultOptions != null && defaultOptions.minimize != null) {
|
3820 | _minimize = defaultOptions.minimize;
|
3821 | } else {
|
3822 | _minimize = this.$__schema.options.minimize;
|
3823 | }
|
3824 |
|
3825 | options.minimize = _minimize;
|
3826 | if (!hasOnlyPrimitiveValues) {
|
3827 | options._seen = options._seen || new Map();
|
3828 | }
|
3829 |
|
3830 | const depopulate = options._calledWithOptions.depopulate
|
3831 | ?? defaultOptions?.depopulate
|
3832 | ?? options.depopulate
|
3833 | ?? false;
|
3834 |
|
3835 |
|
3836 | if (depopulate && options._isNested && this.$__.wasPopulated) {
|
3837 | return clone(this.$__.wasPopulated.value || this._doc._id, options);
|
3838 | }
|
3839 | if (depopulate) {
|
3840 | options.depopulate = true;
|
3841 | }
|
3842 |
|
3843 |
|
3844 | if (defaultOptions != null) {
|
3845 | for (const key of Object.keys(defaultOptions)) {
|
3846 | if (options[key] == null) {
|
3847 | options[key] = defaultOptions[key];
|
3848 | }
|
3849 | }
|
3850 | }
|
3851 | options._isNested = true;
|
3852 | options.json = json;
|
3853 | options.minimize = _minimize;
|
3854 |
|
3855 | const parentOptions = options._parentOptions;
|
3856 |
|
3857 | options._parentOptions = this.$isSubdocument ? options : null;
|
3858 |
|
3859 | options._skipSingleNestedGetters = false;
|
3860 |
|
3861 |
|
3862 |
|
3863 |
|
3864 | let ret;
|
3865 | if (hasOnlyPrimitiveValues && !options.flattenObjectIds) {
|
3866 |
|
3867 |
|
3868 | ret = this.$__toObjectShallow();
|
3869 | } else {
|
3870 | ret = clone(this._doc, options) || {};
|
3871 | }
|
3872 |
|
3873 | options._skipSingleNestedGetters = true;
|
3874 | const getters = options._calledWithOptions.getters
|
3875 | ?? options.getters
|
3876 | ?? defaultOptions.getters
|
3877 | ?? false;
|
3878 | if (getters) {
|
3879 | applyGetters(this, ret, options);
|
3880 |
|
3881 | if (options.minimize) {
|
3882 | ret = minimize(ret) || {};
|
3883 | }
|
3884 | }
|
3885 |
|
3886 | const virtuals = options._calledWithOptions.virtuals
|
3887 | ?? defaultOptions.virtuals
|
3888 | ?? parentOptions?.virtuals
|
3889 | ?? undefined;
|
3890 |
|
3891 | if (virtuals || (getters && virtuals !== false)) {
|
3892 | applyVirtuals(this, ret, options, options);
|
3893 | }
|
3894 |
|
3895 | if (options.versionKey === false && this.$__schema.options.versionKey) {
|
3896 | delete ret[this.$__schema.options.versionKey];
|
3897 | }
|
3898 |
|
3899 | const transform = options._calledWithOptions.transform ?? true;
|
3900 | let transformFunction = undefined;
|
3901 | if (transform === true) {
|
3902 | transformFunction = defaultOptions.transform;
|
3903 | } else if (typeof transform === 'function') {
|
3904 | transformFunction = transform;
|
3905 | }
|
3906 |
|
3907 |
|
3908 |
|
3909 |
|
3910 |
|
3911 |
|
3912 | if (transform) {
|
3913 | applySchemaTypeTransforms(this, ret);
|
3914 | }
|
3915 |
|
3916 | if (options.useProjection) {
|
3917 | omitDeselectedFields(this, ret);
|
3918 | }
|
3919 |
|
3920 | if (typeof transformFunction === 'function') {
|
3921 | const xformed = transformFunction(this, ret, options);
|
3922 | if (typeof xformed !== 'undefined') {
|
3923 | ret = xformed;
|
3924 | }
|
3925 | }
|
3926 |
|
3927 | return ret;
|
3928 | };
|
3929 |
|
3930 |
|
3931 |
|
3932 |
|
3933 |
|
3934 | Document.prototype.$__toObjectShallow = function $__toObjectShallow() {
|
3935 | const ret = {};
|
3936 | if (this._doc != null) {
|
3937 | for (const key of Object.keys(this._doc)) {
|
3938 | const value = this._doc[key];
|
3939 | if (value instanceof Date) {
|
3940 | ret[key] = new Date(value);
|
3941 | } else if (value !== undefined) {
|
3942 | ret[key] = value;
|
3943 | }
|
3944 | }
|
3945 | }
|
3946 |
|
3947 | return ret;
|
3948 | };
|
3949 |
|
3950 |
|
3951 |
|
3952 |
|
3953 |
|
3954 |
|
3955 |
|
3956 |
|
3957 |
|
3958 |
|
3959 |
|
3960 |
|
3961 |
|
3962 |
|
3963 |
|
3964 |
|
3965 |
|
3966 |
|
3967 |
|
3968 |
|
3969 |
|
3970 |
|
3971 |
|
3972 |
|
3973 |
|
3974 |
|
3975 |
|
3976 |
|
3977 |
|
3978 |
|
3979 |
|
3980 |
|
3981 |
|
3982 |
|
3983 |
|
3984 |
|
3985 |
|
3986 |
|
3987 |
|
3988 |
|
3989 |
|
3990 |
|
3991 |
|
3992 |
|
3993 |
|
3994 |
|
3995 |
|
3996 |
|
3997 |
|
3998 |
|
3999 |
|
4000 |
|
4001 |
|
4002 |
|
4003 |
|
4004 |
|
4005 |
|
4006 |
|
4007 |
|
4008 |
|
4009 |
|
4010 |
|
4011 |
|
4012 |
|
4013 |
|
4014 |
|
4015 |
|
4016 |
|
4017 |
|
4018 |
|
4019 |
|
4020 |
|
4021 |
|
4022 |
|
4023 |
|
4024 |
|
4025 |
|
4026 |
|
4027 |
|
4028 |
|
4029 |
|
4030 |
|
4031 |
|
4032 |
|
4033 |
|
4034 |
|
4035 |
|
4036 |
|
4037 |
|
4038 |
|
4039 |
|
4040 |
|
4041 |
|
4042 |
|
4043 |
|
4044 |
|
4045 |
|
4046 |
|
4047 |
|
4048 |
|
4049 |
|
4050 |
|
4051 |
|
4052 |
|
4053 |
|
4054 |
|
4055 |
|
4056 |
|
4057 |
|
4058 |
|
4059 |
|
4060 |
|
4061 |
|
4062 |
|
4063 |
|
4064 |
|
4065 |
|
4066 |
|
4067 |
|
4068 |
|
4069 |
|
4070 |
|
4071 |
|
4072 |
|
4073 |
|
4074 |
|
4075 |
|
4076 |
|
4077 |
|
4078 |
|
4079 |
|
4080 |
|
4081 |
|
4082 |
|
4083 |
|
4084 |
|
4085 |
|
4086 |
|
4087 |
|
4088 |
|
4089 |
|
4090 |
|
4091 |
|
4092 |
|
4093 |
|
4094 |
|
4095 |
|
4096 |
|
4097 | Document.prototype.toObject = function(options) {
|
4098 | return this.$toObject(options);
|
4099 | };
|
4100 |
|
4101 |
|
4102 |
|
4103 |
|
4104 |
|
4105 | function applyVirtuals(self, json, options, toObjectOptions) {
|
4106 | const schema = self.$__schema;
|
4107 | const virtuals = schema.virtuals;
|
4108 | const paths = Object.keys(virtuals);
|
4109 | let i = paths.length;
|
4110 | const numPaths = i;
|
4111 | let path;
|
4112 | let assignPath;
|
4113 | let cur = self._doc;
|
4114 | let v;
|
4115 | const aliases = typeof (toObjectOptions && toObjectOptions.aliases) === 'boolean'
|
4116 | ? toObjectOptions.aliases
|
4117 | : true;
|
4118 |
|
4119 | options = options || {};
|
4120 | let virtualsToApply = null;
|
4121 | if (Array.isArray(options.virtuals)) {
|
4122 | virtualsToApply = new Set(options.virtuals);
|
4123 | } else if (options.virtuals && options.virtuals.pathsToSkip) {
|
4124 | virtualsToApply = new Set(paths);
|
4125 | for (let i = 0; i < options.virtuals.pathsToSkip.length; i++) {
|
4126 | if (virtualsToApply.has(options.virtuals.pathsToSkip[i])) {
|
4127 | virtualsToApply.delete(options.virtuals.pathsToSkip[i]);
|
4128 | }
|
4129 | }
|
4130 | }
|
4131 |
|
4132 | if (!cur) {
|
4133 | return json;
|
4134 | }
|
4135 |
|
4136 | for (i = 0; i < numPaths; ++i) {
|
4137 | path = paths[i];
|
4138 |
|
4139 | if (virtualsToApply != null && !virtualsToApply.has(path)) {
|
4140 | continue;
|
4141 | }
|
4142 |
|
4143 |
|
4144 | if (!aliases && schema.aliases.hasOwnProperty(path)) {
|
4145 | continue;
|
4146 | }
|
4147 |
|
4148 |
|
4149 |
|
4150 |
|
4151 | assignPath = path;
|
4152 | if (options.path != null) {
|
4153 | if (!path.startsWith(options.path + '.')) {
|
4154 | continue;
|
4155 | }
|
4156 | assignPath = path.substring(options.path.length + 1);
|
4157 | }
|
4158 | if (assignPath.indexOf('.') === -1 && assignPath === path) {
|
4159 | v = virtuals[path].applyGetters(void 0, self);
|
4160 | if (v === void 0) {
|
4161 | continue;
|
4162 | }
|
4163 | v = clone(v, options);
|
4164 | json[assignPath] = v;
|
4165 | continue;
|
4166 | }
|
4167 | const parts = assignPath.split('.');
|
4168 | v = clone(self.get(path), options);
|
4169 | if (v === void 0) {
|
4170 | continue;
|
4171 | }
|
4172 | const plen = parts.length;
|
4173 | cur = json;
|
4174 | for (let j = 0; j < plen - 1; ++j) {
|
4175 | cur[parts[j]] = cur[parts[j]] || {};
|
4176 | cur = cur[parts[j]];
|
4177 | }
|
4178 | cur[parts[plen - 1]] = v;
|
4179 | }
|
4180 |
|
4181 | return json;
|
4182 | }
|
4183 |
|
4184 |
|
4185 |
|
4186 |
|
4187 |
|
4188 |
|
4189 |
|
4190 |
|
4191 |
|
4192 |
|
4193 |
|
4194 |
|
4195 | function applyGetters(self, json, options) {
|
4196 | const schema = self.$__schema;
|
4197 | const paths = Object.keys(schema.paths);
|
4198 | let i = paths.length;
|
4199 | let path;
|
4200 | let cur = self._doc;
|
4201 | let v;
|
4202 |
|
4203 | if (!cur) {
|
4204 | return json;
|
4205 | }
|
4206 |
|
4207 | while (i--) {
|
4208 | path = paths[i];
|
4209 |
|
4210 | const parts = path.split('.');
|
4211 |
|
4212 | const plen = parts.length;
|
4213 | const last = plen - 1;
|
4214 | let branch = json;
|
4215 | let part;
|
4216 | cur = self._doc;
|
4217 |
|
4218 | if (!self.$__isSelected(path)) {
|
4219 | continue;
|
4220 | }
|
4221 |
|
4222 | for (let ii = 0; ii < plen; ++ii) {
|
4223 | part = parts[ii];
|
4224 | v = cur[part];
|
4225 |
|
4226 |
|
4227 |
|
4228 | if (branch != null && typeof branch !== 'object') {
|
4229 | break;
|
4230 | } else if (ii === last) {
|
4231 | const val = self.$get(path);
|
4232 | branch[part] = clone(val, options);
|
4233 | if (Array.isArray(branch[part]) && schema.paths[path].$embeddedSchemaType) {
|
4234 | for (let i = 0; i < branch[part].length; ++i) {
|
4235 | branch[part][i] = schema.paths[path].$embeddedSchemaType.applyGetters(
|
4236 | branch[part][i],
|
4237 | self
|
4238 | );
|
4239 | }
|
4240 | }
|
4241 | } else if (v == null) {
|
4242 | if (part in cur) {
|
4243 | branch[part] = v;
|
4244 | }
|
4245 | break;
|
4246 | } else {
|
4247 | branch = branch[part] || (branch[part] = {});
|
4248 | }
|
4249 | cur = v;
|
4250 | }
|
4251 | }
|
4252 |
|
4253 | return json;
|
4254 | }
|
4255 |
|
4256 |
|
4257 |
|
4258 |
|
4259 |
|
4260 |
|
4261 |
|
4262 |
|
4263 |
|
4264 |
|
4265 | function applySchemaTypeTransforms(self, json) {
|
4266 | const schema = self.$__schema;
|
4267 | const paths = Object.keys(schema.paths || {});
|
4268 | const cur = self._doc;
|
4269 |
|
4270 | if (!cur) {
|
4271 | return json;
|
4272 | }
|
4273 |
|
4274 | for (const path of paths) {
|
4275 | const schematype = schema.paths[path];
|
4276 | if (typeof schematype.options.transform === 'function') {
|
4277 | const val = self.$get(path);
|
4278 | if (val === undefined) {
|
4279 | continue;
|
4280 | }
|
4281 | const transformedValue = schematype.options.transform.call(self, val);
|
4282 | throwErrorIfPromise(path, transformedValue);
|
4283 | utils.setValue(path, transformedValue, json);
|
4284 | } else if (schematype.$embeddedSchemaType != null &&
|
4285 | typeof schematype.$embeddedSchemaType.options.transform === 'function') {
|
4286 | const val = self.$get(path);
|
4287 | if (val === undefined) {
|
4288 | continue;
|
4289 | }
|
4290 | const vals = [].concat(val);
|
4291 | const transform = schematype.$embeddedSchemaType.options.transform;
|
4292 | for (let i = 0; i < vals.length; ++i) {
|
4293 | const transformedValue = transform.call(self, vals[i]);
|
4294 | vals[i] = transformedValue;
|
4295 | throwErrorIfPromise(path, transformedValue);
|
4296 | }
|
4297 |
|
4298 | json[path] = vals;
|
4299 | }
|
4300 | }
|
4301 |
|
4302 | return json;
|
4303 | }
|
4304 |
|
4305 | function throwErrorIfPromise(path, transformedValue) {
|
4306 | if (isPromise(transformedValue)) {
|
4307 | throw new Error('`transform` function must be synchronous, but the transform on path `' + path + '` returned a promise.');
|
4308 | }
|
4309 | }
|
4310 |
|
4311 |
|
4312 |
|
4313 |
|
4314 |
|
4315 | function omitDeselectedFields(self, json) {
|
4316 | const schema = self.$__schema;
|
4317 | const paths = Object.keys(schema.paths || {});
|
4318 | const cur = self._doc;
|
4319 |
|
4320 | if (!cur) {
|
4321 | return json;
|
4322 | }
|
4323 |
|
4324 | let selected = self.$__.selected;
|
4325 | if (selected === void 0) {
|
4326 | selected = {};
|
4327 | queryhelpers.applyPaths(selected, schema);
|
4328 | }
|
4329 | if (selected == null || Object.keys(selected).length === 0) {
|
4330 | return json;
|
4331 | }
|
4332 |
|
4333 | for (const path of paths) {
|
4334 | if (selected[path] != null && !selected[path]) {
|
4335 | delete json[path];
|
4336 | }
|
4337 | }
|
4338 |
|
4339 | return json;
|
4340 | }
|
4341 |
|
4342 |
|
4343 |
|
4344 |
|
4345 |
|
4346 |
|
4347 |
|
4348 |
|
4349 |
|
4350 |
|
4351 |
|
4352 |
|
4353 |
|
4354 |
|
4355 |
|
4356 |
|
4357 |
|
4358 |
|
4359 |
|
4360 |
|
4361 |
|
4362 |
|
4363 |
|
4364 |
|
4365 |
|
4366 | Document.prototype.toJSON = function(options) {
|
4367 | return this.$toObject(options, true);
|
4368 | };
|
4369 |
|
4370 |
|
4371 |
|
4372 |
|
4373 |
|
4374 | Document.prototype.ownerDocument = function() {
|
4375 | return this;
|
4376 | };
|
4377 |
|
4378 |
|
4379 |
|
4380 |
|
4381 |
|
4382 |
|
4383 |
|
4384 |
|
4385 |
|
4386 |
|
4387 |
|
4388 |
|
4389 |
|
4390 | Document.prototype.parent = function() {
|
4391 | if (this.$isSubdocument || this.$__.wasPopulated) {
|
4392 | return this.$__.parent;
|
4393 | }
|
4394 | return this;
|
4395 | };
|
4396 |
|
4397 |
|
4398 |
|
4399 |
|
4400 |
|
4401 |
|
4402 |
|
4403 |
|
4404 |
|
4405 |
|
4406 |
|
4407 |
|
4408 | Document.prototype.$parent = Document.prototype.parent;
|
4409 |
|
4410 |
|
4411 |
|
4412 |
|
4413 |
|
4414 |
|
4415 |
|
4416 |
|
4417 |
|
4418 |
|
4419 |
|
4420 | Document.prototype.inspect = function(options) {
|
4421 | const isPOJO = utils.isPOJO(options);
|
4422 | let opts;
|
4423 | if (isPOJO) {
|
4424 | opts = options;
|
4425 | opts.minimize = false;
|
4426 | }
|
4427 |
|
4428 | const ret = arguments.length > 0 ? this.toObject(opts) : this.toObject();
|
4429 |
|
4430 | if (ret == null) {
|
4431 |
|
4432 |
|
4433 | return 'MongooseDocument { ' + ret + ' }';
|
4434 | }
|
4435 |
|
4436 | return ret;
|
4437 | };
|
4438 |
|
4439 | if (inspect.custom) {
|
4440 |
|
4441 | Document.prototype[inspect.custom] = Document.prototype.inspect;
|
4442 | }
|
4443 |
|
4444 |
|
4445 |
|
4446 |
|
4447 |
|
4448 |
|
4449 |
|
4450 |
|
4451 |
|
4452 |
|
4453 |
|
4454 | Document.prototype.toString = function() {
|
4455 | const ret = this.inspect();
|
4456 | if (typeof ret === 'string') {
|
4457 | return ret;
|
4458 | }
|
4459 | return inspect(ret);
|
4460 | };
|
4461 |
|
4462 |
|
4463 |
|
4464 |
|
4465 |
|
4466 |
|
4467 |
|
4468 |
|
4469 |
|
4470 |
|
4471 |
|
4472 |
|
4473 |
|
4474 |
|
4475 |
|
4476 | Document.prototype.equals = function(doc) {
|
4477 | if (!doc) {
|
4478 | return false;
|
4479 | }
|
4480 |
|
4481 | const tid = this.$__getValue('_id');
|
4482 | const docid = doc.$__ != null ? doc.$__getValue('_id') : doc;
|
4483 | if (!tid && !docid) {
|
4484 | return deepEqual(this, doc);
|
4485 | }
|
4486 | return tid && tid.equals
|
4487 | ? tid.equals(docid)
|
4488 | : tid === docid;
|
4489 | };
|
4490 |
|
4491 |
|
4492 |
|
4493 |
|
4494 |
|
4495 |
|
4496 |
|
4497 |
|
4498 |
|
4499 |
|
4500 |
|
4501 |
|
4502 |
|
4503 |
|
4504 |
|
4505 |
|
4506 |
|
4507 |
|
4508 |
|
4509 |
|
4510 |
|
4511 |
|
4512 |
|
4513 |
|
4514 |
|
4515 |
|
4516 |
|
4517 |
|
4518 |
|
4519 |
|
4520 |
|
4521 |
|
4522 |
|
4523 |
|
4524 |
|
4525 |
|
4526 |
|
4527 |
|
4528 |
|
4529 |
|
4530 |
|
4531 |
|
4532 |
|
4533 |
|
4534 |
|
4535 |
|
4536 |
|
4537 |
|
4538 | Document.prototype.populate = async function populate() {
|
4539 | const pop = {};
|
4540 | const args = [...arguments];
|
4541 | if (typeof args[args.length - 1] === 'function') {
|
4542 | throw new MongooseError('Document.prototype.populate() no longer accepts a callback');
|
4543 | }
|
4544 |
|
4545 | if (args.length !== 0) {
|
4546 |
|
4547 | const res = utils.populate.apply(null, args);
|
4548 | for (const populateOptions of res) {
|
4549 | pop[populateOptions.path] = populateOptions;
|
4550 | }
|
4551 | }
|
4552 |
|
4553 | const paths = utils.object.vals(pop);
|
4554 | let topLevelModel = this.constructor;
|
4555 | if (this.$__isNested) {
|
4556 | topLevelModel = this.$__[scopeSymbol].constructor;
|
4557 | const nestedPath = this.$__.nestedPath;
|
4558 | paths.forEach(function(populateOptions) {
|
4559 | populateOptions.path = nestedPath + '.' + populateOptions.path;
|
4560 | });
|
4561 | }
|
4562 |
|
4563 |
|
4564 |
|
4565 | if (this.$session() != null) {
|
4566 | const session = this.$session();
|
4567 | paths.forEach(path => {
|
4568 | if (path.options == null) {
|
4569 | path.options = { session: session };
|
4570 | return;
|
4571 | }
|
4572 | if (!('session' in path.options)) {
|
4573 | path.options.session = session;
|
4574 | }
|
4575 | });
|
4576 | }
|
4577 |
|
4578 | paths.forEach(p => {
|
4579 | p._localModel = topLevelModel;
|
4580 | });
|
4581 |
|
4582 | return topLevelModel.populate(this, paths);
|
4583 | };
|
4584 |
|
4585 |
|
4586 |
|
4587 |
|
4588 |
|
4589 |
|
4590 |
|
4591 |
|
4592 |
|
4593 |
|
4594 |
|
4595 | Document.prototype.$getPopulatedDocs = function $getPopulatedDocs() {
|
4596 | let keys = [];
|
4597 | if (this.$__.populated != null) {
|
4598 | keys = keys.concat(Object.keys(this.$__.populated));
|
4599 | }
|
4600 | let result = [];
|
4601 | for (const key of keys) {
|
4602 | const value = this.$get(key);
|
4603 | if (Array.isArray(value)) {
|
4604 | result = result.concat(value);
|
4605 | } else if (value instanceof Document) {
|
4606 | result.push(value);
|
4607 | }
|
4608 | }
|
4609 | return result;
|
4610 | };
|
4611 |
|
4612 |
|
4613 |
|
4614 |
|
4615 |
|
4616 |
|
4617 |
|
4618 |
|
4619 |
|
4620 |
|
4621 |
|
4622 |
|
4623 |
|
4624 |
|
4625 |
|
4626 |
|
4627 |
|
4628 |
|
4629 |
|
4630 |
|
4631 |
|
4632 |
|
4633 | Document.prototype.populated = function(path, val, options) {
|
4634 |
|
4635 | if (val == null || val === true) {
|
4636 | if (!this.$__.populated) {
|
4637 | return undefined;
|
4638 | }
|
4639 | if (typeof path !== 'string') {
|
4640 | return undefined;
|
4641 | }
|
4642 |
|
4643 |
|
4644 | const _path = path.endsWith('.$*') ? path.replace(/\.\$\*$/, '') : path;
|
4645 |
|
4646 | const v = this.$__.populated[_path];
|
4647 | if (v) {
|
4648 | return val === true ? v : v.value;
|
4649 | }
|
4650 | return undefined;
|
4651 | }
|
4652 |
|
4653 | this.$__.populated || (this.$__.populated = {});
|
4654 | this.$__.populated[path] = { value: val, options: options };
|
4655 |
|
4656 |
|
4657 |
|
4658 | const pieces = path.split('.');
|
4659 | for (let i = 0; i < pieces.length - 1; ++i) {
|
4660 | const subpath = pieces.slice(0, i + 1).join('.');
|
4661 | const subdoc = this.$get(subpath);
|
4662 | if (subdoc != null && subdoc.$__ != null && this.$populated(subpath)) {
|
4663 | const rest = pieces.slice(i + 1).join('.');
|
4664 | subdoc.$populated(rest, val, options);
|
4665 |
|
4666 |
|
4667 | break;
|
4668 | }
|
4669 | }
|
4670 |
|
4671 | return val;
|
4672 | };
|
4673 |
|
4674 |
|
4675 |
|
4676 |
|
4677 |
|
4678 |
|
4679 |
|
4680 |
|
4681 |
|
4682 | Document.prototype.$populated = Document.prototype.populated;
|
4683 |
|
4684 |
|
4685 |
|
4686 |
|
4687 |
|
4688 |
|
4689 |
|
4690 |
|
4691 |
|
4692 |
|
4693 |
|
4694 |
|
4695 |
|
4696 |
|
4697 |
|
4698 |
|
4699 |
|
4700 |
|
4701 |
|
4702 |
|
4703 |
|
4704 |
|
4705 |
|
4706 |
|
4707 |
|
4708 | Document.prototype.$assertPopulated = function $assertPopulated(path, values) {
|
4709 | if (Array.isArray(path)) {
|
4710 | path.forEach(p => this.$assertPopulated(p, values));
|
4711 | return this;
|
4712 | }
|
4713 |
|
4714 | if (arguments.length > 1) {
|
4715 | this.$set(values);
|
4716 | }
|
4717 |
|
4718 | if (!this.$populated(path)) {
|
4719 | throw new MongooseError(`Expected path "${path}" to be populated`);
|
4720 | }
|
4721 |
|
4722 | return this;
|
4723 | };
|
4724 |
|
4725 |
|
4726 |
|
4727 |
|
4728 |
|
4729 |
|
4730 |
|
4731 |
|
4732 |
|
4733 |
|
4734 |
|
4735 |
|
4736 |
|
4737 |
|
4738 |
|
4739 |
|
4740 |
|
4741 |
|
4742 |
|
4743 |
|
4744 |
|
4745 |
|
4746 | Document.prototype.depopulate = function(path) {
|
4747 | if (typeof path === 'string') {
|
4748 | path = path.indexOf(' ') === -1 ? [path] : path.split(' ');
|
4749 | }
|
4750 |
|
4751 | let populatedIds;
|
4752 | const virtualKeys = this.$$populatedVirtuals ? Object.keys(this.$$populatedVirtuals) : [];
|
4753 | const populated = this.$__ && this.$__.populated || {};
|
4754 |
|
4755 | if (arguments.length === 0) {
|
4756 |
|
4757 | for (const virtualKey of virtualKeys) {
|
4758 | delete this.$$populatedVirtuals[virtualKey];
|
4759 | delete this._doc[virtualKey];
|
4760 | delete populated[virtualKey];
|
4761 | }
|
4762 |
|
4763 | const keys = Object.keys(populated);
|
4764 |
|
4765 | for (const key of keys) {
|
4766 | populatedIds = this.$populated(key);
|
4767 | if (!populatedIds) {
|
4768 | continue;
|
4769 | }
|
4770 | delete populated[key];
|
4771 | if (Array.isArray(populatedIds)) {
|
4772 | const arr = utils.getValue(key, this._doc);
|
4773 | if (arr.isMongooseArray) {
|
4774 | const rawArray = arr.__array;
|
4775 | for (let i = 0; i < rawArray.length; ++i) {
|
4776 | const subdoc = rawArray[i];
|
4777 | if (subdoc == null) {
|
4778 | continue;
|
4779 | }
|
4780 | rawArray[i] = subdoc instanceof Document ? subdoc._doc._id : subdoc._id;
|
4781 | }
|
4782 | } else {
|
4783 | utils.setValue(key, populatedIds, this._doc);
|
4784 | }
|
4785 | } else {
|
4786 | utils.setValue(key, populatedIds, this._doc);
|
4787 | }
|
4788 | }
|
4789 | return this;
|
4790 | }
|
4791 |
|
4792 | for (const singlePath of path) {
|
4793 | populatedIds = this.$populated(singlePath);
|
4794 | delete populated[singlePath];
|
4795 |
|
4796 | if (virtualKeys.indexOf(singlePath) !== -1) {
|
4797 | delete this.$$populatedVirtuals[singlePath];
|
4798 | delete this._doc[singlePath];
|
4799 | } else if (populatedIds) {
|
4800 | if (Array.isArray(populatedIds)) {
|
4801 | const arr = utils.getValue(singlePath, this._doc);
|
4802 | if (arr.isMongooseArray) {
|
4803 | const rawArray = arr.__array;
|
4804 | for (let i = 0; i < rawArray.length; ++i) {
|
4805 | const subdoc = rawArray[i];
|
4806 | if (subdoc == null) {
|
4807 | continue;
|
4808 | }
|
4809 | rawArray[i] = subdoc instanceof Document ? subdoc._doc._id : subdoc._id;
|
4810 | }
|
4811 | } else {
|
4812 | utils.setValue(singlePath, populatedIds, this._doc);
|
4813 | }
|
4814 | } else {
|
4815 | utils.setValue(singlePath, populatedIds, this._doc);
|
4816 | }
|
4817 | }
|
4818 | }
|
4819 | return this;
|
4820 | };
|
4821 |
|
4822 |
|
4823 |
|
4824 |
|
4825 |
|
4826 |
|
4827 |
|
4828 |
|
4829 |
|
4830 |
|
4831 |
|
4832 |
|
4833 |
|
4834 | Document.prototype.$__fullPath = function(path) {
|
4835 |
|
4836 | return path || '';
|
4837 | };
|
4838 |
|
4839 |
|
4840 |
|
4841 |
|
4842 |
|
4843 |
|
4844 |
|
4845 |
|
4846 |
|
4847 |
|
4848 |
|
4849 |
|
4850 |
|
4851 |
|
4852 |
|
4853 |
|
4854 |
|
4855 |
|
4856 |
|
4857 |
|
4858 |
|
4859 |
|
4860 |
|
4861 |
|
4862 |
|
4863 |
|
4864 |
|
4865 |
|
4866 |
|
4867 |
|
4868 |
|
4869 |
|
4870 |
|
4871 |
|
4872 |
|
4873 |
|
4874 |
|
4875 |
|
4876 |
|
4877 |
|
4878 |
|
4879 |
|
4880 | Document.prototype.getChanges = function() {
|
4881 | const delta = this.$__delta();
|
4882 | const changes = delta ? delta[1] : {};
|
4883 | return changes;
|
4884 | };
|
4885 |
|
4886 |
|
4887 |
|
4888 |
|
4889 |
|
4890 |
|
4891 |
|
4892 |
|
4893 |
|
4894 |
|
4895 | Document.prototype.$__delta = function $__delta() {
|
4896 | const dirty = this.$__dirty();
|
4897 | const optimisticConcurrency = this.$__schema.options.optimisticConcurrency;
|
4898 | if (optimisticConcurrency) {
|
4899 | if (Array.isArray(optimisticConcurrency)) {
|
4900 | const optCon = new Set(optimisticConcurrency);
|
4901 | const modPaths = this.modifiedPaths();
|
4902 | if (modPaths.find(path => optCon.has(path))) {
|
4903 | this.$__.version = dirty.length ? VERSION_ALL : VERSION_WHERE;
|
4904 | }
|
4905 | } else {
|
4906 | this.$__.version = dirty.length ? VERSION_ALL : VERSION_WHERE;
|
4907 | }
|
4908 | }
|
4909 |
|
4910 | if (!dirty.length && VERSION_ALL !== this.$__.version) {
|
4911 | return;
|
4912 | }
|
4913 | const where = {};
|
4914 | const delta = {};
|
4915 | const len = dirty.length;
|
4916 | const divergent = [];
|
4917 | let d = 0;
|
4918 |
|
4919 | where._id = this._doc._id;
|
4920 |
|
4921 |
|
4922 | if ((where && where._id && where._id.$__ || null) != null) {
|
4923 | where._id = where._id.toObject({ transform: false, depopulate: true });
|
4924 | }
|
4925 | for (; d < len; ++d) {
|
4926 | const data = dirty[d];
|
4927 | let value = data.value;
|
4928 | const match = checkDivergentArray(this, data.path, value);
|
4929 | if (match) {
|
4930 | divergent.push(match);
|
4931 | continue;
|
4932 | }
|
4933 |
|
4934 | const pop = this.$populated(data.path, true);
|
4935 | if (!pop && this.$__.selected) {
|
4936 |
|
4937 |
|
4938 | const pathSplit = data.path.split('.');
|
4939 | const top = pathSplit[0];
|
4940 | if (this.$__.selected[top] && this.$__.selected[top].$elemMatch) {
|
4941 |
|
4942 | if (pathSplit.length > 1 && pathSplit[1] == 0 && typeof where[top] === 'undefined') {
|
4943 | where[top] = this.$__.selected[top];
|
4944 | pathSplit[1] = '$';
|
4945 | data.path = pathSplit.join('.');
|
4946 | }
|
4947 |
|
4948 | else {
|
4949 | divergent.push(data.path);
|
4950 | continue;
|
4951 | }
|
4952 | }
|
4953 | }
|
4954 |
|
4955 |
|
4956 |
|
4957 | if (this.$isDefault(data.path) && this.$__.selected) {
|
4958 | if (data.path.indexOf('.') === -1 && isPathExcluded(this.$__.selected, data.path)) {
|
4959 | continue;
|
4960 | }
|
4961 |
|
4962 | const pathsToCheck = parentPaths(data.path);
|
4963 | if (pathsToCheck.find(path => isPathExcluded(this.$__.isSelected, path))) {
|
4964 | continue;
|
4965 | }
|
4966 | }
|
4967 |
|
4968 | if (divergent.length) continue;
|
4969 | if (value === undefined) {
|
4970 | operand(this, where, delta, data, 1, '$unset');
|
4971 | } else if (value === null) {
|
4972 | operand(this, where, delta, data, null);
|
4973 | } else if (utils.isMongooseArray(value) && value.$path() && value[arrayAtomicsSymbol]) {
|
4974 |
|
4975 | handleAtomics(this, where, delta, data, value);
|
4976 | } else if (value[MongooseBuffer.pathSymbol] && Buffer.isBuffer(value)) {
|
4977 |
|
4978 | value = value.toObject();
|
4979 | operand(this, where, delta, data, value);
|
4980 | } else {
|
4981 | if (this.$__.primitiveAtomics && this.$__.primitiveAtomics[data.path] != null) {
|
4982 | const val = this.$__.primitiveAtomics[data.path];
|
4983 | const op = firstKey(val);
|
4984 | operand(this, where, delta, data, val[op], op);
|
4985 | } else {
|
4986 | value = clone(value, {
|
4987 | depopulate: true,
|
4988 | transform: false,
|
4989 | virtuals: false,
|
4990 | getters: false,
|
4991 | omitUndefined: true,
|
4992 | _isNested: true
|
4993 | });
|
4994 | operand(this, where, delta, data, value);
|
4995 | }
|
4996 | }
|
4997 | }
|
4998 |
|
4999 | if (divergent.length) {
|
5000 | return new DivergentArrayError(divergent);
|
5001 | }
|
5002 |
|
5003 | if (this.$__.version) {
|
5004 | this.$__version(where, delta);
|
5005 | }
|
5006 |
|
5007 | if (Object.keys(delta).length === 0) {
|
5008 | return [where, null];
|
5009 | }
|
5010 |
|
5011 | return [where, delta];
|
5012 | };
|
5013 |
|
5014 |
|
5015 |
|
5016 |
|
5017 |
|
5018 |
|
5019 |
|
5020 |
|
5021 |
|
5022 |
|
5023 |
|
5024 |
|
5025 |
|
5026 | function checkDivergentArray(doc, path, array) {
|
5027 |
|
5028 | const pop = doc.$populated(path, true);
|
5029 |
|
5030 | if (!pop && doc.$__.selected) {
|
5031 |
|
5032 |
|
5033 | const top = path.split('.')[0];
|
5034 | if (doc.$__.selected[top + '.$']) {
|
5035 | return top;
|
5036 | }
|
5037 | }
|
5038 |
|
5039 | if (!(pop && utils.isMongooseArray(array))) return;
|
5040 |
|
5041 |
|
5042 |
|
5043 |
|
5044 |
|
5045 |
|
5046 |
|
5047 |
|
5048 |
|
5049 |
|
5050 | const check = pop.options.match ||
|
5051 | pop.options.options && utils.object.hasOwnProperty(pop.options.options, 'limit') ||
|
5052 | pop.options.options && pop.options.options.skip ||
|
5053 | pop.options.select &&
|
5054 | (pop.options.select._id === 0 ||
|
5055 | /\s?-_id\s?/.test(pop.options.select));
|
5056 |
|
5057 | if (check) {
|
5058 | const atomics = array[arrayAtomicsSymbol];
|
5059 | if (Object.keys(atomics).length === 0 || atomics.$set || atomics.$pop) {
|
5060 | return path;
|
5061 | }
|
5062 | }
|
5063 | }
|
5064 |
|
5065 |
|
5066 |
|
5067 |
|
5068 |
|
5069 |
|
5070 |
|
5071 |
|
5072 |
|
5073 |
|
5074 |
|
5075 |
|
5076 |
|
5077 |
|
5078 | function operand(self, where, delta, data, val, op) {
|
5079 |
|
5080 | op || (op = '$set');
|
5081 | if (!delta[op]) delta[op] = {};
|
5082 | delta[op][data.path] = val;
|
5083 |
|
5084 | if (self.$__schema.options.versionKey === false) return;
|
5085 |
|
5086 |
|
5087 | if (shouldSkipVersioning(self, data.path)) return;
|
5088 |
|
5089 |
|
5090 | if (VERSION_ALL === (VERSION_ALL & self.$__.version)) return;
|
5091 |
|
5092 | if (self.$__schema.options.optimisticConcurrency) {
|
5093 | return;
|
5094 | }
|
5095 |
|
5096 | switch (op) {
|
5097 | case '$set':
|
5098 | case '$unset':
|
5099 | case '$pop':
|
5100 | case '$pull':
|
5101 | case '$pullAll':
|
5102 | case '$push':
|
5103 | case '$addToSet':
|
5104 | case '$inc':
|
5105 | break;
|
5106 | default:
|
5107 |
|
5108 | return;
|
5109 | }
|
5110 |
|
5111 |
|
5112 |
|
5113 |
|
5114 |
|
5115 | if (op === '$push' || op === '$addToSet' || op === '$pullAll' || op === '$pull') {
|
5116 | if (/\.\d+\.|\.\d+$/.test(data.path)) {
|
5117 | self.$__.version = VERSION_ALL;
|
5118 | } else {
|
5119 | self.$__.version = VERSION_INC;
|
5120 | }
|
5121 | } else if (/^\$p/.test(op)) {
|
5122 |
|
5123 | self.$__.version = VERSION_ALL;
|
5124 | } else if (Array.isArray(val)) {
|
5125 |
|
5126 | self.$__.version = VERSION_ALL;
|
5127 | } else if (/\.\d+\.|\.\d+$/.test(data.path)) {
|
5128 |
|
5129 |
|
5130 | self.$__.version = VERSION_WHERE;
|
5131 | }
|
5132 | }
|
5133 |
|
5134 |
|
5135 |
|
5136 |
|
5137 |
|
5138 |
|
5139 |
|
5140 |
|
5141 |
|
5142 |
|
5143 |
|
5144 |
|
5145 | function handleAtomics(self, where, delta, data, value) {
|
5146 | if (delta.$set && delta.$set[data.path]) {
|
5147 |
|
5148 | return;
|
5149 | }
|
5150 |
|
5151 | if (typeof value.$__getAtomics === 'function') {
|
5152 | value.$__getAtomics().forEach(function(atomic) {
|
5153 | const op = atomic[0];
|
5154 | const val = atomic[1];
|
5155 | operand(self, where, delta, data, val, op);
|
5156 | });
|
5157 | return;
|
5158 | }
|
5159 |
|
5160 |
|
5161 |
|
5162 | const atomics = value[arrayAtomicsSymbol];
|
5163 | const ops = Object.keys(atomics);
|
5164 | let i = ops.length;
|
5165 | let val;
|
5166 | let op;
|
5167 |
|
5168 | if (i === 0) {
|
5169 |
|
5170 |
|
5171 | if (utils.isMongooseObject(value)) {
|
5172 | value = value.toObject({ depopulate: 1, _isNested: true });
|
5173 | } else if (value.valueOf) {
|
5174 | value = value.valueOf();
|
5175 | }
|
5176 |
|
5177 | return operand(self, where, delta, data, value);
|
5178 | }
|
5179 |
|
5180 | function iter(mem) {
|
5181 | return utils.isMongooseObject(mem)
|
5182 | ? mem.toObject({ depopulate: 1, _isNested: true })
|
5183 | : mem;
|
5184 | }
|
5185 |
|
5186 | while (i--) {
|
5187 | op = ops[i];
|
5188 | val = atomics[op];
|
5189 |
|
5190 | if (utils.isMongooseObject(val)) {
|
5191 | val = val.toObject({ depopulate: true, transform: false, _isNested: true });
|
5192 | } else if (Array.isArray(val)) {
|
5193 | val = val.map(iter);
|
5194 | } else if (val.valueOf) {
|
5195 | val = val.valueOf();
|
5196 | }
|
5197 |
|
5198 | if (op === '$addToSet') {
|
5199 | val = { $each: val };
|
5200 | }
|
5201 |
|
5202 | operand(self, where, delta, data, val, op);
|
5203 | }
|
5204 | }
|
5205 |
|
5206 |
|
5207 |
|
5208 |
|
5209 |
|
5210 |
|
5211 |
|
5212 |
|
5213 |
|
5214 | function shouldSkipVersioning(self, path) {
|
5215 | const skipVersioning = self.$__schema.options.skipVersioning;
|
5216 | if (!skipVersioning) return false;
|
5217 |
|
5218 |
|
5219 | path = path.replace(/\.\d+\./, '.');
|
5220 |
|
5221 | return skipVersioning[path];
|
5222 | }
|
5223 |
|
5224 |
|
5225 |
|
5226 |
|
5227 |
|
5228 |
|
5229 |
|
5230 |
|
5231 |
|
5232 |
|
5233 |
|
5234 | Document.prototype.$clone = function() {
|
5235 | const Model = this.constructor;
|
5236 | const clonedDoc = new Model();
|
5237 | clonedDoc.$isNew = this.$isNew;
|
5238 | if (this._doc) {
|
5239 | clonedDoc._doc = clone(this._doc, { retainDocuments: true });
|
5240 | }
|
5241 | if (this.$__) {
|
5242 | const Cache = this.$__.constructor;
|
5243 | const clonedCache = new Cache();
|
5244 | for (const key of Object.getOwnPropertyNames(this.$__)) {
|
5245 | if (key === 'activePaths') {
|
5246 | continue;
|
5247 | }
|
5248 | clonedCache[key] = clone(this.$__[key]);
|
5249 | }
|
5250 | Object.assign(clonedCache.activePaths, clone({ ...this.$__.activePaths }));
|
5251 | clonedDoc.$__ = clonedCache;
|
5252 | }
|
5253 | return clonedDoc;
|
5254 | };
|
5255 |
|
5256 |
|
5257 |
|
5258 |
|
5259 |
|
5260 |
|
5261 |
|
5262 |
|
5263 |
|
5264 |
|
5265 |
|
5266 |
|
5267 |
|
5268 |
|
5269 |
|
5270 |
|
5271 |
|
5272 | Document.prototype.$createModifiedPathsSnapshot = function $createModifiedPathsSnapshot() {
|
5273 | const subdocSnapshot = new WeakMap();
|
5274 | if (!this.$isSubdocument) {
|
5275 | const subdocs = this.$getAllSubdocs();
|
5276 | for (const child of subdocs) {
|
5277 | subdocSnapshot.set(child, child.$__.activePaths.clone());
|
5278 | }
|
5279 | }
|
5280 |
|
5281 | return new ModifiedPathsSnapshot(
|
5282 | subdocSnapshot,
|
5283 | this.$__.activePaths.clone(),
|
5284 | this.$__.version
|
5285 | );
|
5286 | };
|
5287 |
|
5288 |
|
5289 |
|
5290 |
|
5291 |
|
5292 |
|
5293 |
|
5294 |
|
5295 |
|
5296 |
|
5297 |
|
5298 |
|
5299 |
|
5300 |
|
5301 |
|
5302 |
|
5303 |
|
5304 |
|
5305 |
|
5306 |
|
5307 |
|
5308 |
|
5309 |
|
5310 |
|
5311 |
|
5312 |
|
5313 | Document.prototype.$restoreModifiedPathsSnapshot = function $restoreModifiedPathsSnapshot(snapshot) {
|
5314 | this.$__.activePaths = snapshot.activePaths.clone();
|
5315 | this.$__.version = snapshot.version;
|
5316 | if (!this.$isSubdocument) {
|
5317 | const subdocs = this.$getAllSubdocs();
|
5318 | for (const child of subdocs) {
|
5319 | if (snapshot.subdocSnapshot.has(child)) {
|
5320 | child.$__.activePaths = snapshot.subdocSnapshot.get(child);
|
5321 | }
|
5322 | }
|
5323 | }
|
5324 |
|
5325 | return this;
|
5326 | };
|
5327 |
|
5328 |
|
5329 |
|
5330 |
|
5331 |
|
5332 |
|
5333 |
|
5334 |
|
5335 |
|
5336 |
|
5337 |
|
5338 |
|
5339 |
|
5340 |
|
5341 |
|
5342 |
|
5343 |
|
5344 |
|
5345 |
|
5346 |
|
5347 |
|
5348 | Document.prototype.$clearModifiedPaths = function $clearModifiedPaths() {
|
5349 | this.$__.activePaths.clear('modify');
|
5350 | this.$__.activePaths.clear('init');
|
5351 | this.$__.version = 0;
|
5352 | if (!this.$isSubdocument) {
|
5353 | const subdocs = this.$getAllSubdocs();
|
5354 | for (const child of subdocs) {
|
5355 | child.$clearModifiedPaths();
|
5356 | }
|
5357 | }
|
5358 |
|
5359 | return this;
|
5360 | };
|
5361 |
|
5362 |
|
5363 |
|
5364 |
|
5365 |
|
5366 | Document.prototype.$__hasOnlyPrimitiveValues = function $__hasOnlyPrimitiveValues() {
|
5367 | return !this.$__.populated && !this.$__.wasPopulated && (this._doc == null || Object.values(this._doc).every(v => {
|
5368 | return v == null
|
5369 | || typeof v !== 'object'
|
5370 | || (utils.isNativeObject(v) && !Array.isArray(v))
|
5371 | || isBsonType(v, 'ObjectId')
|
5372 | || isBsonType(v, 'Decimal128');
|
5373 | }));
|
5374 | };
|
5375 |
|
5376 |
|
5377 |
|
5378 |
|
5379 |
|
5380 | Document.VERSION_WHERE = VERSION_WHERE;
|
5381 | Document.VERSION_INC = VERSION_INC;
|
5382 | Document.VERSION_ALL = VERSION_ALL;
|
5383 | Document.ValidationError = ValidationError;
|
5384 | module.exports = exports = Document;
|