mongoose 9.6.3 → 9.7.0
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/lib/aggregate.js +50 -23
- package/lib/connection.js +1 -1
- package/lib/cursor/aggregationCursor.js +47 -16
- package/lib/cursor/queryCursor.js +23 -7
- package/lib/document.js +20 -4
- package/lib/error/divergentArray.js +1 -1
- package/lib/helpers/populate/getModelsMapForPopulate.js +5 -1
- package/lib/model.js +95 -17
- package/lib/query.js +44 -28
- package/lib/schema/date.js +7 -5
- package/lib/schema/documentArray.js +1 -1
- package/lib/schema/subdocument.js +1 -1
- package/lib/schema/union.js +2 -2
- package/lib/schemaType.js +2 -1
- package/lib/standardSchema/convertErrorToIssues.js +20 -0
- package/lib/tracing.js +38 -0
- package/package.json +6 -6
- package/types/document.d.ts +21 -4
- package/types/index.d.ts +1 -0
- package/types/models.d.ts +42 -4
- package/types/tracing.d.ts +10 -0
package/lib/aggregate.js
CHANGED
|
@@ -15,6 +15,8 @@ const { buildMiddlewareFilter } = require('./helpers/buildMiddlewareFilter');
|
|
|
15
15
|
const stringifyFunctionOperators = require('./helpers/aggregate/stringifyFunctionOperators');
|
|
16
16
|
const utils = require('./utils');
|
|
17
17
|
const { modelSymbol } = require('./helpers/symbols');
|
|
18
|
+
const { createTracedChannel } = require('./tracing');
|
|
19
|
+
const { trace: traceAggregate } = createTracedChannel('mongoose:aggregate');
|
|
18
20
|
const read = Query.prototype.read;
|
|
19
21
|
const readConcern = Query.prototype.readConcern;
|
|
20
22
|
|
|
@@ -1071,8 +1073,20 @@ Aggregate.prototype.exec = async function exec() {
|
|
|
1071
1073
|
|
|
1072
1074
|
this._optionsForExec();
|
|
1073
1075
|
|
|
1074
|
-
const
|
|
1075
|
-
return
|
|
1076
|
+
const _this = this;
|
|
1077
|
+
return traceAggregate(async function maybeTracedConnectionAggregate() {
|
|
1078
|
+
const cursor = await _this._connection.client.db().aggregate(_this._pipeline, _this.options);
|
|
1079
|
+
return await cursor.toArray();
|
|
1080
|
+
}, () => ({
|
|
1081
|
+
operation: 'aggregate',
|
|
1082
|
+
database: _this._connection.name,
|
|
1083
|
+
serverAddress: _this._connection.host,
|
|
1084
|
+
serverPort: _this._connection.port,
|
|
1085
|
+
args: {
|
|
1086
|
+
pipeline: _this._pipeline,
|
|
1087
|
+
options: _this.options
|
|
1088
|
+
}
|
|
1089
|
+
}));
|
|
1076
1090
|
}
|
|
1077
1091
|
|
|
1078
1092
|
const model = this._model;
|
|
@@ -1090,32 +1104,45 @@ Aggregate.prototype.exec = async function exec() {
|
|
|
1090
1104
|
prepareDiscriminatorPipeline(this._pipeline, this._model.schema);
|
|
1091
1105
|
stringifyFunctionOperators(this._pipeline);
|
|
1092
1106
|
|
|
1093
|
-
const
|
|
1094
|
-
|
|
1107
|
+
const _this = this;
|
|
1108
|
+
return traceAggregate(async function maybeTracedAggregateExec() {
|
|
1109
|
+
const preFilter = buildMiddlewareFilter(_this.options, 'pre');
|
|
1110
|
+
const postFilter = buildMiddlewareFilter(_this.options, 'post');
|
|
1095
1111
|
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1112
|
+
try {
|
|
1113
|
+
await model.hooks.execPre('aggregate', _this, [], { filter: preFilter });
|
|
1114
|
+
} catch (error) {
|
|
1115
|
+
return await model.hooks.execPost('aggregate', _this, [null], { error, filter: postFilter });
|
|
1116
|
+
}
|
|
1101
1117
|
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1118
|
+
if (!_this._pipeline.length) {
|
|
1119
|
+
throw new MongooseError('Aggregate has empty pipeline');
|
|
1120
|
+
}
|
|
1105
1121
|
|
|
1106
|
-
|
|
1107
|
-
|
|
1122
|
+
const options = clone(_this.options || {});
|
|
1123
|
+
delete options.middleware;
|
|
1108
1124
|
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1125
|
+
let result;
|
|
1126
|
+
try {
|
|
1127
|
+
const cursor = await collection.aggregate(_this._pipeline, options);
|
|
1128
|
+
result = await cursor.toArray();
|
|
1129
|
+
} catch (error) {
|
|
1130
|
+
return await model.hooks.execPost('aggregate', _this, [null], { error, filter: postFilter });
|
|
1131
|
+
}
|
|
1116
1132
|
|
|
1117
|
-
|
|
1118
|
-
|
|
1133
|
+
await model.hooks.execPost('aggregate', _this, [result], { error: null, filter: postFilter });
|
|
1134
|
+
return result;
|
|
1135
|
+
}, () => ({
|
|
1136
|
+
operation: 'aggregate',
|
|
1137
|
+
collection: collection.name,
|
|
1138
|
+
database: model.db?.name,
|
|
1139
|
+
serverAddress: model.db?.host,
|
|
1140
|
+
serverPort: model.db?.port,
|
|
1141
|
+
args: {
|
|
1142
|
+
pipeline: _this._pipeline,
|
|
1143
|
+
options: _this.options
|
|
1144
|
+
}
|
|
1145
|
+
}));
|
|
1119
1146
|
};
|
|
1120
1147
|
|
|
1121
1148
|
/**
|
package/lib/connection.js
CHANGED
|
@@ -1354,7 +1354,7 @@ Connection.prototype.onClose = function onClose(force) {
|
|
|
1354
1354
|
|
|
1355
1355
|
/**
|
|
1356
1356
|
* Retrieves a raw collection instance, creating it if not cached.
|
|
1357
|
-
* This method returns a thin wrapper around a [MongoDB Node.js driver collection](
|
|
1357
|
+
* This method returns a thin wrapper around a [MongoDB Node.js driver collection](https://mongodb.github.io/node-mongodb-native/Next/classes/Collection.html).
|
|
1358
1358
|
* Using a Collection bypasses Mongoose middleware, validation, and casting,
|
|
1359
1359
|
* letting you use [MongoDB Node.js driver](https://mongodb.github.io/node-mongodb-native/) functionality directly.
|
|
1360
1360
|
*
|
|
@@ -10,6 +10,7 @@ const eachAsync = require('../helpers/cursor/eachAsync');
|
|
|
10
10
|
const immediate = require('../helpers/immediate');
|
|
11
11
|
const kareem = require('kareem');
|
|
12
12
|
const util = require('util');
|
|
13
|
+
const { cursorNextChannel } = require('../tracing');
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* An AggregationCursor is a concurrency primitive for processing aggregation
|
|
@@ -62,13 +63,7 @@ util.inherits(AggregationCursor, Readable);
|
|
|
62
63
|
*/
|
|
63
64
|
|
|
64
65
|
function _init(model, c, agg) {
|
|
65
|
-
|
|
66
|
-
model.hooks.execPre('aggregate', agg).then(() => onPreComplete(null), err => onPreComplete(err));
|
|
67
|
-
} else {
|
|
68
|
-
model.collection.emitter.once('queue', function() {
|
|
69
|
-
model.hooks.execPre('aggregate', agg).then(() => onPreComplete(null), err => onPreComplete(err));
|
|
70
|
-
});
|
|
71
|
-
}
|
|
66
|
+
model.hooks.execPre('aggregate', agg).then(() => onPreComplete(null), err => onPreComplete(err));
|
|
72
67
|
|
|
73
68
|
function onPreComplete(err) {
|
|
74
69
|
if (err != null) {
|
|
@@ -79,8 +74,28 @@ function _init(model, c, agg) {
|
|
|
79
74
|
c._transforms.push(agg.options.cursor.transform);
|
|
80
75
|
}
|
|
81
76
|
|
|
82
|
-
|
|
83
|
-
|
|
77
|
+
if (model.collection._shouldBufferCommands() && model.collection.buffer) {
|
|
78
|
+
model.collection.queue.push([
|
|
79
|
+
() => _getRawCursor(model, c, agg)
|
|
80
|
+
]);
|
|
81
|
+
} else {
|
|
82
|
+
_getRawCursor(model, c, agg);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/*!
|
|
88
|
+
* ignore
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
function _getRawCursor(model, aggregationCursor, agg) {
|
|
92
|
+
try {
|
|
93
|
+
const cursor = model.collection.aggregate(agg._pipeline, agg.options || {});
|
|
94
|
+
aggregationCursor.cursor = cursor;
|
|
95
|
+
aggregationCursor.emit('cursor', cursor);
|
|
96
|
+
} catch (err) {
|
|
97
|
+
aggregationCursor._markError(err);
|
|
98
|
+
aggregationCursor.listeners('error').length > 0 && aggregationCursor.emit('error', aggregationCursor._error);
|
|
84
99
|
}
|
|
85
100
|
}
|
|
86
101
|
|
|
@@ -277,14 +292,30 @@ AggregationCursor.prototype.next = async function next() {
|
|
|
277
292
|
if (typeof arguments[0] === 'function') {
|
|
278
293
|
throw new MongooseError('AggregationCursor.prototype.next() no longer accepts a callback');
|
|
279
294
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
295
|
+
const _this = this;
|
|
296
|
+
const model = this.agg._model;
|
|
297
|
+
return cursorNextChannel.trace(function maybeTracedAggCursorNext() {
|
|
298
|
+
return new Promise((resolve, reject) => {
|
|
299
|
+
_next(_this, (err, res) => {
|
|
300
|
+
if (err != null) {
|
|
301
|
+
return reject(err);
|
|
302
|
+
}
|
|
303
|
+
resolve(res);
|
|
304
|
+
});
|
|
286
305
|
});
|
|
287
|
-
})
|
|
306
|
+
}, () => ({
|
|
307
|
+
operation: 'aggregate',
|
|
308
|
+
collection: model?.collection?.name,
|
|
309
|
+
database: model?.db?.name,
|
|
310
|
+
serverAddress: model?.db?.host,
|
|
311
|
+
serverPort: model?.db?.port,
|
|
312
|
+
batchSize: _this.agg.options?.cursor?.batchSize,
|
|
313
|
+
tailable: false,
|
|
314
|
+
args: {
|
|
315
|
+
pipeline: _this.agg._pipeline,
|
|
316
|
+
options: _this.agg.options
|
|
317
|
+
}
|
|
318
|
+
}));
|
|
288
319
|
};
|
|
289
320
|
|
|
290
321
|
/**
|
|
@@ -12,6 +12,7 @@ const kareem = require('kareem');
|
|
|
12
12
|
const immediate = require('../helpers/immediate');
|
|
13
13
|
const { once } = require('events');
|
|
14
14
|
const util = require('util');
|
|
15
|
+
const { cursorNextChannel } = require('../tracing');
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* A QueryCursor is a concurrency primitive for processing query results
|
|
@@ -310,14 +311,29 @@ QueryCursor.prototype.next = async function next() {
|
|
|
310
311
|
if (this._closed) {
|
|
311
312
|
throw new MongooseError('Cannot call `next()` on a closed cursor');
|
|
312
313
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
314
|
+
const _this = this;
|
|
315
|
+
return cursorNextChannel.trace(function maybeTracedQueryCursorNext() {
|
|
316
|
+
return new Promise((resolve, reject) => {
|
|
317
|
+
_next(_this, function(error, doc) {
|
|
318
|
+
if (error) {
|
|
319
|
+
return reject(error);
|
|
320
|
+
}
|
|
321
|
+
resolve(doc);
|
|
322
|
+
});
|
|
319
323
|
});
|
|
320
|
-
})
|
|
324
|
+
}, () => ({
|
|
325
|
+
operation: _this.query.op || 'find',
|
|
326
|
+
collection: _this.query.mongooseCollection.name,
|
|
327
|
+
database: _this.model.db?.name,
|
|
328
|
+
serverAddress: _this.model.db?.host,
|
|
329
|
+
serverPort: _this.model.db?.port,
|
|
330
|
+
batchSize: _this.options.batchSize || _this.query.options?.batchSize,
|
|
331
|
+
tailable: _this.options.tailable || _this.query.options?.tailable || false,
|
|
332
|
+
args: {
|
|
333
|
+
filter: _this.query.getFilter(),
|
|
334
|
+
options: _this.query._mongooseOptions
|
|
335
|
+
}
|
|
336
|
+
}));
|
|
321
337
|
};
|
|
322
338
|
|
|
323
339
|
/**
|
package/lib/document.js
CHANGED
|
@@ -3264,6 +3264,9 @@ function _handlePathsToSkip(paths, pathsToSkip) {
|
|
|
3264
3264
|
/**
|
|
3265
3265
|
* Executes registered validation rules (skipping asynchronous validators) for this document.
|
|
3266
3266
|
*
|
|
3267
|
+
* **Deprecated.** Use [`validate()`](https://mongoosejs.com/docs/api/document.html#Document.prototype.validate()) instead.
|
|
3268
|
+
* `validateSync()` does not run validation middleware and will be removed in Mongoose 10.
|
|
3269
|
+
*
|
|
3267
3270
|
* #### Note:
|
|
3268
3271
|
*
|
|
3269
3272
|
* This method is useful if you need synchronous validation.
|
|
@@ -3281,14 +3284,21 @@ function _handlePathsToSkip(paths, pathsToSkip) {
|
|
|
3281
3284
|
* @param {object} [options] options for validation
|
|
3282
3285
|
* @param {boolean} [options.validateModifiedOnly=false] If `true`, Mongoose will only validate modified paths, as opposed to modified paths and `required` paths.
|
|
3283
3286
|
* @param {Array|string} [options.pathsToSkip] list of paths to skip. If set, Mongoose will validate every modified path that is not in this list.
|
|
3284
|
-
* @param {boolean|object} [options.middleware=true] set to `false` to skip all user-defined middleware
|
|
3285
|
-
* @param {boolean} [options.middleware.pre=true] set to `false` to skip only pre hooks
|
|
3286
|
-
* @param {boolean} [options.middleware.post=true] set to `false` to skip only post hooks
|
|
3287
3287
|
* @return {ValidationError|undefined} ValidationError if there are errors during validation, or undefined if there is no error.
|
|
3288
|
+
* @deprecated Use `validate()` instead. `validateSync()` does not run middleware and will be removed in Mongoose 10.
|
|
3288
3289
|
* @api public
|
|
3289
3290
|
*/
|
|
3290
3291
|
|
|
3291
|
-
Document.prototype.validateSync = function(
|
|
3292
|
+
Document.prototype.validateSync = function() {
|
|
3293
|
+
utils.warn('Mongoose: `Document.prototype.validateSync()` is deprecated and will be removed in Mongoose 10. Use `Document.prototype.validate()` instead.');
|
|
3294
|
+
return this.$__validateSync.apply(this, arguments);
|
|
3295
|
+
};
|
|
3296
|
+
|
|
3297
|
+
/*!
|
|
3298
|
+
* ignore
|
|
3299
|
+
*/
|
|
3300
|
+
|
|
3301
|
+
Document.prototype.$__validateSync = function(pathsToValidate, options) {
|
|
3292
3302
|
const _this = this;
|
|
3293
3303
|
|
|
3294
3304
|
if (arguments.length === 1 && typeof arguments[0] === 'object' && !Array.isArray(arguments[0])) {
|
|
@@ -5266,6 +5276,12 @@ function checkDivergentArray(doc, path, array) {
|
|
|
5266
5276
|
// If any array was selected using an $elemMatch projection, we deny the update.
|
|
5267
5277
|
// NOTE: MongoDB only supports projected $elemMatch on top level array.
|
|
5268
5278
|
const top = path.split('.')[0];
|
|
5279
|
+
if (doc.$__.selected[top] && doc.$__.selected[top].$slice != null && utils.isMongooseArray(array)) {
|
|
5280
|
+
const atomics = array[arrayAtomicsSymbol];
|
|
5281
|
+
if (atomics.$set) {
|
|
5282
|
+
return top;
|
|
5283
|
+
}
|
|
5284
|
+
}
|
|
5269
5285
|
if (doc.$__.selected[top + '.$']) {
|
|
5270
5286
|
return top;
|
|
5271
5287
|
}
|
|
@@ -17,7 +17,7 @@ class DivergentArrayError extends MongooseError {
|
|
|
17
17
|
|
|
18
18
|
constructor(paths) {
|
|
19
19
|
const msg = 'For your own good, using `document.save()` to update an array '
|
|
20
|
-
+ 'which was selected using an $elemMatch projection OR '
|
|
20
|
+
+ 'which was selected using an $elemMatch or $slice projection OR '
|
|
21
21
|
+ 'populated using skip, limit, query conditions, or exclusion of '
|
|
22
22
|
+ 'the _id field when the operation results in a $pop or $set of '
|
|
23
23
|
+ 'the entire array is not supported. The following '
|
|
@@ -873,7 +873,11 @@ function _findRefPathForDiscriminators(doc, modelSchema, data, options, normaliz
|
|
|
873
873
|
}
|
|
874
874
|
|
|
875
875
|
/**
|
|
876
|
-
* Throw an error if there are any $where keys
|
|
876
|
+
* Throw an error if there are any $where keys to defend against [CVE-2024-53900](https://nvd.nist.gov/vuln/detail/CVE-2024-53900)
|
|
877
|
+
*
|
|
878
|
+
* Note that this is ONLY for $where because sift executes $where in Node.js memory.
|
|
879
|
+
* Other forms of MongoDB server-side execution, like $expr, are NOT filtered out.
|
|
880
|
+
* This function is not meant to protect against server-side execution in MongoDB.
|
|
877
881
|
*/
|
|
878
882
|
|
|
879
883
|
function throwOn$where(match) {
|
package/lib/model.js
CHANGED
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
const Aggregate = require('./aggregate');
|
|
8
8
|
const ChangeStream = require('./cursor/changeStream');
|
|
9
9
|
const Document = require('./document');
|
|
10
|
+
const { createTracedChannel } = require('./tracing');
|
|
11
|
+
const { trace: traceSave } = createTracedChannel('mongoose:model:save');
|
|
12
|
+
const { trace: traceInsertMany } = createTracedChannel('mongoose:model:insertMany');
|
|
13
|
+
const { trace: traceBulkWrite } = createTracedChannel('mongoose:model:bulkWrite');
|
|
10
14
|
const DocumentNotFoundError = require('./error/notFound');
|
|
11
15
|
const EventEmitter = require('events').EventEmitter;
|
|
12
16
|
const Kareem = require('kareem');
|
|
@@ -37,6 +41,7 @@ const applyVirtualsHelper = require('./helpers/document/applyVirtuals');
|
|
|
37
41
|
const assignVals = require('./helpers/populate/assignVals');
|
|
38
42
|
const castBulkWrite = require('./helpers/model/castBulkWrite');
|
|
39
43
|
const clone = require('./helpers/clone');
|
|
44
|
+
const convertErrorToStandardSchemaIssues = require('./standardSchema/convertErrorToIssues');
|
|
40
45
|
const createPopulateQueryFilter = require('./helpers/populate/createPopulateQueryFilter');
|
|
41
46
|
const decorateUpdateWithVersionKey = require('./helpers/update/decorateUpdateWithVersionKey');
|
|
42
47
|
const getDefaultBulkwriteResult = require('./helpers/getDefaultBulkwriteResult');
|
|
@@ -663,19 +668,29 @@ Model.prototype.save = async function save(options) {
|
|
|
663
668
|
|
|
664
669
|
this.$__.saveOptions = options;
|
|
665
670
|
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
671
|
+
const _this = this;
|
|
672
|
+
return traceSave(async function maybeTracedSave() {
|
|
673
|
+
try {
|
|
674
|
+
await _this.$__save(options);
|
|
675
|
+
} catch (error) {
|
|
676
|
+
_this.$__handleReject(error);
|
|
677
|
+
throw error;
|
|
678
|
+
} finally {
|
|
679
|
+
_this.$__.saving = null;
|
|
680
|
+
_this.$__.saveOptions = null;
|
|
681
|
+
_this.$__.$versionError = null;
|
|
682
|
+
_this.$op = null;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
return _this;
|
|
686
|
+
}, () => ({
|
|
687
|
+
operation: 'save',
|
|
688
|
+
collection: _this.constructor.collection.name,
|
|
689
|
+
database: _this.constructor.db?.name,
|
|
690
|
+
serverAddress: _this.constructor.db?.host,
|
|
691
|
+
serverPort: _this.constructor.db?.port,
|
|
692
|
+
args: { options }
|
|
693
|
+
}));
|
|
679
694
|
};
|
|
680
695
|
|
|
681
696
|
Model.prototype.$save = Model.prototype.save;
|
|
@@ -3015,6 +3030,18 @@ Model.insertMany = async function insertMany(arr, options) {
|
|
|
3015
3030
|
throw new MongooseError('Model.insertMany() no longer accepts a callback');
|
|
3016
3031
|
}
|
|
3017
3032
|
|
|
3033
|
+
const ThisModel = this;
|
|
3034
|
+
return traceInsertMany(function maybeTracedInsertMany() { return _insertMany.call(ThisModel, arr, options); }, () => ({
|
|
3035
|
+
operation: 'insertMany',
|
|
3036
|
+
collection: ThisModel.collection.name,
|
|
3037
|
+
database: ThisModel.db?.name,
|
|
3038
|
+
serverAddress: ThisModel.db?.host,
|
|
3039
|
+
serverPort: ThisModel.db?.port,
|
|
3040
|
+
args: { docs: arr, options }
|
|
3041
|
+
}));
|
|
3042
|
+
};
|
|
3043
|
+
|
|
3044
|
+
async function _insertMany(arr, options) {
|
|
3018
3045
|
options = options || {};
|
|
3019
3046
|
const preFilter = buildMiddlewareFilter(options, 'pre');
|
|
3020
3047
|
const postFilter = buildMiddlewareFilter(options, 'post');
|
|
@@ -3250,7 +3277,7 @@ Model.insertMany = async function insertMany(arr, options) {
|
|
|
3250
3277
|
|
|
3251
3278
|
const [result] = await this._middleware.execPost('insertMany', this, [docAttributes], { filter: postFilter });
|
|
3252
3279
|
return result;
|
|
3253
|
-
}
|
|
3280
|
+
}
|
|
3254
3281
|
|
|
3255
3282
|
/*!
|
|
3256
3283
|
* ignore
|
|
@@ -3378,6 +3405,19 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
3378
3405
|
typeof arguments[2] === 'function') {
|
|
3379
3406
|
throw new MongooseError('Model.bulkWrite() no longer accepts a callback');
|
|
3380
3407
|
}
|
|
3408
|
+
|
|
3409
|
+
const ThisModel = this;
|
|
3410
|
+
return traceBulkWrite(function maybeTracedBulkWrite() { return _bulkWrite.call(ThisModel, ops, options); }, () => ({
|
|
3411
|
+
operation: 'bulkWrite',
|
|
3412
|
+
collection: ThisModel.collection.name,
|
|
3413
|
+
database: ThisModel.db?.name,
|
|
3414
|
+
serverAddress: ThisModel.db?.host,
|
|
3415
|
+
serverPort: ThisModel.db?.port,
|
|
3416
|
+
args: { ops, options }
|
|
3417
|
+
}));
|
|
3418
|
+
};
|
|
3419
|
+
|
|
3420
|
+
async function _bulkWrite(ops, options) {
|
|
3381
3421
|
options = options || {};
|
|
3382
3422
|
const preFilter = buildMiddlewareFilter(options, 'pre');
|
|
3383
3423
|
const postFilter = buildMiddlewareFilter(options, 'post');
|
|
@@ -3516,7 +3556,7 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
3516
3556
|
await this.hooks.execPost('bulkWrite', this, [res], { filter: postFilter });
|
|
3517
3557
|
|
|
3518
3558
|
return res;
|
|
3519
|
-
}
|
|
3559
|
+
}
|
|
3520
3560
|
|
|
3521
3561
|
/**
|
|
3522
3562
|
* Takes an array of documents, gets the changes and inserts/updates documents in the database
|
|
@@ -3861,7 +3901,7 @@ Model.buildBulkWriteOperations = function buildBulkWriteOperations(documents, op
|
|
|
3861
3901
|
throw new MongooseError(`documents.${i} was not a mongoose document, documents must be an array of mongoose documents (instanceof mongoose.Document).`);
|
|
3862
3902
|
}
|
|
3863
3903
|
if (options.validateBeforeSave == null || options.validateBeforeSave) {
|
|
3864
|
-
const err = document
|
|
3904
|
+
const err = document.$__validateSync();
|
|
3865
3905
|
if (err != null) {
|
|
3866
3906
|
throw err;
|
|
3867
3907
|
}
|
|
@@ -4188,13 +4228,24 @@ Model.aggregate = function aggregate(pipeline, options) {
|
|
|
4188
4228
|
* age: { type: Number, required: true }
|
|
4189
4229
|
* });
|
|
4190
4230
|
*
|
|
4231
|
+
* // Succeeds
|
|
4232
|
+
* await Model.validate({ name: 'John Smith', age: 31 });
|
|
4233
|
+
*
|
|
4191
4234
|
* try {
|
|
4192
|
-
* await Model.validate({ name: null }
|
|
4235
|
+
* await Model.validate({ name: null });
|
|
4193
4236
|
* } catch (err) {
|
|
4194
4237
|
* err instanceof mongoose.Error.ValidationError; // true
|
|
4195
4238
|
* Object.keys(err.errors); // ['name']
|
|
4196
4239
|
* }
|
|
4197
4240
|
*
|
|
4241
|
+
* Note: the `pathsToSkip` and `pathsToValidate` options **only** apply to validation, not
|
|
4242
|
+
* casting. This function will still throw an error for values that cannot be casted to the
|
|
4243
|
+
* schema-specified type. Remove any paths you do not want to cast.
|
|
4244
|
+
*
|
|
4245
|
+
* // The following will still throw an error because the value of `age` cannot be
|
|
4246
|
+
* // casted to a number. Remove the `age` property before calling `validate()`.
|
|
4247
|
+
* await Model.validate({ name: 'Test', age: 'not a number' }, ['name']);
|
|
4248
|
+
*
|
|
4198
4249
|
* @param {object} obj
|
|
4199
4250
|
* @param {object|Array|string} pathsOrOptions
|
|
4200
4251
|
* @param {object} [context]
|
|
@@ -4299,6 +4350,33 @@ Model.validate = async function validate(obj, pathsOrOptions, context) {
|
|
|
4299
4350
|
return obj;
|
|
4300
4351
|
};
|
|
4301
4352
|
|
|
4353
|
+
/**
|
|
4354
|
+
* Standard Schema adapter for this model.
|
|
4355
|
+
* Calls [`Model.validate()`](https://mongoosejs.com/docs/api/model.html#Model.validate()) internally with the provided `libraryOptions`
|
|
4356
|
+
* to cast and validate the given value.
|
|
4357
|
+
*
|
|
4358
|
+
* @api public
|
|
4359
|
+
* @property ~standard
|
|
4360
|
+
* @memberOf Model
|
|
4361
|
+
* @static
|
|
4362
|
+
*/
|
|
4363
|
+
|
|
4364
|
+
Object.defineProperty(Model, '~standard', {
|
|
4365
|
+
configurable: true,
|
|
4366
|
+
get() {
|
|
4367
|
+
return {
|
|
4368
|
+
version: 1,
|
|
4369
|
+
vendor: 'mongoose',
|
|
4370
|
+
validate: (value, options) => {
|
|
4371
|
+
return this.validate(value, options?.libraryOptions).then(
|
|
4372
|
+
value => ({ value }),
|
|
4373
|
+
error => ({ issues: convertErrorToStandardSchemaIssues(error) })
|
|
4374
|
+
);
|
|
4375
|
+
}
|
|
4376
|
+
};
|
|
4377
|
+
}
|
|
4378
|
+
});
|
|
4379
|
+
|
|
4302
4380
|
/**
|
|
4303
4381
|
* Populates document references.
|
|
4304
4382
|
*
|
package/lib/query.js
CHANGED
|
@@ -42,6 +42,8 @@ const updateValidators = require('./helpers/updateValidators');
|
|
|
42
42
|
const util = require('util');
|
|
43
43
|
const utils = require('./utils');
|
|
44
44
|
const queryMiddlewareFunctions = require('./constants').queryMiddlewareFunctions;
|
|
45
|
+
const { createTracedChannel } = require('./tracing');
|
|
46
|
+
const { trace: traceQuery } = createTracedChannel('mongoose:query');
|
|
45
47
|
|
|
46
48
|
const queryOptionMethods = new Set([
|
|
47
49
|
'allowDiskUse',
|
|
@@ -4778,42 +4780,56 @@ Query.prototype.exec = async function exec(op) {
|
|
|
4778
4780
|
}
|
|
4779
4781
|
this._execCount++;
|
|
4780
4782
|
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4783
|
+
const _this = this;
|
|
4784
|
+
return traceQuery(async function maybeTracedQueryExec() {
|
|
4785
|
+
let skipWrappedFunction = null;
|
|
4786
|
+
try {
|
|
4787
|
+
await _this._hooks.execPre('exec', _this, []);
|
|
4788
|
+
} catch (err) {
|
|
4789
|
+
if (err instanceof Kareem.skipWrappedFunction) {
|
|
4790
|
+
skipWrappedFunction = err;
|
|
4791
|
+
} else {
|
|
4792
|
+
throw err;
|
|
4793
|
+
}
|
|
4789
4794
|
}
|
|
4790
|
-
}
|
|
4791
4795
|
|
|
4792
|
-
|
|
4796
|
+
let res;
|
|
4793
4797
|
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
+
let error = null;
|
|
4799
|
+
try {
|
|
4800
|
+
await _executePreHooks(_this);
|
|
4801
|
+
res = skipWrappedFunction ? skipWrappedFunction.args[0] : await _this[thunk]();
|
|
4798
4802
|
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4803
|
+
for (const fn of _this._transforms) {
|
|
4804
|
+
res = fn(res);
|
|
4805
|
+
}
|
|
4806
|
+
} catch (err) {
|
|
4807
|
+
if (err instanceof Kareem.skipWrappedFunction) {
|
|
4808
|
+
res = err.args[0];
|
|
4809
|
+
} else {
|
|
4810
|
+
error = err;
|
|
4811
|
+
}
|
|
4808
4812
|
|
|
4809
|
-
|
|
4810
|
-
|
|
4813
|
+
error = _this.model.schema._transformDuplicateKeyError(error);
|
|
4814
|
+
}
|
|
4811
4815
|
|
|
4812
|
-
|
|
4816
|
+
res = await _executePostHooks(_this, res, error);
|
|
4813
4817
|
|
|
4814
|
-
|
|
4818
|
+
await _this._hooks.execPost('exec', _this, []);
|
|
4815
4819
|
|
|
4816
|
-
|
|
4820
|
+
return res;
|
|
4821
|
+
}, () => ({
|
|
4822
|
+
operation: _this.op,
|
|
4823
|
+
collection: _this.mongooseCollection.name,
|
|
4824
|
+
database: _this.model.db?.name,
|
|
4825
|
+
serverAddress: _this.model.db?.host,
|
|
4826
|
+
serverPort: _this.model.db?.port,
|
|
4827
|
+
args: {
|
|
4828
|
+
filter: _this.getFilter(),
|
|
4829
|
+
fields: _this._fields,
|
|
4830
|
+
options: _this._mongooseOptions
|
|
4831
|
+
}
|
|
4832
|
+
}));
|
|
4817
4833
|
};
|
|
4818
4834
|
|
|
4819
4835
|
/*!
|
package/lib/schema/date.js
CHANGED
|
@@ -188,16 +188,18 @@ SchemaDate.prototype.expires = function(when) {
|
|
|
188
188
|
SchemaDate._checkRequired = v => v instanceof Date;
|
|
189
189
|
|
|
190
190
|
/**
|
|
191
|
-
* Override the function the required validator uses to check whether a
|
|
191
|
+
* Override the function the required validator uses to check whether a date
|
|
192
192
|
* passes the `required` check.
|
|
193
193
|
*
|
|
194
194
|
* #### Example:
|
|
195
195
|
*
|
|
196
|
-
* //
|
|
197
|
-
* mongoose.Schema.Types.
|
|
196
|
+
* // Disallow "invalid date"
|
|
197
|
+
* mongoose.Schema.Types.Date.checkRequired(v => v instanceof Date && !isNaN(v.valueOf()));
|
|
198
198
|
*
|
|
199
|
-
* const
|
|
200
|
-
*
|
|
199
|
+
* const schema = new mongoose.Schema({ myDate: { type: Date, required: true } });
|
|
200
|
+
* const M = mongoose.model('Test', schema);
|
|
201
|
+
* // returns a ValidationError due to date being invalid
|
|
202
|
+
* new M({ myDate: new Date('invalid') }).validateSync();
|
|
201
203
|
*
|
|
202
204
|
* @param {Function} fn
|
|
203
205
|
* @return {Function}
|
|
@@ -314,7 +314,7 @@ SchemaDocumentArray.prototype.doValidateSync = function(array, scope, options) {
|
|
|
314
314
|
continue;
|
|
315
315
|
}
|
|
316
316
|
|
|
317
|
-
const subdocValidateError = doc
|
|
317
|
+
const subdocValidateError = doc.$__validateSync(options);
|
|
318
318
|
|
|
319
319
|
if (subdocValidateError && resultError == null) {
|
|
320
320
|
resultError = subdocValidateError;
|
package/lib/schema/union.js
CHANGED
|
@@ -112,8 +112,8 @@ class Union extends SchemaType {
|
|
|
112
112
|
return schemaTypeError;
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
|
-
if (value != null && typeof value
|
|
116
|
-
return value
|
|
115
|
+
if (value != null && typeof value.$__validateSync === 'function') {
|
|
116
|
+
return value.$__validateSync();
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
|
package/lib/schemaType.js
CHANGED
|
@@ -1198,7 +1198,8 @@ SchemaType.prototype.required = function(required, message) {
|
|
|
1198
1198
|
* name: { type: String, allowNull: false }
|
|
1199
1199
|
* });
|
|
1200
1200
|
*
|
|
1201
|
-
* new Model({
|
|
1201
|
+
* new Model({}).validateSync(); // OK
|
|
1202
|
+
* new Model({ name: undefined }).validateSync(); // OK, Mongoose strips out `name` when its value is `undefined`
|
|
1202
1203
|
* new Model({ name: null }).validateSync(); // ValidationError
|
|
1203
1204
|
*
|
|
1204
1205
|
* @param {boolean} allowNull
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const ValidationError = require('../error/validation');
|
|
4
|
+
|
|
5
|
+
module.exports = function convertErrorToIssues(error) {
|
|
6
|
+
if (error instanceof ValidationError) {
|
|
7
|
+
return Object.keys(error.errors).map(path => {
|
|
8
|
+
const err = error.errors[path];
|
|
9
|
+
return {
|
|
10
|
+
message: err.message,
|
|
11
|
+
path: path.split('.').map(part => {
|
|
12
|
+
const num = +part;
|
|
13
|
+
return Number.isInteger(num) && String(num) === part ? num : part;
|
|
14
|
+
})
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return [{ message: error.message }];
|
|
20
|
+
};
|
package/lib/tracing.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
let dc;
|
|
4
|
+
try {
|
|
5
|
+
dc = (typeof process !== 'undefined' && 'getBuiltinModule' in process)
|
|
6
|
+
? process.getBuiltinModule('node:diagnostics_channel')
|
|
7
|
+
: require('node:diagnostics_channel');
|
|
8
|
+
} catch {
|
|
9
|
+
// diagnostics_channel not available
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const hasTracingChannel = !!dc && typeof dc.tracingChannel === 'function';
|
|
13
|
+
|
|
14
|
+
function shouldTrace(channel) {
|
|
15
|
+
// Node 18 and Bun don't expose hasSubscribers on TracingChannel
|
|
16
|
+
// so undefined means it may or may not have subscribers, so we'll trace anyway
|
|
17
|
+
return !!channel && channel.hasSubscribers !== false;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function createTracedChannel(name) {
|
|
21
|
+
const ch = hasTracingChannel ? dc.tracingChannel(name) : undefined;
|
|
22
|
+
|
|
23
|
+
function trace(fn, contextFactory) {
|
|
24
|
+
if (!shouldTrace(ch)) {
|
|
25
|
+
return fn();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const traced = ch.tracePromise(fn, contextFactory());
|
|
29
|
+
return traced;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return { channel: ch, trace };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = {
|
|
36
|
+
createTracedChannel,
|
|
37
|
+
cursorNextChannel: createTracedChannel('mongoose:cursor:next')
|
|
38
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mongoose",
|
|
3
3
|
"description": "Mongoose MongoDB ODM",
|
|
4
|
-
"version": "9.
|
|
4
|
+
"version": "9.7.0",
|
|
5
5
|
"author": "Guillermo Rauch <guillermo@learnboost.com>",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"mongodb",
|
|
@@ -39,9 +39,9 @@
|
|
|
39
39
|
"c8": "11.0.0",
|
|
40
40
|
"cheerio": "1.2.0",
|
|
41
41
|
"dox": "1.0.0",
|
|
42
|
-
"eslint": "10.
|
|
42
|
+
"eslint": "10.4.1",
|
|
43
43
|
"eslint-plugin-mocha-no-only": "1.2.0",
|
|
44
|
-
"express": "
|
|
44
|
+
"express": "5.2.1",
|
|
45
45
|
"fs-extra": "~11.3.0",
|
|
46
46
|
"globals": "^17.4.0",
|
|
47
47
|
"glob": "^13.0.6",
|
|
@@ -50,16 +50,16 @@
|
|
|
50
50
|
"lodash.isequal": "4.5.0",
|
|
51
51
|
"lodash.isequalwith": "4.4.0",
|
|
52
52
|
"markdownlint-cli2": "0.22.1",
|
|
53
|
-
"marked": "18.0.
|
|
53
|
+
"marked": "18.0.4",
|
|
54
54
|
"mkdirp": "^3.0.1",
|
|
55
55
|
"mocha": "12.0.0-beta-10",
|
|
56
56
|
"moment": "2.30.1",
|
|
57
57
|
"mongodb-client-encryption": "~7.0",
|
|
58
|
-
"mongodb-memory-server": "11.
|
|
58
|
+
"mongodb-memory-server": "11.2.0",
|
|
59
59
|
"mongodb-runner": "^6.0.0",
|
|
60
60
|
"ncp": "^2.0.0",
|
|
61
61
|
"pug": "3.0.4",
|
|
62
|
-
"sinon": "
|
|
62
|
+
"sinon": "22.0.0",
|
|
63
63
|
"tstyche": "^7.0.0",
|
|
64
64
|
"typescript": "5.9.3",
|
|
65
65
|
"typescript-eslint": "^8.31.1",
|
package/types/document.d.ts
CHANGED
|
@@ -11,6 +11,12 @@ declare module 'mongoose' {
|
|
|
11
11
|
middleware?: boolean | SkipMiddlewareOptions;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
interface ValidateSyncOptions extends Omit<ValidateOptions, 'middleware'> {
|
|
15
|
+
/** `validateSync()` does not run middleware. Use `validate()` if you need middleware. */
|
|
16
|
+
middleware?: never;
|
|
17
|
+
[k: string]: any;
|
|
18
|
+
}
|
|
19
|
+
|
|
14
20
|
interface DocumentSetOptions {
|
|
15
21
|
merge?: boolean;
|
|
16
22
|
|
|
@@ -320,9 +326,20 @@ declare module 'mongoose' {
|
|
|
320
326
|
validate(pathsToValidate?: pathsToValidate, options?: Omit<ValidateOptions, 'pathsToSkip'> & AnyObject): Promise<void>;
|
|
321
327
|
validate(options: ValidateOptions): Promise<void>;
|
|
322
328
|
|
|
323
|
-
/**
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
329
|
+
/**
|
|
330
|
+
* Executes registered validation rules (skipping asynchronous validators) for this document.
|
|
331
|
+
* @deprecated Use `validate()` instead. `validateSync()` does not run middleware and will be removed in Mongoose 10.
|
|
332
|
+
*/
|
|
333
|
+
validateSync(options: ValidateSyncOptions): Error.ValidationError | null;
|
|
334
|
+
/**
|
|
335
|
+
* Executes registered validation rules (skipping asynchronous validators) for this document.
|
|
336
|
+
* @deprecated Use `validate()` instead. `validateSync()` does not run middleware and will be removed in Mongoose 10.
|
|
337
|
+
*/
|
|
338
|
+
validateSync<T extends keyof DocType>(pathsToValidate?: T | T[], options?: Omit<ValidateSyncOptions, 'pathsToSkip'>): Error.ValidationError | null;
|
|
339
|
+
/**
|
|
340
|
+
* Executes registered validation rules (skipping asynchronous validators) for this document.
|
|
341
|
+
* @deprecated Use `validate()` instead. `validateSync()` does not run middleware and will be removed in Mongoose 10.
|
|
342
|
+
*/
|
|
343
|
+
validateSync(pathsToValidate?: pathsToValidate, options?: Omit<ValidateSyncOptions, 'pathsToSkip'>): Error.ValidationError | null;
|
|
327
344
|
}
|
|
328
345
|
}
|
package/types/index.d.ts
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
/// <reference path="./inferrawdoctype.d.ts" />
|
|
25
25
|
/// <reference path="./inferschematype.d.ts" />
|
|
26
26
|
/// <reference path="./virtuals.d.ts" />
|
|
27
|
+
/// <reference path="./tracing.d.ts" />
|
|
27
28
|
/// <reference path="./augmentations.d.ts" />
|
|
28
29
|
|
|
29
30
|
declare class NativeDate extends globalThis.Date { }
|
package/types/models.d.ts
CHANGED
|
@@ -108,6 +108,41 @@ declare module 'mongoose' {
|
|
|
108
108
|
*/
|
|
109
109
|
type pathsToValidate = PathsToValidate;
|
|
110
110
|
|
|
111
|
+
export namespace StandardSchemaV1 {
|
|
112
|
+
export interface Props<Output = unknown> {
|
|
113
|
+
readonly version: 1;
|
|
114
|
+
readonly vendor: 'mongoose';
|
|
115
|
+
readonly validate: (
|
|
116
|
+
value: unknown,
|
|
117
|
+
options?: Options | undefined
|
|
118
|
+
) => Result<Output> | Promise<Result<Output>>;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export interface Options {
|
|
122
|
+
readonly libraryOptions?: Record<string, unknown> | undefined;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export type Result<Output> = SuccessResult<Output> | FailureResult;
|
|
126
|
+
|
|
127
|
+
export interface SuccessResult<Output> {
|
|
128
|
+
readonly value: Output;
|
|
129
|
+
readonly issues?: undefined;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface FailureResult {
|
|
133
|
+
readonly issues: ReadonlyArray<Issue>;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export interface Issue {
|
|
137
|
+
readonly message: string;
|
|
138
|
+
readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export interface PathSegment {
|
|
142
|
+
readonly key: PropertyKey;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
111
146
|
interface SaveOptions extends
|
|
112
147
|
SessionOption {
|
|
113
148
|
checkKeys?: boolean;
|
|
@@ -192,15 +227,15 @@ declare module 'mongoose' {
|
|
|
192
227
|
type CreateObjectWithExtraKeys<T> = T & Record<string, unknown>;
|
|
193
228
|
type ApplyBasicCreateCasting<T> = {
|
|
194
229
|
[K in keyof T]: NonNullable<T[K]> extends Map<infer KeyType extends string, infer ValueType>
|
|
195
|
-
? (Record<KeyType, ValueType> | Array<[KeyType, ValueType]> | T[K])
|
|
230
|
+
? (Record<KeyType, ValueType> | Array<[KeyType, ValueType]> | T[K] | QueryTypeCasting<Extract<T[K], TreatAsPrimitives>>)
|
|
196
231
|
: NonNullable<T[K]> extends Types.DocumentArray<infer RawSubdocType>
|
|
197
|
-
? RawSubdocType[] | T[K]
|
|
232
|
+
? RawSubdocType[] | T[K] | QueryTypeCasting<Extract<T[K], TreatAsPrimitives>>
|
|
198
233
|
: NonNullable<T[K]> extends Document<any, any, infer RawSubdocType>
|
|
199
|
-
? CreateObjectWithExtraKeys<ApplyBasicCreateCasting<RawSubdocType>> | T[K]
|
|
234
|
+
? CreateObjectWithExtraKeys<ApplyBasicCreateCasting<RawSubdocType>> | T[K] | QueryTypeCasting<Extract<T[K], TreatAsPrimitives>>
|
|
200
235
|
: NonNullable<T[K]> extends TreatAsPrimitives
|
|
201
236
|
? QueryTypeCasting<T[K]>
|
|
202
237
|
: NonNullable<T[K]> extends object
|
|
203
|
-
? CreateObjectWithExtraKeys<ApplyBasicCreateCasting<T[K]>> | T[K]
|
|
238
|
+
? CreateObjectWithExtraKeys<ApplyBasicCreateCasting<T[K]>> | T[K] | QueryTypeCasting<Extract<T[K], TreatAsPrimitives>>
|
|
204
239
|
: QueryTypeCasting<T[K]>;
|
|
205
240
|
};
|
|
206
241
|
|
|
@@ -234,6 +269,9 @@ declare module 'mongoose' {
|
|
|
234
269
|
/** Base Mongoose instance the model uses. */
|
|
235
270
|
base: Mongoose;
|
|
236
271
|
|
|
272
|
+
/** Standard Schema adapter for validating input with this model's schema. */
|
|
273
|
+
readonly '~standard': StandardSchemaV1.Props<TRawDocType>;
|
|
274
|
+
|
|
237
275
|
/**
|
|
238
276
|
* If this is a discriminator model, `baseModelName` is the name of
|
|
239
277
|
* the base model.
|