mongoose 6.2.0 → 6.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +150 -0
- package/CHANGELOG.md +21 -0
- package/dist/browser.umd.js +113 -112
- package/lib/aggregate.js +1 -1
- package/lib/document.js +83 -64
- package/lib/helpers/clone.js +40 -27
- package/lib/helpers/common.js +2 -2
- package/lib/helpers/getFunctionName.js +6 -4
- package/lib/helpers/isMongooseObject.js +9 -8
- package/lib/helpers/isObject.js +4 -4
- package/lib/helpers/path/parentPaths.js +10 -5
- package/lib/helpers/populate/assignRawDocsToIdStructure.js +4 -2
- package/lib/helpers/populate/assignVals.js +8 -4
- package/lib/helpers/populate/getModelsMapForPopulate.js +4 -4
- package/lib/helpers/populate/markArraySubdocsPopulated.js +3 -1
- package/lib/helpers/populate/modelNamesFromRefPath.js +4 -3
- package/lib/helpers/query/castUpdate.js +6 -2
- package/lib/helpers/schema/getPath.js +4 -2
- package/lib/helpers/timestamps/setupTimestamps.js +3 -8
- package/lib/index.js +2 -0
- package/lib/internal.js +1 -1
- package/lib/model.js +22 -8
- package/lib/plugins/trackTransaction.js +4 -3
- package/lib/query.js +3 -2
- package/lib/queryhelpers.js +1 -1
- package/lib/schema/array.js +17 -15
- package/lib/schema/documentarray.js +5 -8
- package/lib/schema/objectid.js +1 -1
- package/lib/schematype.js +29 -26
- package/lib/types/ArraySubdocument.js +2 -1
- package/lib/types/DocumentArray/index.js +9 -26
- package/lib/types/DocumentArray/isMongooseDocumentArray.js +5 -0
- package/lib/types/DocumentArray/methods/index.js +15 -3
- package/lib/types/array/index.js +21 -20
- package/lib/types/array/isMongooseArray.js +5 -0
- package/lib/types/array/methods/index.js +12 -12
- package/lib/utils.js +7 -0
- package/package.json +18 -147
- package/tools/repl.js +1 -1
- package/tsconfig.json +10 -0
- package/{index.d.ts → types/index.d.ts} +84 -75
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const utils = require('../../utils');
|
|
4
|
+
|
|
3
5
|
/*!
|
|
4
6
|
* If populating a path within a document array, make sure each
|
|
5
7
|
* subdoc within the array knows its subpaths are populated.
|
|
@@ -29,7 +31,7 @@ module.exports = function markArraySubdocsPopulated(doc, populated) {
|
|
|
29
31
|
continue;
|
|
30
32
|
}
|
|
31
33
|
|
|
32
|
-
if (
|
|
34
|
+
if (utils.isMongooseDocumentArray(val)) {
|
|
33
35
|
for (let j = 0; j < val.length; ++j) {
|
|
34
36
|
val[j].populated(rest, item._docs[id] == null ? void 0 : item._docs[id][j], item);
|
|
35
37
|
}
|
|
@@ -7,6 +7,8 @@ const mpath = require('mpath');
|
|
|
7
7
|
const util = require('util');
|
|
8
8
|
const utils = require('../../utils');
|
|
9
9
|
|
|
10
|
+
const hasNumericPropRE = /(\.\d+$|\.\d+\.)/g;
|
|
11
|
+
|
|
10
12
|
module.exports = function modelNamesFromRefPath(refPath, doc, populatedPath, modelSchema, queryProjection) {
|
|
11
13
|
if (refPath == null) {
|
|
12
14
|
return [];
|
|
@@ -20,10 +22,9 @@ module.exports = function modelNamesFromRefPath(refPath, doc, populatedPath, mod
|
|
|
20
22
|
// If populated path has numerics, the end `refPath` should too. For example,
|
|
21
23
|
// if populating `a.0.b` instead of `a.b` and `b` has `refPath = a.c`, we
|
|
22
24
|
// should return `a.0.c` for the refPath.
|
|
23
|
-
const hasNumericProp = /(\.\d+$|\.\d+\.)/g;
|
|
24
25
|
|
|
25
|
-
if (
|
|
26
|
-
const chunks = populatedPath.split(
|
|
26
|
+
if (hasNumericPropRE.test(populatedPath)) {
|
|
27
|
+
const chunks = populatedPath.split(hasNumericPropRE);
|
|
27
28
|
|
|
28
29
|
if (chunks[chunks.length - 1] === '') {
|
|
29
30
|
throw new Error('Can\'t populate individual element in an array');
|
|
@@ -41,9 +41,10 @@ module.exports = function castUpdate(schema, obj, options, context, filter) {
|
|
|
41
41
|
}
|
|
42
42
|
return obj;
|
|
43
43
|
}
|
|
44
|
+
|
|
44
45
|
if (schema.options.strict === 'throw' && obj.hasOwnProperty(schema.options.discriminatorKey)) {
|
|
45
46
|
throw new StrictModeError(schema.options.discriminatorKey);
|
|
46
|
-
} else if (
|
|
47
|
+
} else if (!options.overwriteDiscriminatorKey) {
|
|
47
48
|
delete obj[schema.options.discriminatorKey];
|
|
48
49
|
}
|
|
49
50
|
if (options.upsert) {
|
|
@@ -353,7 +354,10 @@ function walkUpdatePath(schema, obj, op, options, context, filter, pref) {
|
|
|
353
354
|
}
|
|
354
355
|
|
|
355
356
|
if (Array.isArray(obj[key]) && (op === '$addToSet' || op === '$push') && key !== '$each') {
|
|
356
|
-
if (schematype &&
|
|
357
|
+
if (schematype &&
|
|
358
|
+
schematype.caster &&
|
|
359
|
+
!schematype.caster.$isMongooseArray &&
|
|
360
|
+
!schematype.caster[schemaMixedSymbol]) {
|
|
357
361
|
obj[key] = { $each: obj[key] };
|
|
358
362
|
}
|
|
359
363
|
}
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* needing to put `.0.`, so `getPath(schema, 'docArr.elProp')` works.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
const numberRE = /^\d+$/;
|
|
9
|
+
|
|
8
10
|
module.exports = function getPath(schema, path) {
|
|
9
11
|
let schematype = schema.path(path);
|
|
10
12
|
if (schematype != null) {
|
|
@@ -16,7 +18,7 @@ module.exports = function getPath(schema, path) {
|
|
|
16
18
|
let isArray = false;
|
|
17
19
|
|
|
18
20
|
for (const piece of pieces) {
|
|
19
|
-
if (
|
|
21
|
+
if (isArray && numberRE.test(piece)) {
|
|
20
22
|
continue;
|
|
21
23
|
}
|
|
22
24
|
cur = cur.length === 0 ? piece : cur + '.' + piece;
|
|
@@ -25,7 +27,7 @@ module.exports = function getPath(schema, path) {
|
|
|
25
27
|
if (schematype != null && schematype.schema) {
|
|
26
28
|
schema = schematype.schema;
|
|
27
29
|
cur = '';
|
|
28
|
-
if (schematype.$isMongooseDocumentArray) {
|
|
30
|
+
if (!isArray && schematype.$isMongooseDocumentArray) {
|
|
29
31
|
isArray = true;
|
|
30
32
|
}
|
|
31
33
|
}
|
|
@@ -47,20 +47,15 @@ module.exports = function setupTimestamps(schema, timestamps) {
|
|
|
47
47
|
const defaultTimestamp = currentTime != null ?
|
|
48
48
|
currentTime() :
|
|
49
49
|
this.ownerDocument().constructor.base.now();
|
|
50
|
-
const auto_id = this._id && this._id.auto;
|
|
51
50
|
|
|
52
51
|
if (!skipCreatedAt && this.isNew && createdAt && !this.$__getValue(createdAt) && this.$__isSelected(createdAt)) {
|
|
53
|
-
this.$set(createdAt,
|
|
52
|
+
this.$set(createdAt, defaultTimestamp);
|
|
54
53
|
}
|
|
55
54
|
|
|
56
55
|
if (!skipUpdatedAt && updatedAt && (this.isNew || this.$isModified())) {
|
|
57
56
|
let ts = defaultTimestamp;
|
|
58
|
-
if (this.isNew) {
|
|
59
|
-
|
|
60
|
-
ts = this.$__getValue(createdAt);
|
|
61
|
-
} else if (auto_id) {
|
|
62
|
-
ts = this._id.getTimestamp();
|
|
63
|
-
}
|
|
57
|
+
if (this.isNew && createdAt != null) {
|
|
58
|
+
ts = this.$__getValue(createdAt);
|
|
64
59
|
}
|
|
65
60
|
this.$set(updatedAt, ts);
|
|
66
61
|
}
|
package/lib/index.js
CHANGED
|
@@ -951,6 +951,8 @@ Mongoose.prototype.ObjectId = SchemaTypes.ObjectId;
|
|
|
951
951
|
* mongoose.isValidObjectId({ test: 42 }); // false
|
|
952
952
|
*
|
|
953
953
|
* @method isValidObjectId
|
|
954
|
+
* @param {Any} value
|
|
955
|
+
* @returns {boolean} true if it is a valid ObjectId
|
|
954
956
|
* @api public
|
|
955
957
|
*/
|
|
956
958
|
|
package/lib/internal.js
CHANGED
|
@@ -10,7 +10,7 @@ const ActiveRoster = StateMachine.ctor('require', 'modify', 'init', 'default', '
|
|
|
10
10
|
module.exports = exports = InternalCache;
|
|
11
11
|
|
|
12
12
|
function InternalCache() {
|
|
13
|
-
this.activePaths = new ActiveRoster;
|
|
13
|
+
this.activePaths = new ActiveRoster();
|
|
14
14
|
this.strictMode = undefined;
|
|
15
15
|
}
|
|
16
16
|
|
package/lib/model.js
CHANGED
|
@@ -380,7 +380,12 @@ Model.prototype.$__save = function(options, callback) {
|
|
|
380
380
|
});
|
|
381
381
|
}
|
|
382
382
|
let numAffected = 0;
|
|
383
|
-
|
|
383
|
+
const writeConcern = options != null ?
|
|
384
|
+
options.writeConcern != null ?
|
|
385
|
+
options.writeConcern.w :
|
|
386
|
+
options.w :
|
|
387
|
+
0;
|
|
388
|
+
if (writeConcern !== 0) {
|
|
384
389
|
// Skip checking if write succeeded if writeConcern is set to
|
|
385
390
|
// unacknowledged writes, because otherwise `numAffected` will always be 0
|
|
386
391
|
if (result != null) {
|
|
@@ -392,8 +397,10 @@ Model.prototype.$__save = function(options, callback) {
|
|
|
392
397
|
numAffected = result;
|
|
393
398
|
}
|
|
394
399
|
}
|
|
400
|
+
|
|
401
|
+
const versionBump = this.$__.version || this.$__schema.options.optimisticConcurrency;
|
|
395
402
|
// was this an update that required a version bump?
|
|
396
|
-
if (
|
|
403
|
+
if (versionBump && !this.$__.inserting) {
|
|
397
404
|
const doIncrement = VERSION_INC === (VERSION_INC & this.$__.version);
|
|
398
405
|
this.$__.version = undefined;
|
|
399
406
|
const key = this.$__schema.options.versionKey;
|
|
@@ -741,7 +748,7 @@ Model.prototype.$__delta = function() {
|
|
|
741
748
|
operand(this, where, delta, data, 1, '$unset');
|
|
742
749
|
} else if (value === null) {
|
|
743
750
|
operand(this, where, delta, data, null);
|
|
744
|
-
} else if (
|
|
751
|
+
} else if (utils.isMongooseArray(value) && value.$path() && value[arrayAtomicsSymbol]) {
|
|
745
752
|
// arrays and other custom types (support plugins etc)
|
|
746
753
|
handleAtomics(this, where, delta, data, value);
|
|
747
754
|
} else if (value[MongooseBuffer.pathSymbol] && Buffer.isBuffer(value)) {
|
|
@@ -793,7 +800,7 @@ function checkDivergentArray(doc, path, array) {
|
|
|
793
800
|
}
|
|
794
801
|
}
|
|
795
802
|
|
|
796
|
-
if (!(pop &&
|
|
803
|
+
if (!(pop && utils.isMongooseArray(array))) return;
|
|
797
804
|
|
|
798
805
|
// If the array was populated using options that prevented all
|
|
799
806
|
// documents from being returned (match, skip, limit) or they
|
|
@@ -3374,7 +3381,7 @@ Model.$__insertMany = function(arr, options, callback) {
|
|
|
3374
3381
|
return doc != null;
|
|
3375
3382
|
});
|
|
3376
3383
|
// Quickly escape while there aren't any valid docAttributes
|
|
3377
|
-
if (docAttributes.length
|
|
3384
|
+
if (docAttributes.length === 0) {
|
|
3378
3385
|
if (rawResult) {
|
|
3379
3386
|
const res = {
|
|
3380
3387
|
mongoose: {
|
|
@@ -4456,9 +4463,16 @@ const excludeIdRegGlobal = /\s?-_id\s?/g;
|
|
|
4456
4463
|
|
|
4457
4464
|
function populate(model, docs, options, callback) {
|
|
4458
4465
|
const populateOptions = { ...options };
|
|
4459
|
-
if (
|
|
4460
|
-
|
|
4466
|
+
if (options.strictPopulate == null) {
|
|
4467
|
+
if (options._localModel != null && options._localModel.schema._userProvidedOptions.strictPopulate != null) {
|
|
4468
|
+
populateOptions.strictPopulate = options._localModel.schema._userProvidedOptions.strictPopulate;
|
|
4469
|
+
} else if (options._localModel != null && model.base.options.strictPopulate != null) {
|
|
4470
|
+
populateOptions.strictPopulate = model.base.options.strictPopulate;
|
|
4471
|
+
} else if (model.base.options.strictPopulate != null) {
|
|
4472
|
+
populateOptions.strictPopulate = model.base.options.strictPopulate;
|
|
4473
|
+
}
|
|
4461
4474
|
}
|
|
4475
|
+
|
|
4462
4476
|
// normalize single / multiple docs passed
|
|
4463
4477
|
if (!Array.isArray(docs)) {
|
|
4464
4478
|
docs = [docs];
|
|
@@ -4529,7 +4543,7 @@ function populate(model, docs, options, callback) {
|
|
|
4529
4543
|
}
|
|
4530
4544
|
if (!hasOne) {
|
|
4531
4545
|
// If models but no docs, skip further deep populate.
|
|
4532
|
-
if (modelsMap.length
|
|
4546
|
+
if (modelsMap.length !== 0) {
|
|
4533
4547
|
return callback();
|
|
4534
4548
|
}
|
|
4535
4549
|
// If no models to populate but we have a nested populate,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const arrayAtomicsSymbol = require('../helpers/symbols').arrayAtomicsSymbol;
|
|
4
4
|
const sessionNewDocuments = require('../helpers/symbols').sessionNewDocuments;
|
|
5
|
+
const utils = require('../utils');
|
|
5
6
|
|
|
6
7
|
module.exports = function trackTransaction(schema) {
|
|
7
8
|
schema.pre('save', function() {
|
|
@@ -47,10 +48,10 @@ function _getAtomics(doc, previous) {
|
|
|
47
48
|
const val = doc.$__getValue(path);
|
|
48
49
|
if (val != null &&
|
|
49
50
|
val instanceof Array &&
|
|
50
|
-
|
|
51
|
+
utils.isMongooseDocumentArray(val) &&
|
|
51
52
|
val.length &&
|
|
52
53
|
val[arrayAtomicsSymbol] != null &&
|
|
53
|
-
Object.keys(val[arrayAtomicsSymbol]).length
|
|
54
|
+
Object.keys(val[arrayAtomicsSymbol]).length !== 0) {
|
|
54
55
|
const existing = previous.get(path) || {};
|
|
55
56
|
pathToAtomics.set(path, mergeAtomics(existing, val[arrayAtomicsSymbol]));
|
|
56
57
|
}
|
|
@@ -61,7 +62,7 @@ function _getAtomics(doc, previous) {
|
|
|
61
62
|
const path = dirt.path;
|
|
62
63
|
|
|
63
64
|
const val = dirt.value;
|
|
64
|
-
if (val != null && val[arrayAtomicsSymbol] != null && Object.keys(val[arrayAtomicsSymbol]).length
|
|
65
|
+
if (val != null && val[arrayAtomicsSymbol] != null && Object.keys(val[arrayAtomicsSymbol]).length !== 0) {
|
|
65
66
|
const existing = previous.get(path) || {};
|
|
66
67
|
pathToAtomics.set(path, mergeAtomics(existing, val[arrayAtomicsSymbol]));
|
|
67
68
|
}
|
package/lib/query.js
CHANGED
|
@@ -120,7 +120,7 @@ function Query(conditions, options, model, collection) {
|
|
|
120
120
|
* inherit mquery
|
|
121
121
|
*/
|
|
122
122
|
|
|
123
|
-
Query.prototype = new mquery;
|
|
123
|
+
Query.prototype = new mquery();
|
|
124
124
|
Query.prototype.constructor = Query;
|
|
125
125
|
Query.base = mquery.prototype;
|
|
126
126
|
|
|
@@ -4848,7 +4848,8 @@ Query.prototype._castUpdate = function _castUpdate(obj, overwrite) {
|
|
|
4848
4848
|
overwrite: overwrite,
|
|
4849
4849
|
strict: this._mongooseOptions.strict,
|
|
4850
4850
|
upsert: upsert,
|
|
4851
|
-
arrayFilters: this.options.arrayFilters
|
|
4851
|
+
arrayFilters: this.options.arrayFilters,
|
|
4852
|
+
overwriteDiscriminatorKey: this._mongooseOptions.overwriteDiscriminatorKey
|
|
4852
4853
|
}, this, this._conditions);
|
|
4853
4854
|
};
|
|
4854
4855
|
|
package/lib/queryhelpers.js
CHANGED
|
@@ -212,7 +212,7 @@ exports.applyPaths = function applyPaths(fields, schema) {
|
|
|
212
212
|
|
|
213
213
|
let addedPath = analyzePath(path, type);
|
|
214
214
|
// arrays
|
|
215
|
-
if (addedPath == null && type.$isMongooseArray && !type.$isMongooseDocumentArray) {
|
|
215
|
+
if (addedPath == null && !Array.isArray(type) && type.$isMongooseArray && !type.$isMongooseDocumentArray) {
|
|
216
216
|
addedPath = analyzePath(path, type.caster);
|
|
217
217
|
}
|
|
218
218
|
if (addedPath != null) {
|
package/lib/schema/array.js
CHANGED
|
@@ -112,14 +112,12 @@ function SchemaArray(key, cast, options, schemaOptions) {
|
|
|
112
112
|
|
|
113
113
|
if (!('defaultValue' in this) || this.defaultValue !== void 0) {
|
|
114
114
|
const defaultFn = function() {
|
|
115
|
-
let arr = [];
|
|
116
|
-
if (fn) {
|
|
117
|
-
arr = defaultArr.call(this);
|
|
118
|
-
} else if (defaultArr != null) {
|
|
119
|
-
arr = arr.concat(defaultArr);
|
|
120
|
-
}
|
|
121
115
|
// Leave it up to `cast()` to convert the array
|
|
122
|
-
return
|
|
116
|
+
return fn
|
|
117
|
+
? defaultArr.call(this)
|
|
118
|
+
: defaultArr != null
|
|
119
|
+
? [].concat(defaultArr)
|
|
120
|
+
: [];
|
|
123
121
|
};
|
|
124
122
|
defaultFn.$runBeforeSetters = !fn;
|
|
125
123
|
this.default(defaultFn);
|
|
@@ -275,7 +273,7 @@ SchemaArray.prototype.applyGetters = function(value, scope) {
|
|
|
275
273
|
|
|
276
274
|
const ret = SchemaType.prototype.applyGetters.call(this, value, scope);
|
|
277
275
|
if (Array.isArray(ret)) {
|
|
278
|
-
const rawValue = ret
|
|
276
|
+
const rawValue = utils.isMongooseArray(ret) ? ret.__array : ret;
|
|
279
277
|
const len = rawValue.length;
|
|
280
278
|
for (let i = 0; i < len; ++i) {
|
|
281
279
|
rawValue[i] = this.caster.applyGetters(rawValue[i], scope);
|
|
@@ -299,7 +297,7 @@ SchemaArray.prototype._applySetters = function(value, scope, init, priorVal) {
|
|
|
299
297
|
}
|
|
300
298
|
|
|
301
299
|
// No need to wrap empty arrays
|
|
302
|
-
if (value != null && value.length
|
|
300
|
+
if (value != null && value.length !== 0) {
|
|
303
301
|
const valueDepth = arrayDepth(value);
|
|
304
302
|
if (valueDepth.min === valueDepth.max && valueDepth.max < depth && valueDepth.containsNonArrayItem) {
|
|
305
303
|
for (let i = valueDepth.max; i < depth; ++i) {
|
|
@@ -357,7 +355,7 @@ SchemaArray.prototype.cast = function(value, doc, init, prev, options) {
|
|
|
357
355
|
|
|
358
356
|
options = options || emptyOpts;
|
|
359
357
|
|
|
360
|
-
let rawValue = value
|
|
358
|
+
let rawValue = utils.isMongooseArray(value) ? value.__array : value;
|
|
361
359
|
value = MongooseArray(rawValue, options.path || this._arrayPath || this.path, doc, this);
|
|
362
360
|
rawValue = value.__array;
|
|
363
361
|
|
|
@@ -557,12 +555,16 @@ function cast$all(val) {
|
|
|
557
555
|
}
|
|
558
556
|
|
|
559
557
|
val = val.map(function(v) {
|
|
560
|
-
if (utils.isObject(v)) {
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
558
|
+
if (!utils.isObject(v)) {
|
|
559
|
+
return v;
|
|
560
|
+
}
|
|
561
|
+
if (v.$elemMatch != null) {
|
|
562
|
+
return { $elemMatch: cast(this.casterConstructor.schema, v.$elemMatch) };
|
|
564
563
|
}
|
|
565
|
-
|
|
564
|
+
|
|
565
|
+
const o = {};
|
|
566
|
+
o[this.path] = v;
|
|
567
|
+
return cast(this.casterConstructor.schema, o)[this.path];
|
|
566
568
|
}, this);
|
|
567
569
|
|
|
568
570
|
return this.castForQuery(val);
|
|
@@ -228,7 +228,7 @@ DocumentArrayPath.prototype.doValidate = function(array, fn, scope, options) {
|
|
|
228
228
|
if (options && options.updateValidator) {
|
|
229
229
|
return fn();
|
|
230
230
|
}
|
|
231
|
-
if (!
|
|
231
|
+
if (!utils.isMongooseDocumentArray(array)) {
|
|
232
232
|
array = new MongooseDocumentArray(array, _this.path, scope);
|
|
233
233
|
}
|
|
234
234
|
|
|
@@ -398,12 +398,9 @@ DocumentArrayPath.prototype.cast = function(value, doc, init, prev, options) {
|
|
|
398
398
|
return this.cast([value], doc, init, prev, options);
|
|
399
399
|
}
|
|
400
400
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
} else if (value && value.isMongooseDocumentArray) {
|
|
405
|
-
// We need to create a new array, otherwise change tracking will
|
|
406
|
-
// update the old doc (gh-4449)
|
|
401
|
+
// We need to create a new array, otherwise change tracking will
|
|
402
|
+
// update the old doc (gh-4449)
|
|
403
|
+
if (!options.skipDocumentArrayCast || utils.isMongooseDocumentArray(value)) {
|
|
407
404
|
value = new MongooseDocumentArray(value, this.path, doc);
|
|
408
405
|
}
|
|
409
406
|
|
|
@@ -415,7 +412,7 @@ DocumentArrayPath.prototype.cast = function(value, doc, init, prev, options) {
|
|
|
415
412
|
value[arrayPathSymbol] = this.path + '.' + options.arrayPathIndex;
|
|
416
413
|
}
|
|
417
414
|
|
|
418
|
-
const rawArray = value
|
|
415
|
+
const rawArray = utils.isMongooseDocumentArray(value) ? value.__array : value;
|
|
419
416
|
|
|
420
417
|
const len = rawArray.length;
|
|
421
418
|
const initDocumentOptions = { skipId: true, willInit: true };
|
package/lib/schema/objectid.js
CHANGED
package/lib/schematype.js
CHANGED
|
@@ -1125,7 +1125,7 @@ SchemaType.prototype.getDefault = function(scope, init) {
|
|
|
1125
1125
|
}
|
|
1126
1126
|
|
|
1127
1127
|
const casted = this.applySetters(ret, scope, init);
|
|
1128
|
-
if (casted && casted.$isSingleNested) {
|
|
1128
|
+
if (casted && !Array.isArray(casted) && casted.$isSingleNested) {
|
|
1129
1129
|
casted.$__parent = scope;
|
|
1130
1130
|
}
|
|
1131
1131
|
return casted;
|
|
@@ -1328,6 +1328,16 @@ SchemaType.prototype.doValidate = function(value, fn, scope, options) {
|
|
|
1328
1328
|
}
|
|
1329
1329
|
};
|
|
1330
1330
|
|
|
1331
|
+
|
|
1332
|
+
function _validate(ok, validatorProperties) {
|
|
1333
|
+
if (ok !== undefined && !ok) {
|
|
1334
|
+
const ErrorConstructor = validatorProperties.ErrorConstructor || ValidatorError;
|
|
1335
|
+
const err = new ErrorConstructor(validatorProperties);
|
|
1336
|
+
err[validatorErrorSymbol] = true;
|
|
1337
|
+
return err;
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1331
1341
|
/**
|
|
1332
1342
|
* Performs a validation of `value` using the validators declared for this SchemaType.
|
|
1333
1343
|
*
|
|
@@ -1351,7 +1361,7 @@ SchemaType.prototype.doValidateSync = function(value, scope, options) {
|
|
|
1351
1361
|
|
|
1352
1362
|
let validators = this.validators;
|
|
1353
1363
|
if (value === void 0) {
|
|
1354
|
-
if (this.validators.length
|
|
1364
|
+
if (this.validators.length !== 0 && this.validators[0].type === 'required') {
|
|
1355
1365
|
validators = [this.validators[0]];
|
|
1356
1366
|
} else {
|
|
1357
1367
|
return null;
|
|
@@ -1359,34 +1369,35 @@ SchemaType.prototype.doValidateSync = function(value, scope, options) {
|
|
|
1359
1369
|
}
|
|
1360
1370
|
|
|
1361
1371
|
let err = null;
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1372
|
+
let i = 0;
|
|
1373
|
+
const len = validators.length;
|
|
1374
|
+
for (i = 0; i < len; ++i) {
|
|
1375
|
+
|
|
1376
|
+
const v = validators[i];
|
|
1366
1377
|
|
|
1367
1378
|
if (v == null || typeof v !== 'object') {
|
|
1368
|
-
|
|
1379
|
+
continue;
|
|
1369
1380
|
}
|
|
1370
1381
|
|
|
1371
1382
|
const validator = v.validator;
|
|
1372
1383
|
const validatorProperties = utils.clone(v);
|
|
1373
1384
|
validatorProperties.path = options && options.path ? options.path : path;
|
|
1374
1385
|
validatorProperties.value = value;
|
|
1375
|
-
let ok;
|
|
1386
|
+
let ok = false;
|
|
1376
1387
|
|
|
1377
1388
|
// Skip any explicit async validators. Validators that return a promise
|
|
1378
1389
|
// will still run, but won't trigger any errors.
|
|
1379
1390
|
if (isAsyncFunction(validator)) {
|
|
1380
|
-
|
|
1391
|
+
continue;
|
|
1381
1392
|
}
|
|
1382
1393
|
|
|
1383
1394
|
if (validator instanceof RegExp) {
|
|
1384
|
-
|
|
1385
|
-
|
|
1395
|
+
err = _validate(validator.test(value), validatorProperties);
|
|
1396
|
+
continue;
|
|
1386
1397
|
}
|
|
1387
1398
|
|
|
1388
1399
|
if (typeof validator !== 'function') {
|
|
1389
|
-
|
|
1400
|
+
continue;
|
|
1390
1401
|
}
|
|
1391
1402
|
|
|
1392
1403
|
try {
|
|
@@ -1403,23 +1414,15 @@ SchemaType.prototype.doValidateSync = function(value, scope, options) {
|
|
|
1403
1414
|
// Skip any validators that return a promise, we can't handle those
|
|
1404
1415
|
// synchronously
|
|
1405
1416
|
if (ok != null && typeof ok.then === 'function') {
|
|
1406
|
-
|
|
1417
|
+
continue;
|
|
1407
1418
|
}
|
|
1408
|
-
|
|
1409
|
-
});
|
|
1410
|
-
|
|
1411
|
-
return err;
|
|
1412
|
-
|
|
1413
|
-
function validate(ok, validatorProperties) {
|
|
1419
|
+
err = _validate(ok, validatorProperties);
|
|
1414
1420
|
if (err) {
|
|
1415
|
-
|
|
1416
|
-
}
|
|
1417
|
-
if (ok !== undefined && !ok) {
|
|
1418
|
-
const ErrorConstructor = validatorProperties.ErrorConstructor || ValidatorError;
|
|
1419
|
-
err = new ErrorConstructor(validatorProperties);
|
|
1420
|
-
err[validatorErrorSymbol] = true;
|
|
1421
|
+
break;
|
|
1421
1422
|
}
|
|
1422
1423
|
}
|
|
1424
|
+
|
|
1425
|
+
return err;
|
|
1423
1426
|
};
|
|
1424
1427
|
|
|
1425
1428
|
/**
|
|
@@ -1630,7 +1633,7 @@ SchemaType.prototype._castForQuery = function(val) {
|
|
|
1630
1633
|
*/
|
|
1631
1634
|
|
|
1632
1635
|
SchemaType.checkRequired = function(fn) {
|
|
1633
|
-
if (arguments.length
|
|
1636
|
+
if (arguments.length !== 0) {
|
|
1634
1637
|
this._checkRequired = fn;
|
|
1635
1638
|
}
|
|
1636
1639
|
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
const EventEmitter = require('events').EventEmitter;
|
|
8
8
|
const Subdocument = require('./subdocument');
|
|
9
|
+
const utils = require('../utils');
|
|
9
10
|
|
|
10
11
|
const documentArrayParent = require('../helpers/symbols').documentArrayParent;
|
|
11
12
|
|
|
@@ -20,7 +21,7 @@ const documentArrayParent = require('../helpers/symbols').documentArrayParent;
|
|
|
20
21
|
*/
|
|
21
22
|
|
|
22
23
|
function ArraySubdocument(obj, parentArr, skipId, fields, index) {
|
|
23
|
-
if (
|
|
24
|
+
if (utils.isMongooseDocumentArray(parentArr)) {
|
|
24
25
|
this.__parentArray = parentArr;
|
|
25
26
|
this[documentArrayParent] = parentArr.$parent();
|
|
26
27
|
} else {
|
|
@@ -15,7 +15,7 @@ const arrayPathSymbol = require('../../helpers/symbols').arrayPathSymbol;
|
|
|
15
15
|
const arraySchemaSymbol = require('../../helpers/symbols').arraySchemaSymbol;
|
|
16
16
|
|
|
17
17
|
const _basePush = Array.prototype.push;
|
|
18
|
-
|
|
18
|
+
const numberRE = /^\d+$/;
|
|
19
19
|
/**
|
|
20
20
|
* DocumentArray constructor
|
|
21
21
|
*
|
|
@@ -29,7 +29,7 @@ const _basePush = Array.prototype.push;
|
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
31
|
function MongooseDocumentArray(values, path, doc) {
|
|
32
|
-
const
|
|
32
|
+
const __array = [];
|
|
33
33
|
|
|
34
34
|
const internals = {
|
|
35
35
|
[arrayAtomicsSymbol]: {},
|
|
@@ -45,10 +45,11 @@ function MongooseDocumentArray(values, path, doc) {
|
|
|
45
45
|
internals[arrayAtomicsSymbol] = Object.assign({}, values[arrayAtomicsSymbol]);
|
|
46
46
|
}
|
|
47
47
|
values.forEach(v => {
|
|
48
|
-
_basePush.call(
|
|
48
|
+
_basePush.call(__array, v);
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
51
|
internals[arrayPathSymbol] = path;
|
|
52
|
+
internals.__array = __array;
|
|
52
53
|
|
|
53
54
|
// Because doc comes from the context of another function, doc === global
|
|
54
55
|
// can happen if there was a null somewhere up the chain (see #3020 && #3034)
|
|
@@ -69,7 +70,7 @@ function MongooseDocumentArray(values, path, doc) {
|
|
|
69
70
|
}
|
|
70
71
|
}
|
|
71
72
|
|
|
72
|
-
const proxy = new Proxy(
|
|
73
|
+
const proxy = new Proxy(__array, {
|
|
73
74
|
get: function(target, prop) {
|
|
74
75
|
if (prop === 'isMongooseArray' ||
|
|
75
76
|
prop === 'isMongooseArrayProxy' ||
|
|
@@ -77,12 +78,6 @@ function MongooseDocumentArray(values, path, doc) {
|
|
|
77
78
|
prop === 'isMongooseDocumentArrayProxy') {
|
|
78
79
|
return true;
|
|
79
80
|
}
|
|
80
|
-
if (prop === '__array') {
|
|
81
|
-
return arr;
|
|
82
|
-
}
|
|
83
|
-
if (prop === 'set') {
|
|
84
|
-
return set;
|
|
85
|
-
}
|
|
86
81
|
if (internals.hasOwnProperty(prop)) {
|
|
87
82
|
return internals[prop];
|
|
88
83
|
}
|
|
@@ -93,15 +88,15 @@ function MongooseDocumentArray(values, path, doc) {
|
|
|
93
88
|
return ArrayMethods[prop];
|
|
94
89
|
}
|
|
95
90
|
|
|
96
|
-
return
|
|
91
|
+
return __array[prop];
|
|
97
92
|
},
|
|
98
93
|
set: function(target, prop, value) {
|
|
99
|
-
if (typeof prop === 'string' &&
|
|
100
|
-
set.call(proxy, prop, value);
|
|
94
|
+
if (typeof prop === 'string' && numberRE.test(prop)) {
|
|
95
|
+
DocumentArrayMethods.set.call(proxy, prop, value, false);
|
|
101
96
|
} else if (internals.hasOwnProperty(prop)) {
|
|
102
97
|
internals[prop] = value;
|
|
103
98
|
} else {
|
|
104
|
-
|
|
99
|
+
__array[prop] = value;
|
|
105
100
|
}
|
|
106
101
|
|
|
107
102
|
return true;
|
|
@@ -111,18 +106,6 @@ function MongooseDocumentArray(values, path, doc) {
|
|
|
111
106
|
return proxy;
|
|
112
107
|
}
|
|
113
108
|
|
|
114
|
-
function set(i, val, skipModified) {
|
|
115
|
-
const arr = this.__array;
|
|
116
|
-
if (skipModified) {
|
|
117
|
-
arr[i] = val;
|
|
118
|
-
return arr;
|
|
119
|
-
}
|
|
120
|
-
const value = DocumentArrayMethods._cast.call(this, val, i);
|
|
121
|
-
arr[i] = value;
|
|
122
|
-
DocumentArrayMethods._markModified.call(this, i);
|
|
123
|
-
return arr;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
109
|
/*!
|
|
127
110
|
* Module exports.
|
|
128
111
|
*/
|
|
@@ -36,7 +36,7 @@ const methods = {
|
|
|
36
36
|
}
|
|
37
37
|
let Constructor = this[arraySchemaSymbol].casterConstructor;
|
|
38
38
|
const isInstance = Constructor.$isMongooseDocumentArray ?
|
|
39
|
-
|
|
39
|
+
utils.isMongooseDocumentArray(value) :
|
|
40
40
|
value instanceof Constructor;
|
|
41
41
|
if (isInstance ||
|
|
42
42
|
// Hack re: #5001, see #5005
|
|
@@ -295,7 +295,7 @@ const methods = {
|
|
|
295
295
|
break;
|
|
296
296
|
}
|
|
297
297
|
|
|
298
|
-
if (_arr[i]
|
|
298
|
+
if (utils.isMongooseArray(_arr[i])) {
|
|
299
299
|
notify(val, _arr[i]);
|
|
300
300
|
} else if (_arr[i]) {
|
|
301
301
|
_arr[i].emit(event, val);
|
|
@@ -304,6 +304,18 @@ const methods = {
|
|
|
304
304
|
};
|
|
305
305
|
},
|
|
306
306
|
|
|
307
|
+
set(i, val, skipModified) {
|
|
308
|
+
const arr = this.__array;
|
|
309
|
+
if (skipModified) {
|
|
310
|
+
arr[i] = val;
|
|
311
|
+
return this;
|
|
312
|
+
}
|
|
313
|
+
const value = methods._cast.call(this, val, i);
|
|
314
|
+
arr[i] = value;
|
|
315
|
+
methods._markModified.call(this, i);
|
|
316
|
+
return this;
|
|
317
|
+
},
|
|
318
|
+
|
|
307
319
|
_markModified(elem, embeddedPath) {
|
|
308
320
|
const parent = this[arrayParentSymbol];
|
|
309
321
|
let dirtyPath;
|
|
@@ -326,7 +338,7 @@ const methods = {
|
|
|
326
338
|
return this;
|
|
327
339
|
}
|
|
328
340
|
|
|
329
|
-
parent.markModified(dirtyPath, arguments.length
|
|
341
|
+
parent.markModified(dirtyPath, arguments.length !== 0 ? elem : parent);
|
|
330
342
|
}
|
|
331
343
|
|
|
332
344
|
return this;
|