mongoose 8.19.4 → 9.0.0-rc0
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/eslint.config.mjs +198 -0
- package/lib/aggregate.js +17 -73
- package/lib/cast/bigint.js +1 -1
- package/lib/cast/double.js +1 -1
- package/lib/cast/uuid.js +5 -48
- package/lib/cast.js +3 -3
- package/lib/connection.js +0 -1
- package/lib/cursor/aggregationCursor.js +14 -24
- package/lib/cursor/queryCursor.js +7 -14
- package/lib/document.js +125 -121
- package/lib/drivers/node-mongodb-native/connection.js +3 -10
- package/lib/error/divergentArray.js +2 -2
- package/lib/error/objectParameter.js +1 -2
- package/lib/error/validation.js +0 -8
- package/lib/helpers/clone.js +1 -1
- package/lib/helpers/common.js +1 -1
- package/lib/helpers/discriminator/mergeDiscriminatorSchema.js +10 -0
- package/lib/helpers/indexes/isIndexEqual.js +0 -1
- package/lib/helpers/model/applyDefaultsToPOJO.js +2 -2
- package/lib/helpers/model/applyHooks.js +43 -53
- package/lib/helpers/model/applyMethods.js +2 -2
- package/lib/helpers/model/applyStaticHooks.js +1 -48
- package/lib/helpers/model/castBulkWrite.js +1 -1
- package/lib/helpers/parallelLimit.js +18 -36
- package/lib/helpers/pluralize.js +3 -3
- package/lib/helpers/populate/assignRawDocsToIdStructure.js +1 -8
- package/lib/helpers/populate/createPopulateQueryFilter.js +1 -1
- package/lib/helpers/populate/getModelsMapForPopulate.js +17 -9
- package/lib/helpers/populate/getSchemaTypes.js +5 -5
- package/lib/helpers/query/cast$expr.js +8 -10
- package/lib/helpers/query/castFilterPath.js +1 -1
- package/lib/helpers/query/castUpdate.js +15 -13
- package/lib/helpers/query/getEmbeddedDiscriminatorPath.js +1 -1
- package/lib/helpers/schema/applyPlugins.js +1 -1
- package/lib/helpers/schema/getIndexes.js +1 -7
- package/lib/helpers/timestamps/setupTimestamps.js +3 -6
- package/lib/helpers/updateValidators.js +57 -111
- package/lib/model.js +419 -607
- package/lib/mongoose.js +41 -13
- package/lib/plugins/saveSubdocs.js +24 -51
- package/lib/plugins/sharding.js +5 -4
- package/lib/plugins/validateBeforeSave.js +3 -13
- package/lib/query.js +101 -145
- package/lib/queryHelpers.js +2 -2
- package/lib/schema/array.js +46 -84
- package/lib/schema/bigint.js +4 -2
- package/lib/schema/boolean.js +4 -2
- package/lib/schema/buffer.js +4 -2
- package/lib/schema/date.js +4 -2
- package/lib/schema/decimal128.js +4 -2
- package/lib/schema/documentArray.js +66 -91
- package/lib/schema/documentArrayElement.js +18 -11
- package/lib/schema/double.js +4 -2
- package/lib/schema/int32.js +4 -2
- package/lib/schema/map.js +87 -6
- package/lib/schema/mixed.js +4 -2
- package/lib/schema/number.js +4 -2
- package/lib/schema/objectId.js +4 -2
- package/lib/schema/string.js +5 -3
- package/lib/schema/subdocument.js +27 -31
- package/lib/schema/union.js +11 -3
- package/lib/schema/uuid.js +4 -23
- package/lib/schema.js +91 -91
- package/lib/schemaType.js +67 -59
- package/lib/types/array/index.js +2 -2
- package/lib/types/array/methods/index.js +4 -4
- package/lib/types/arraySubdocument.js +1 -1
- package/lib/types/buffer.js +10 -10
- package/lib/types/decimal128.js +1 -1
- package/lib/types/documentArray/index.js +1 -1
- package/lib/types/documentArray/methods/index.js +32 -18
- package/lib/types/double.js +1 -1
- package/lib/types/map.js +1 -2
- package/lib/types/objectid.js +1 -1
- package/lib/types/subdocument.js +15 -43
- package/lib/types/uuid.js +1 -1
- package/lib/utils.js +1 -8
- package/lib/validOptions.js +3 -3
- package/package.json +11 -24
- package/types/connection.d.ts +20 -11
- package/types/document.d.ts +96 -27
- package/types/index.d.ts +143 -39
- package/types/inferhydrateddoctype.d.ts +115 -0
- package/types/inferrawdoctype.d.ts +99 -75
- package/types/inferschematype.d.ts +17 -3
- package/types/middlewares.d.ts +0 -2
- package/types/models.d.ts +131 -199
- package/types/mongooseoptions.d.ts +6 -5
- package/types/pipelinestage.d.ts +1 -1
- package/types/query.d.ts +71 -139
- package/types/schemaoptions.d.ts +1 -1
- package/types/schematypes.d.ts +14 -10
- package/types/types.d.ts +3 -4
- package/types/utility.d.ts +68 -48
- package/types/validation.d.ts +18 -14
- package/browser.js +0 -8
- package/dist/browser.umd.js +0 -2
- package/lib/browser.js +0 -141
- package/lib/browserDocument.js +0 -101
- package/lib/documentProvider.js +0 -30
- package/lib/drivers/browser/binary.js +0 -14
- package/lib/drivers/browser/decimal128.js +0 -7
- package/lib/drivers/browser/index.js +0 -13
- package/lib/drivers/browser/objectid.js +0 -29
- package/lib/helpers/promiseOrCallback.js +0 -54
package/lib/schema.js
CHANGED
|
@@ -23,6 +23,7 @@ const merge = require('./helpers/schema/merge');
|
|
|
23
23
|
const mpath = require('mpath');
|
|
24
24
|
const setPopulatedVirtualValue = require('./helpers/populate/setPopulatedVirtualValue');
|
|
25
25
|
const setupTimestamps = require('./helpers/timestamps/setupTimestamps');
|
|
26
|
+
const symbols = require('./schema/symbols');
|
|
26
27
|
const utils = require('./utils');
|
|
27
28
|
const validateRef = require('./helpers/populate/validateRef');
|
|
28
29
|
|
|
@@ -31,7 +32,7 @@ const hasNumericSubpathRegex = /\.\d+(\.|$)/;
|
|
|
31
32
|
let MongooseTypes;
|
|
32
33
|
|
|
33
34
|
const queryHooks = require('./constants').queryMiddlewareFunctions;
|
|
34
|
-
const documentHooks = require('./
|
|
35
|
+
const documentHooks = require('./constants').documentMiddlewareFunctions;
|
|
35
36
|
const hookNames = queryHooks.concat(documentHooks).
|
|
36
37
|
reduce((s, hook) => s.add(hook), new Set());
|
|
37
38
|
|
|
@@ -372,6 +373,29 @@ Schema.prototype.paths;
|
|
|
372
373
|
|
|
373
374
|
Schema.prototype.tree;
|
|
374
375
|
|
|
376
|
+
/**
|
|
377
|
+
* Creates a new schema with the given definition and options. Equivalent to `new Schema(definition, options)`.
|
|
378
|
+
*
|
|
379
|
+
* `Schema.create()` is primarily useful for automatic schema type inference in TypeScript.
|
|
380
|
+
*
|
|
381
|
+
* #### Example:
|
|
382
|
+
*
|
|
383
|
+
* const schema = Schema.create({ name: String }, { toObject: { virtuals: true } });
|
|
384
|
+
* // Equivalent:
|
|
385
|
+
* const schema2 = new Schema({ name: String }, { toObject: { virtuals: true } });
|
|
386
|
+
*
|
|
387
|
+
* @param {Object} definition
|
|
388
|
+
* @param {Object} [options]
|
|
389
|
+
* @return {Schema} the new schema
|
|
390
|
+
* @api public
|
|
391
|
+
* @memberOf Schema
|
|
392
|
+
* @static
|
|
393
|
+
*/
|
|
394
|
+
|
|
395
|
+
Schema.create = function create(definition, options) {
|
|
396
|
+
return new Schema(definition, options);
|
|
397
|
+
};
|
|
398
|
+
|
|
375
399
|
/**
|
|
376
400
|
* Returns a deep copy of the schema
|
|
377
401
|
*
|
|
@@ -660,6 +684,33 @@ Schema.prototype.discriminator = function(name, schema, options) {
|
|
|
660
684
|
return this;
|
|
661
685
|
};
|
|
662
686
|
|
|
687
|
+
/*!
|
|
688
|
+
* Get the document middleware for this schema, filtering out any hooks that are specific to queries.
|
|
689
|
+
*/
|
|
690
|
+
Schema.prototype._getDocumentMiddleware = function _getDocumentMiddleware() {
|
|
691
|
+
return this.s.hooks.
|
|
692
|
+
filter(hook => {
|
|
693
|
+
if (hook.name === 'updateOne' || hook.name === 'deleteOne') {
|
|
694
|
+
return !!hook['document'];
|
|
695
|
+
}
|
|
696
|
+
if (hook.name === 'remove' || hook.name === 'init') {
|
|
697
|
+
return hook['document'] == null || !!hook['document'];
|
|
698
|
+
}
|
|
699
|
+
if (hook.query != null || hook.document != null) {
|
|
700
|
+
return hook.document !== false;
|
|
701
|
+
}
|
|
702
|
+
return true;
|
|
703
|
+
}).
|
|
704
|
+
filter(hook => {
|
|
705
|
+
// If user has overwritten the method, don't apply built-in middleware
|
|
706
|
+
if (this.methods[hook.name]) {
|
|
707
|
+
return !hook.fn[symbols.builtInMiddleware];
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
return true;
|
|
711
|
+
});
|
|
712
|
+
};
|
|
713
|
+
|
|
663
714
|
/*!
|
|
664
715
|
* Get this schema's default toObject/toJSON options, including Mongoose global
|
|
665
716
|
* options.
|
|
@@ -1300,7 +1351,7 @@ Schema.prototype.path = function(path, obj) {
|
|
|
1300
1351
|
if (schemaType.$__schemaType.$isSingleNested) {
|
|
1301
1352
|
this.childSchemas.push({
|
|
1302
1353
|
schema: schemaType.$__schemaType.schema,
|
|
1303
|
-
model: schemaType.$__schemaType.
|
|
1354
|
+
model: schemaType.$__schemaType.Constructor,
|
|
1304
1355
|
path: path
|
|
1305
1356
|
});
|
|
1306
1357
|
}
|
|
@@ -1329,10 +1380,10 @@ Schema.prototype.path = function(path, obj) {
|
|
|
1329
1380
|
value: this.base
|
|
1330
1381
|
});
|
|
1331
1382
|
|
|
1332
|
-
schemaType.
|
|
1383
|
+
schemaType.Constructor.base = this.base;
|
|
1333
1384
|
this.childSchemas.push({
|
|
1334
1385
|
schema: schemaType.schema,
|
|
1335
|
-
model: schemaType.
|
|
1386
|
+
model: schemaType.Constructor,
|
|
1336
1387
|
path: path
|
|
1337
1388
|
});
|
|
1338
1389
|
} else if (schemaType.$isMongooseDocumentArray) {
|
|
@@ -1343,15 +1394,15 @@ Schema.prototype.path = function(path, obj) {
|
|
|
1343
1394
|
value: this.base
|
|
1344
1395
|
});
|
|
1345
1396
|
|
|
1346
|
-
schemaType.
|
|
1397
|
+
schemaType.Constructor.base = this.base;
|
|
1347
1398
|
this.childSchemas.push({
|
|
1348
1399
|
schema: schemaType.schema,
|
|
1349
|
-
model: schemaType.
|
|
1400
|
+
model: schemaType.Constructor,
|
|
1350
1401
|
path: path
|
|
1351
1402
|
});
|
|
1352
1403
|
}
|
|
1353
1404
|
|
|
1354
|
-
if (schemaType.$isMongooseArray && schemaType
|
|
1405
|
+
if (schemaType.$isMongooseArray && !schemaType.$isMongooseDocumentArray) {
|
|
1355
1406
|
let arrayPath = path;
|
|
1356
1407
|
let _schemaType = schemaType;
|
|
1357
1408
|
|
|
@@ -1359,16 +1410,9 @@ Schema.prototype.path = function(path, obj) {
|
|
|
1359
1410
|
while (_schemaType.$isMongooseArray) {
|
|
1360
1411
|
arrayPath = arrayPath + '.$';
|
|
1361
1412
|
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
_schemaType.$embeddedSchemaType._arrayParentPath = path;
|
|
1366
|
-
_schemaType = _schemaType.$embeddedSchemaType;
|
|
1367
|
-
} else {
|
|
1368
|
-
_schemaType.caster._arrayPath = arrayPath;
|
|
1369
|
-
_schemaType.caster._arrayParentPath = path;
|
|
1370
|
-
_schemaType = _schemaType.caster;
|
|
1371
|
-
}
|
|
1413
|
+
_schemaType.embeddedSchemaType._arrayPath = arrayPath;
|
|
1414
|
+
_schemaType.embeddedSchemaType._arrayParentPath = path;
|
|
1415
|
+
_schemaType = _schemaType.embeddedSchemaType;
|
|
1372
1416
|
|
|
1373
1417
|
this.subpaths[arrayPath] = _schemaType;
|
|
1374
1418
|
}
|
|
@@ -1420,13 +1464,13 @@ Schema.prototype._gatherChildSchemas = function _gatherChildSchemas() {
|
|
|
1420
1464
|
if (schematype.$isMongooseDocumentArray || schematype.$isSingleNested) {
|
|
1421
1465
|
childSchemas.push({
|
|
1422
1466
|
schema: schematype.schema,
|
|
1423
|
-
model: schematype.
|
|
1467
|
+
model: schematype.Constructor,
|
|
1424
1468
|
path: path
|
|
1425
1469
|
});
|
|
1426
1470
|
} else if (schematype.$isSchemaMap && schematype.$__schemaType.$isSingleNested) {
|
|
1427
1471
|
childSchemas.push({
|
|
1428
1472
|
schema: schematype.$__schemaType.schema,
|
|
1429
|
-
model: schematype.$__schemaType.
|
|
1473
|
+
model: schematype.$__schemaType.Constructor,
|
|
1430
1474
|
path: path
|
|
1431
1475
|
});
|
|
1432
1476
|
}
|
|
@@ -1572,7 +1616,7 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
|
|
|
1572
1616
|
let name;
|
|
1573
1617
|
|
|
1574
1618
|
if (utils.isPOJO(type) || type === 'mixed') {
|
|
1575
|
-
return new MongooseTypes.Mixed(path, obj);
|
|
1619
|
+
return new MongooseTypes.Mixed(path, obj, null, this);
|
|
1576
1620
|
}
|
|
1577
1621
|
|
|
1578
1622
|
if (Array.isArray(type) || type === Array || type === 'array' || type === MongooseTypes.Array) {
|
|
@@ -1595,7 +1639,7 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
|
|
|
1595
1639
|
`${path}: new Schema(...)`);
|
|
1596
1640
|
}
|
|
1597
1641
|
}
|
|
1598
|
-
return new MongooseTypes.DocumentArray(path, cast, obj);
|
|
1642
|
+
return new MongooseTypes.DocumentArray(path, cast, obj, null, this);
|
|
1599
1643
|
}
|
|
1600
1644
|
if (cast &&
|
|
1601
1645
|
cast[options.typeKey] &&
|
|
@@ -1612,14 +1656,14 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
|
|
|
1612
1656
|
`${path}: new Schema(...)`);
|
|
1613
1657
|
}
|
|
1614
1658
|
}
|
|
1615
|
-
return new MongooseTypes.DocumentArray(path, cast[options.typeKey], obj, cast);
|
|
1659
|
+
return new MongooseTypes.DocumentArray(path, cast[options.typeKey], obj, cast, this);
|
|
1616
1660
|
}
|
|
1617
1661
|
if (typeof cast !== 'undefined') {
|
|
1618
1662
|
if (Array.isArray(cast) || cast.type === Array || cast.type == 'Array') {
|
|
1619
1663
|
if (cast && cast.type == 'Array') {
|
|
1620
1664
|
cast.type = Array;
|
|
1621
1665
|
}
|
|
1622
|
-
return new MongooseTypes.Array(path, this.interpretAsType(path, cast, options), obj);
|
|
1666
|
+
return new MongooseTypes.Array(path, this.interpretAsType(path, cast, options), obj, null, this);
|
|
1623
1667
|
}
|
|
1624
1668
|
}
|
|
1625
1669
|
|
|
@@ -1660,10 +1704,10 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
|
|
|
1660
1704
|
|
|
1661
1705
|
const childSchema = new Schema(castFromTypeKey, childSchemaOptions);
|
|
1662
1706
|
childSchema.$implicitlyCreated = true;
|
|
1663
|
-
return new MongooseTypes.DocumentArray(path, childSchema, obj);
|
|
1707
|
+
return new MongooseTypes.DocumentArray(path, childSchema, obj, null, this);
|
|
1664
1708
|
} else {
|
|
1665
1709
|
// Special case: empty object becomes mixed
|
|
1666
|
-
return new MongooseTypes.Array(path, MongooseTypes.Mixed, obj);
|
|
1710
|
+
return new MongooseTypes.Array(path, MongooseTypes.Mixed, obj, null, this);
|
|
1667
1711
|
}
|
|
1668
1712
|
}
|
|
1669
1713
|
|
|
@@ -1672,7 +1716,7 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
|
|
|
1672
1716
|
? cast[options.typeKey]
|
|
1673
1717
|
: cast;
|
|
1674
1718
|
if (Array.isArray(type)) {
|
|
1675
|
-
return new MongooseTypes.Array(path, this.interpretAsType(path, type, options), obj);
|
|
1719
|
+
return new MongooseTypes.Array(path, this.interpretAsType(path, type, options), obj, null, this);
|
|
1676
1720
|
}
|
|
1677
1721
|
|
|
1678
1722
|
name = typeof type === 'string'
|
|
@@ -1700,11 +1744,11 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
|
|
|
1700
1744
|
}
|
|
1701
1745
|
}
|
|
1702
1746
|
|
|
1703
|
-
return new MongooseTypes.Array(path, cast || MongooseTypes.Mixed, obj, options);
|
|
1747
|
+
return new MongooseTypes.Array(path, cast || MongooseTypes.Mixed, obj, options, this);
|
|
1704
1748
|
}
|
|
1705
1749
|
|
|
1706
1750
|
if (type && type.instanceOfSchema) {
|
|
1707
|
-
return new MongooseTypes.Subdocument(type, path, obj);
|
|
1751
|
+
return new MongooseTypes.Subdocument(type, path, obj, this);
|
|
1708
1752
|
}
|
|
1709
1753
|
|
|
1710
1754
|
if (Buffer.isBuffer(type)) {
|
|
@@ -1743,53 +1787,11 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
|
|
|
1743
1787
|
'https://bit.ly/mongoose-schematypes for a list of valid schema types.');
|
|
1744
1788
|
}
|
|
1745
1789
|
|
|
1746
|
-
|
|
1747
|
-
obj.parentSchema = this;
|
|
1748
|
-
}
|
|
1749
|
-
const schemaType = new MongooseTypes[name](path, obj, options);
|
|
1750
|
-
|
|
1751
|
-
if (schemaType.$isSchemaMap) {
|
|
1752
|
-
createMapNestedSchemaType(this, schemaType, path, obj, options);
|
|
1753
|
-
}
|
|
1790
|
+
const schemaType = new MongooseTypes[name](path, obj, options, this);
|
|
1754
1791
|
|
|
1755
1792
|
return schemaType;
|
|
1756
1793
|
};
|
|
1757
1794
|
|
|
1758
|
-
/*!
|
|
1759
|
-
* ignore
|
|
1760
|
-
*/
|
|
1761
|
-
|
|
1762
|
-
function createMapNestedSchemaType(schema, schemaType, path, obj, options) {
|
|
1763
|
-
const mapPath = path + '.$*';
|
|
1764
|
-
let _mapType = { type: {} };
|
|
1765
|
-
if (utils.hasUserDefinedProperty(obj, 'of')) {
|
|
1766
|
-
const isInlineSchema = utils.isPOJO(obj.of) &&
|
|
1767
|
-
Object.keys(obj.of).length > 0 &&
|
|
1768
|
-
!utils.hasUserDefinedProperty(obj.of, schema.options.typeKey);
|
|
1769
|
-
if (isInlineSchema) {
|
|
1770
|
-
_mapType = { [schema.options.typeKey]: new Schema(obj.of) };
|
|
1771
|
-
} else if (utils.isPOJO(obj.of)) {
|
|
1772
|
-
_mapType = Object.assign({}, obj.of);
|
|
1773
|
-
} else {
|
|
1774
|
-
_mapType = { [schema.options.typeKey]: obj.of };
|
|
1775
|
-
}
|
|
1776
|
-
|
|
1777
|
-
if (_mapType[schema.options.typeKey] && _mapType[schema.options.typeKey].instanceOfSchema) {
|
|
1778
|
-
const subdocumentSchema = _mapType[schema.options.typeKey];
|
|
1779
|
-
subdocumentSchema.eachPath((subpath, type) => {
|
|
1780
|
-
if (type.options.select === true || type.options.select === false) {
|
|
1781
|
-
throw new MongooseError('Cannot use schema-level projections (`select: true` or `select: false`) within maps at path "' + path + '.' + subpath + '"');
|
|
1782
|
-
}
|
|
1783
|
-
});
|
|
1784
|
-
}
|
|
1785
|
-
|
|
1786
|
-
if (utils.hasUserDefinedProperty(obj, 'ref')) {
|
|
1787
|
-
_mapType.ref = obj.ref;
|
|
1788
|
-
}
|
|
1789
|
-
}
|
|
1790
|
-
schemaType.$__schemaType = schema.interpretAsType(mapPath, _mapType, options);
|
|
1791
|
-
}
|
|
1792
|
-
|
|
1793
1795
|
/**
|
|
1794
1796
|
* Iterates the schemas paths similar to Array#forEach.
|
|
1795
1797
|
*
|
|
@@ -1987,10 +1989,10 @@ function getPositionalPathType(self, path, cleanPath) {
|
|
|
1987
1989
|
|
|
1988
1990
|
if (i === last && val && !/\D/.test(subpath)) {
|
|
1989
1991
|
if (val.$isMongooseDocumentArray) {
|
|
1990
|
-
val = val
|
|
1992
|
+
val = val.embeddedSchemaType;
|
|
1991
1993
|
} else if (val instanceof MongooseTypes.Array) {
|
|
1992
1994
|
// StringSchema, NumberSchema, etc
|
|
1993
|
-
val = val.
|
|
1995
|
+
val = val.embeddedSchemaType;
|
|
1994
1996
|
} else {
|
|
1995
1997
|
val = undefined;
|
|
1996
1998
|
}
|
|
@@ -2001,7 +2003,7 @@ function getPositionalPathType(self, path, cleanPath) {
|
|
|
2001
2003
|
if (!/\D/.test(subpath)) {
|
|
2002
2004
|
// Nested array
|
|
2003
2005
|
if (val instanceof MongooseTypes.Array && i !== last) {
|
|
2004
|
-
val = val.
|
|
2006
|
+
val = val.embeddedSchemaType;
|
|
2005
2007
|
}
|
|
2006
2008
|
continue;
|
|
2007
2009
|
}
|
|
@@ -2064,23 +2066,21 @@ Schema.prototype.queue = function(name, args) {
|
|
|
2064
2066
|
*
|
|
2065
2067
|
* const toySchema = new Schema({ name: String, created: Date });
|
|
2066
2068
|
*
|
|
2067
|
-
* toySchema.pre('save', function(
|
|
2069
|
+
* toySchema.pre('save', function() {
|
|
2068
2070
|
* if (!this.created) this.created = new Date;
|
|
2069
|
-
* next();
|
|
2070
2071
|
* });
|
|
2071
2072
|
*
|
|
2072
|
-
* toySchema.pre('validate', function(
|
|
2073
|
+
* toySchema.pre('validate', function() {
|
|
2073
2074
|
* if (this.name !== 'Woody') this.name = 'Woody';
|
|
2074
|
-
* next();
|
|
2075
2075
|
* });
|
|
2076
2076
|
*
|
|
2077
2077
|
* // Equivalent to calling `pre()` on `find`, `findOne`, `findOneAndUpdate`.
|
|
2078
|
-
* toySchema.pre(/^find/, function(
|
|
2078
|
+
* toySchema.pre(/^find/, function() {
|
|
2079
2079
|
* console.log(this.getFilter());
|
|
2080
2080
|
* });
|
|
2081
2081
|
*
|
|
2082
2082
|
* // Equivalent to calling `pre()` on `updateOne`, `findOneAndUpdate`.
|
|
2083
|
-
* toySchema.pre(['updateOne', 'findOneAndUpdate'], function(
|
|
2083
|
+
* toySchema.pre(['updateOne', 'findOneAndUpdate'], function() {
|
|
2084
2084
|
* console.log(this.getFilter());
|
|
2085
2085
|
* });
|
|
2086
2086
|
*
|
|
@@ -2497,8 +2497,8 @@ Object.defineProperty(Schema, 'indexTypes', {
|
|
|
2497
2497
|
* registeredAt: { type: Date, index: true }
|
|
2498
2498
|
* });
|
|
2499
2499
|
*
|
|
2500
|
-
* // [ [ { email: 1 }, { unique: true
|
|
2501
|
-
* // [ { registeredAt: 1 }, {
|
|
2500
|
+
* // [ [ { email: 1 }, { unique: true } ],
|
|
2501
|
+
* // [ { registeredAt: 1 }, {} ] ]
|
|
2502
2502
|
* userSchema.indexes();
|
|
2503
2503
|
*
|
|
2504
2504
|
* [Plugins](https://mongoosejs.com/docs/plugins.html) can use the return value of this function to modify a schema's indexes.
|
|
@@ -2896,11 +2896,11 @@ Schema.prototype._getSchema = function(path) {
|
|
|
2896
2896
|
if (foundschema) {
|
|
2897
2897
|
resultPath.push(trypath);
|
|
2898
2898
|
|
|
2899
|
-
if (foundschema.
|
|
2899
|
+
if (foundschema.embeddedSchemaType || foundschema.Constructor) {
|
|
2900
2900
|
// array of Mixed?
|
|
2901
|
-
if (foundschema.
|
|
2902
|
-
foundschema.
|
|
2903
|
-
return foundschema.
|
|
2901
|
+
if (foundschema.embeddedSchemaType instanceof MongooseTypes.Mixed) {
|
|
2902
|
+
foundschema.embeddedSchemaType.$fullPath = resultPath.join('.');
|
|
2903
|
+
return foundschema.embeddedSchemaType;
|
|
2904
2904
|
}
|
|
2905
2905
|
|
|
2906
2906
|
// Now that we found the array, we need to check if there
|
|
@@ -2910,8 +2910,8 @@ Schema.prototype._getSchema = function(path) {
|
|
|
2910
2910
|
// If there is no foundschema.schema we are dealing with
|
|
2911
2911
|
// a path like array.$
|
|
2912
2912
|
if (p !== parts.length) {
|
|
2913
|
-
if (p + 1 === parts.length && foundschema
|
|
2914
|
-
return foundschema
|
|
2913
|
+
if (p + 1 === parts.length && foundschema.embeddedSchemaType && (parts[p] === '$' || isArrayFilter(parts[p]))) {
|
|
2914
|
+
return foundschema.embeddedSchemaType;
|
|
2915
2915
|
}
|
|
2916
2916
|
|
|
2917
2917
|
if (foundschema.schema) {
|
|
@@ -2919,7 +2919,7 @@ Schema.prototype._getSchema = function(path) {
|
|
|
2919
2919
|
if (parts[p] === '$' || isArrayFilter(parts[p])) {
|
|
2920
2920
|
if (p + 1 === parts.length) {
|
|
2921
2921
|
// comments.$
|
|
2922
|
-
return foundschema
|
|
2922
|
+
return foundschema.embeddedSchemaType;
|
|
2923
2923
|
}
|
|
2924
2924
|
// comments.$.comments.$.title
|
|
2925
2925
|
ret = search(parts.slice(p + 1), foundschema.schema);
|
|
@@ -2999,9 +2999,9 @@ Schema.prototype._getPathType = function(path) {
|
|
|
2999
2999
|
trypath = parts.slice(0, p).join('.');
|
|
3000
3000
|
foundschema = schema.path(trypath);
|
|
3001
3001
|
if (foundschema) {
|
|
3002
|
-
if (foundschema.
|
|
3002
|
+
if (foundschema.embeddedSchemaType || foundschema.Constructor) {
|
|
3003
3003
|
// array of Mixed?
|
|
3004
|
-
if (foundschema.
|
|
3004
|
+
if (foundschema.embeddedSchemaType instanceof MongooseTypes.Mixed) {
|
|
3005
3005
|
return { schema: foundschema, pathType: 'mixed' };
|
|
3006
3006
|
}
|
|
3007
3007
|
|
package/lib/schemaType.js
CHANGED
|
@@ -12,7 +12,6 @@ const clone = require('./helpers/clone');
|
|
|
12
12
|
const handleImmutable = require('./helpers/schematype/handleImmutable');
|
|
13
13
|
const isAsyncFunction = require('./helpers/isAsyncFunction');
|
|
14
14
|
const isSimpleValidator = require('./helpers/isSimpleValidator');
|
|
15
|
-
const immediate = require('./helpers/immediate');
|
|
16
15
|
const schemaTypeSymbol = require('./helpers/symbols').schemaTypeSymbol;
|
|
17
16
|
const utils = require('./utils');
|
|
18
17
|
const validatorErrorSymbol = require('./helpers/symbols').validatorErrorSymbol;
|
|
@@ -37,10 +36,11 @@ const setOptionsForDefaults = { _skipMarkModified: true };
|
|
|
37
36
|
* @param {String} path
|
|
38
37
|
* @param {SchemaTypeOptions} [options] See [SchemaTypeOptions docs](https://mongoosejs.com/docs/api/schematypeoptions.html)
|
|
39
38
|
* @param {String} [instance]
|
|
39
|
+
* @param {Schema} [parentSchema]
|
|
40
40
|
* @api public
|
|
41
41
|
*/
|
|
42
42
|
|
|
43
|
-
function SchemaType(path, options, instance) {
|
|
43
|
+
function SchemaType(path, options, instance, parentSchema) {
|
|
44
44
|
this[schemaTypeSymbol] = true;
|
|
45
45
|
this.path = path;
|
|
46
46
|
this.instance = instance;
|
|
@@ -73,6 +73,7 @@ function SchemaType(path, options, instance) {
|
|
|
73
73
|
|
|
74
74
|
const Options = this.OptionsConstructor || SchemaTypeOptions;
|
|
75
75
|
this.options = new Options(options);
|
|
76
|
+
this.parentSchema = parentSchema;
|
|
76
77
|
this._index = null;
|
|
77
78
|
|
|
78
79
|
if (utils.hasUserDefinedProperty(this.options, 'immutable')) {
|
|
@@ -157,6 +158,30 @@ SchemaType.prototype.OptionsConstructor = SchemaTypeOptions;
|
|
|
157
158
|
|
|
158
159
|
SchemaType.prototype.path;
|
|
159
160
|
|
|
161
|
+
/**
|
|
162
|
+
* Returns a plain JavaScript object representing this SchemaType.
|
|
163
|
+
*
|
|
164
|
+
* Typically used by `JSON.stringify()` or when calling `.toJSON()` on a SchemaType instance.
|
|
165
|
+
* Omits certain internal properties such as `parentSchema` that can cause circular references.
|
|
166
|
+
*
|
|
167
|
+
* #### Example:
|
|
168
|
+
*
|
|
169
|
+
* const schema = new Schema({ name: String });
|
|
170
|
+
* const schematype = schema.path('name');
|
|
171
|
+
* console.log(schematype.toJSON());
|
|
172
|
+
*
|
|
173
|
+
* @function toJSON
|
|
174
|
+
* @memberOf SchemaType
|
|
175
|
+
* @instance
|
|
176
|
+
* @api public
|
|
177
|
+
*/
|
|
178
|
+
|
|
179
|
+
SchemaType.prototype.toJSON = function toJSON() {
|
|
180
|
+
const res = { ...this };
|
|
181
|
+
delete res.parentSchema;
|
|
182
|
+
return res;
|
|
183
|
+
};
|
|
184
|
+
|
|
160
185
|
/**
|
|
161
186
|
* The validators that Mongoose should run to validate properties at this SchemaType's path.
|
|
162
187
|
*
|
|
@@ -419,13 +444,6 @@ SchemaType.prototype.default = function(val) {
|
|
|
419
444
|
* s.path('my.date').index({ expires: 60 });
|
|
420
445
|
* s.path('my.path').index({ unique: true, sparse: true });
|
|
421
446
|
*
|
|
422
|
-
* #### Note:
|
|
423
|
-
*
|
|
424
|
-
* _Indexes are created [in the background](https://www.mongodb.com/docs/manual/core/index-creation/#index-creation-background)
|
|
425
|
-
* by default. If `background` is set to `false`, MongoDB will not execute any
|
|
426
|
-
* read/write operations you send until the index build.
|
|
427
|
-
* Specify `background: false` to override Mongoose's default._
|
|
428
|
-
*
|
|
429
447
|
* @param {Object|Boolean|String|Number} options
|
|
430
448
|
* @return {SchemaType} this
|
|
431
449
|
* @api public
|
|
@@ -1315,7 +1333,6 @@ SchemaType.prototype.select = function select(val) {
|
|
|
1315
1333
|
* Performs a validation of `value` using the validators declared for this SchemaType.
|
|
1316
1334
|
*
|
|
1317
1335
|
* @param {Any} value
|
|
1318
|
-
* @param {Function} callback
|
|
1319
1336
|
* @param {Object} scope
|
|
1320
1337
|
* @param {Object} [options]
|
|
1321
1338
|
* @param {String} [options.path]
|
|
@@ -1323,28 +1340,20 @@ SchemaType.prototype.select = function select(val) {
|
|
|
1323
1340
|
* @api public
|
|
1324
1341
|
*/
|
|
1325
1342
|
|
|
1326
|
-
SchemaType.prototype.doValidate = function(value,
|
|
1343
|
+
SchemaType.prototype.doValidate = async function doValidate(value, scope, options) {
|
|
1327
1344
|
let err = false;
|
|
1328
1345
|
const path = this.path;
|
|
1329
|
-
if (typeof fn !== 'function') {
|
|
1330
|
-
throw new TypeError(`Must pass callback function to doValidate(), got ${typeof fn}`);
|
|
1331
|
-
}
|
|
1332
1346
|
|
|
1333
1347
|
// Avoid non-object `validators`
|
|
1334
1348
|
const validators = this.validators.
|
|
1335
1349
|
filter(v => typeof v === 'object' && v !== null);
|
|
1336
1350
|
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
if (!count) {
|
|
1340
|
-
return fn(null);
|
|
1351
|
+
if (!validators.length) {
|
|
1352
|
+
return;
|
|
1341
1353
|
}
|
|
1342
1354
|
|
|
1355
|
+
const promises = [];
|
|
1343
1356
|
for (let i = 0, len = validators.length; i < len; ++i) {
|
|
1344
|
-
if (err) {
|
|
1345
|
-
break;
|
|
1346
|
-
}
|
|
1347
|
-
|
|
1348
1357
|
const v = validators[i];
|
|
1349
1358
|
const validator = v.validator;
|
|
1350
1359
|
let ok;
|
|
@@ -1360,17 +1369,19 @@ SchemaType.prototype.doValidate = function(value, fn, scope, options) {
|
|
|
1360
1369
|
}
|
|
1361
1370
|
}
|
|
1362
1371
|
|
|
1363
|
-
if (validator
|
|
1364
|
-
validate(validator.test(value), validatorProperties, scope);
|
|
1372
|
+
if (value === undefined && validator !== this.requiredValidator) {
|
|
1365
1373
|
continue;
|
|
1366
1374
|
}
|
|
1367
|
-
|
|
1368
|
-
|
|
1375
|
+
if (validator instanceof RegExp) {
|
|
1376
|
+
ok = validator.test(value);
|
|
1377
|
+
if (ok === false) {
|
|
1378
|
+
const ErrorConstructor = validatorProperties.ErrorConstructor || ValidatorError;
|
|
1379
|
+
err = new ErrorConstructor(validatorProperties, scope);
|
|
1380
|
+
err[validatorErrorSymbol] = true;
|
|
1381
|
+
throw err;
|
|
1382
|
+
}
|
|
1369
1383
|
continue;
|
|
1370
|
-
}
|
|
1371
|
-
|
|
1372
|
-
if (value === undefined && validator !== this.requiredValidator) {
|
|
1373
|
-
validate(true, validatorProperties, scope);
|
|
1384
|
+
} else if (typeof validator !== 'function') {
|
|
1374
1385
|
continue;
|
|
1375
1386
|
}
|
|
1376
1387
|
|
|
@@ -1389,38 +1400,35 @@ SchemaType.prototype.doValidate = function(value, fn, scope, options) {
|
|
|
1389
1400
|
}
|
|
1390
1401
|
|
|
1391
1402
|
if (ok != null && typeof ok.then === 'function') {
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
});
|
|
1414
|
-
}
|
|
1415
|
-
} else {
|
|
1403
|
+
promises.push(
|
|
1404
|
+
ok.then(
|
|
1405
|
+
function(ok) {
|
|
1406
|
+
if (ok === false) {
|
|
1407
|
+
const ErrorConstructor = validatorProperties.ErrorConstructor || ValidatorError;
|
|
1408
|
+
err = new ErrorConstructor(validatorProperties, scope);
|
|
1409
|
+
err[validatorErrorSymbol] = true;
|
|
1410
|
+
throw err;
|
|
1411
|
+
}
|
|
1412
|
+
},
|
|
1413
|
+
function(error) {
|
|
1414
|
+
validatorProperties.reason = error;
|
|
1415
|
+
validatorProperties.message = error.message;
|
|
1416
|
+
ok = false;
|
|
1417
|
+
const ErrorConstructor = validatorProperties.ErrorConstructor || ValidatorError;
|
|
1418
|
+
err = new ErrorConstructor(validatorProperties, scope);
|
|
1419
|
+
err[validatorErrorSymbol] = true;
|
|
1420
|
+
throw err;
|
|
1421
|
+
})
|
|
1422
|
+
);
|
|
1423
|
+
} else if (ok !== undefined && !ok) {
|
|
1416
1424
|
const ErrorConstructor = validatorProperties.ErrorConstructor || ValidatorError;
|
|
1417
1425
|
err = new ErrorConstructor(validatorProperties, scope);
|
|
1418
1426
|
err[validatorErrorSymbol] = true;
|
|
1419
|
-
|
|
1420
|
-
fn(err);
|
|
1421
|
-
});
|
|
1427
|
+
throw err;
|
|
1422
1428
|
}
|
|
1423
1429
|
}
|
|
1430
|
+
|
|
1431
|
+
await Promise.all(promises);
|
|
1424
1432
|
};
|
|
1425
1433
|
|
|
1426
1434
|
|
|
@@ -1751,7 +1759,7 @@ SchemaType.prototype.checkRequired = function(val) {
|
|
|
1751
1759
|
|
|
1752
1760
|
SchemaType.prototype.clone = function() {
|
|
1753
1761
|
const options = Object.assign({}, this.options);
|
|
1754
|
-
const schematype = new this.constructor(this.path, options, this.instance);
|
|
1762
|
+
const schematype = new this.constructor(this.path, options, this.instance, this.parentSchema);
|
|
1755
1763
|
schematype.validators = this.validators.slice();
|
|
1756
1764
|
if (this.requiredValidator !== undefined) schematype.requiredValidator = this.requiredValidator;
|
|
1757
1765
|
if (this.defaultValue !== undefined) schematype.defaultValue = this.defaultValue;
|
|
@@ -1785,7 +1793,7 @@ SchemaType.prototype.clone = function() {
|
|
|
1785
1793
|
*/
|
|
1786
1794
|
|
|
1787
1795
|
SchemaType.prototype.getEmbeddedSchemaType = function getEmbeddedSchemaType() {
|
|
1788
|
-
return this
|
|
1796
|
+
return this.embeddedSchemaType;
|
|
1789
1797
|
};
|
|
1790
1798
|
|
|
1791
1799
|
/*!
|
package/lib/types/array/index.js
CHANGED
|
@@ -88,8 +88,8 @@ function MongooseArray(values, path, doc, schematype) {
|
|
|
88
88
|
if (schematype && schematype.virtuals && schematype.virtuals.hasOwnProperty(prop)) {
|
|
89
89
|
return schematype.virtuals[prop].applyGetters(undefined, target);
|
|
90
90
|
}
|
|
91
|
-
if (typeof prop === 'string' && numberRE.test(prop) && schematype
|
|
92
|
-
return schematype
|
|
91
|
+
if (typeof prop === 'string' && numberRE.test(prop) && schematype?.embeddedSchemaType != null) {
|
|
92
|
+
return schematype.embeddedSchemaType.applyGetters(__array[prop], doc);
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
return __array[prop];
|
|
@@ -251,10 +251,10 @@ const methods = {
|
|
|
251
251
|
if (!isDisc) {
|
|
252
252
|
value = new Model(value);
|
|
253
253
|
}
|
|
254
|
-
return this[arraySchemaSymbol].
|
|
254
|
+
return this[arraySchemaSymbol].embeddedSchemaType.applySetters(value, parent, true);
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
-
return this[arraySchemaSymbol].
|
|
257
|
+
return this[arraySchemaSymbol].embeddedSchemaType.applySetters(value, parent, false);
|
|
258
258
|
},
|
|
259
259
|
|
|
260
260
|
/**
|
|
@@ -1007,7 +1007,7 @@ function _minimizePath(obj, parts, i) {
|
|
|
1007
1007
|
function _checkManualPopulation(arr, docs) {
|
|
1008
1008
|
const ref = arr == null ?
|
|
1009
1009
|
null :
|
|
1010
|
-
arr[arraySchemaSymbol]
|
|
1010
|
+
arr[arraySchemaSymbol]?.embeddedSchemaType?.options?.ref || null;
|
|
1011
1011
|
if (arr.length === 0 &&
|
|
1012
1012
|
docs.length !== 0) {
|
|
1013
1013
|
if (_isAllSubdocs(docs, ref)) {
|
|
@@ -1025,7 +1025,7 @@ function _checkManualPopulation(arr, docs) {
|
|
|
1025
1025
|
function _depopulateIfNecessary(arr, docs) {
|
|
1026
1026
|
const ref = arr == null ?
|
|
1027
1027
|
null :
|
|
1028
|
-
arr[arraySchemaSymbol]
|
|
1028
|
+
arr[arraySchemaSymbol]?.embeddedSchemaType?.options?.ref || null;
|
|
1029
1029
|
const parentDoc = arr[arrayParentSymbol];
|
|
1030
1030
|
const path = arr[arrayPathSymbol];
|
|
1031
1031
|
if (!ref || !parentDoc.populated(path)) {
|
|
@@ -41,7 +41,7 @@ function ArraySubdocument(obj, parentArr, skipId, fields, index) {
|
|
|
41
41
|
options = { isNew: true };
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
Subdocument.call(this, obj, fields, this[documentArrayParent],
|
|
44
|
+
Subdocument.call(this, obj, fields, this[documentArrayParent], options);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
/*!
|