mongoose 6.4.4 → 6.4.5

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.
@@ -0,0 +1,26 @@
1
+ 'use strict';
2
+
3
+ module.exports = function setDocumentTimestamps(doc, timestampOption, currentTime, createdAt, updatedAt) {
4
+ const skipUpdatedAt = timestampOption != null && timestampOption.updatedAt === false;
5
+ const skipCreatedAt = timestampOption != null && timestampOption.createdAt === false;
6
+
7
+ const defaultTimestamp = currentTime != null ?
8
+ currentTime() :
9
+ doc.ownerDocument().constructor.base.now();
10
+
11
+ if (!skipCreatedAt &&
12
+ (doc.isNew || doc.$isSubdocument) &&
13
+ createdAt &&
14
+ !doc.$__getValue(createdAt) &&
15
+ doc.$__isSelected(createdAt)) {
16
+ doc.$set(createdAt, defaultTimestamp, undefined, { overwriteImmutable: true });
17
+ }
18
+
19
+ if (!skipUpdatedAt && updatedAt && (doc.isNew || doc.$isModified())) {
20
+ let ts = defaultTimestamp;
21
+ if (doc.isNew && createdAt != null) {
22
+ ts = doc.$__getValue(createdAt);
23
+ }
24
+ doc.$set(updatedAt, ts);
25
+ }
26
+ };
@@ -4,6 +4,7 @@ const applyTimestampsToChildren = require('../update/applyTimestampsToChildren')
4
4
  const applyTimestampsToUpdate = require('../update/applyTimestampsToUpdate');
5
5
  const get = require('../get');
6
6
  const handleTimestampOption = require('../schema/handleTimestampOption');
7
+ const setDocumentTimestamps = require('./setDocumentTimestamps');
7
8
  const symbols = require('../../schema/symbols');
8
9
 
9
10
  module.exports = function setupTimestamps(schema, timestamps) {
@@ -44,24 +45,7 @@ module.exports = function setupTimestamps(schema, timestamps) {
44
45
  return next();
45
46
  }
46
47
 
47
- const skipUpdatedAt = timestampOption != null && timestampOption.updatedAt === false;
48
- const skipCreatedAt = timestampOption != null && timestampOption.createdAt === false;
49
-
50
- const defaultTimestamp = currentTime != null ?
51
- currentTime() :
52
- this.ownerDocument().constructor.base.now();
53
-
54
- if (!skipCreatedAt && (this.isNew || this.$isSubdocument) && createdAt && !this.$__getValue(createdAt) && this.$__isSelected(createdAt)) {
55
- this.$set(createdAt, defaultTimestamp, undefined, { overwriteImmutable: true });
56
- }
57
-
58
- if (!skipUpdatedAt && updatedAt && (this.isNew || this.$isModified())) {
59
- let ts = defaultTimestamp;
60
- if (this.isNew && createdAt != null) {
61
- ts = this.$__getValue(createdAt);
62
- }
63
- this.$set(updatedAt, ts);
64
- }
48
+ setDocumentTimestamps(this, timestampOption, currentTime, createdAt, updatedAt);
65
49
 
66
50
  next();
67
51
  });
@@ -76,6 +60,18 @@ module.exports = function setupTimestamps(schema, timestamps) {
76
60
  if (updatedAt && !this.get(updatedAt)) {
77
61
  this.$set(updatedAt, ts);
78
62
  }
63
+
64
+ if (this.$isSubdocument) {
65
+ return this;
66
+ }
67
+
68
+ const subdocs = this.$getAllSubdocs();
69
+ for (const subdoc of subdocs) {
70
+ if (subdoc.initializeTimestamps) {
71
+ subdoc.initializeTimestamps();
72
+ }
73
+ }
74
+
79
75
  return this;
80
76
  };
81
77
 
@@ -2,25 +2,30 @@
2
2
 
3
3
  const getConstructorName = require('../getConstructorName');
4
4
 
5
+ /**
6
+ * @typedef { import('mongodb').TopologyDescription } TopologyDescription
7
+ */
8
+
9
+ /**
10
+ * Checks if topologyDescription contains servers connected to an atlas instance
11
+ *
12
+ * @param {TopologyDescription} topologyDescription
13
+ * @returns {boolean}
14
+ */
5
15
  module.exports = function isAtlas(topologyDescription) {
6
16
  if (getConstructorName(topologyDescription) !== 'TopologyDescription') {
7
17
  return false;
8
18
  }
9
19
 
10
- const hostnames = Array.from(topologyDescription.servers.keys());
11
-
12
- if (hostnames.length === 0) {
20
+ if (topologyDescription.servers.size === 0) {
13
21
  return false;
14
22
  }
15
23
 
16
- for (let i = 0, il = hostnames.length; i < il; ++i) {
17
- const url = new URL(hostnames[i]);
18
- if (
19
- url.hostname.endsWith('.mongodb.net') === false ||
20
- url.port !== '27017'
21
- ) {
24
+ for (const server of topologyDescription.servers.values()) {
25
+ if (server.host.endsWith('.mongodb.net') === false || server.port !== 27017) {
22
26
  return false;
23
27
  }
24
28
  }
29
+
25
30
  return true;
26
31
  };
package/lib/index.js CHANGED
@@ -204,6 +204,7 @@ Mongoose.prototype.setDriver = function setDriver(driver) {
204
204
  * - 'overwriteModels': Set to `true` to default to overwriting models with the same name when calling `mongoose.model()`, as opposed to throwing an `OverwriteModelError`.
205
205
  * - 'returnOriginal': If `false`, changes the default `returnOriginal` option to `findOneAndUpdate()`, `findByIdAndUpdate`, and `findOneAndReplace()` to false. This is equivalent to setting the `new` option to `true` for `findOneAndX()` calls by default. Read our [`findOneAndUpdate()` tutorial](/docs/tutorials/findoneandupdate.html) for more information.
206
206
  * - 'runValidators': `false` by default. Set to true to enable [update validators](/docs/validation.html#update-validators) for all validators by default.
207
+ * - 'sanitizeFilter': `false` by default. Set to true to enable the [sanitization of the query filters](/docs/api.html#mongoose_Mongoose-sanitizeFilter) against query selector injection attacks by wrapping any nested objects that have a property whose name starts with `$` in a `$eq`.
207
208
  * - 'selectPopulatedPaths': `true` by default. Set to false to opt out of Mongoose adding all fields that you `populate()` to your `select()`. The schema-level option `selectPopulatedPaths` overwrites this one.
208
209
  * - 'strict': `true` by default, may be `false`, `true`, or `'throw'`. Sets the default strict mode for schemas.
209
210
  * - 'strictQuery': same value as 'strict' by default (`true`), may be `false`, `true`, or `'throw'`. Sets the default [strictQuery](/docs/guide.html#strictQuery) mode for schemas.
package/lib/model.js CHANGED
@@ -96,7 +96,7 @@ const saveToObjectOptions = Object.assign({}, internalToObjectOptions, {
96
96
  * const userFromDb = await UserModel.findOne({ name: 'Foo' });
97
97
  *
98
98
  * @param {Object} doc values for initial set
99
- * @param [fields] optional object containing the fields that were selected in the query which returned this document. You do **not** need to set this parameter to ensure Mongoose handles your [query projection](./api.html#query_Query-select).
99
+ * @param {Object} [fields] optional object containing the fields that were selected in the query which returned this document. You do **not** need to set this parameter to ensure Mongoose handles your [query projection](./api.html#query_Query-select).
100
100
  * @param {Boolean} [skipId=false] optional boolean. If true, mongoose doesn't add an `_id` field to the document.
101
101
  * @inherits Document https://mongoosejs.com/docs/api/document.html
102
102
  * @event `error`: If listening to this event, 'error' is emitted when a document was saved without passing a callback and an `error` occurred. If not listening, the event bubbles to the connection used to create this Model.
@@ -210,6 +210,7 @@ Model.prototype.baseModelName;
210
210
  * await MyModel.findOne({ _id: 'Not a valid ObjectId' }).catch(noop);
211
211
  *
212
212
  * @api public
213
+ * @property events
213
214
  * @fires error whenever any query or model function errors
214
215
  * @memberOf Model
215
216
  * @static
@@ -888,26 +889,30 @@ Model.prototype.$__version = function(where, delta) {
888
889
  }
889
890
  };
890
891
 
892
+ /*!
893
+ * ignore
894
+ */
895
+
896
+ function increment() {
897
+ this.$__.version = VERSION_ALL;
898
+ return this;
899
+ }
900
+
891
901
  /**
892
902
  * Signal that we desire an increment of this documents version.
893
903
  *
894
904
  * #### Example:
895
905
  *
896
- * Model.findById(id, function (err, doc) {
897
- * doc.increment();
898
- * doc.save(function (err) { .. })
899
- * })
906
+ * const doc = await Model.findById(id);
907
+ * doc.increment();
908
+ * await doc.save();
900
909
  *
901
910
  * @see versionKeys https://mongoosejs.com/docs/guide.html#versionKey
902
911
  * @memberOf Model
912
+ * @method increment
903
913
  * @api public
904
914
  */
905
915
 
906
- function increment() {
907
- this.$__.version = VERSION_ALL;
908
- return this;
909
- }
910
-
911
916
  Model.prototype.increment = increment;
912
917
 
913
918
  /**
@@ -937,22 +942,12 @@ Model.prototype.$__where = function _where(where) {
937
942
  * Removes this document from the db.
938
943
  *
939
944
  * #### Example:
940
- * product.remove(function (err, product) {
941
- * if (err) return handleError(err);
942
- * Product.findById(product._id, function (err, product) {
943
- * console.log(product) // null
944
- * })
945
- * })
946
- *
947
- *
948
- * As an extra measure of flow control, remove will return a Promise (bound to `fn` if passed) so it could be chained, or hooked to receive errors
949
945
  *
950
- * #### Example:
951
- * product.remove().then(function (product) {
952
- * ...
953
- * }).catch(function (err) {
954
- * assert.ok(err)
955
- * })
946
+ * const product = await product.remove().catch(function (err) {
947
+ * assert.ok(err);
948
+ * });
949
+ * const foundProduct = await Product.findById(product._id);
950
+ * console.log(foundProduct) // null
956
951
  *
957
952
  * @param {Object} [options]
958
953
  * @param {Session} [options.session=null] the [session](https://docs.mongodb.com/manual/reference/server-sessions/) associated with this operation. If not specified, defaults to the [document's associated session](api.html#document_Document-$session).
@@ -995,6 +990,7 @@ Model.prototype.delete = Model.prototype.remove;
995
990
  * Removes this document from the db. Equivalent to `.remove()`.
996
991
  *
997
992
  * #### Example:
993
+ *
998
994
  * product = await product.deleteOne();
999
995
  * await Product.findById(product._id); // null
1000
996
  *
@@ -1104,6 +1100,7 @@ Model.prototype.$model = function $model(name) {
1104
1100
  * `MyModel.findOne({ answer: 42 }).select({ _id: 1 }).lean()`
1105
1101
  *
1106
1102
  * #### Example:
1103
+ *
1107
1104
  * await Character.deleteMany({});
1108
1105
  * await Character.create({ name: 'Jean-Luc Picard' });
1109
1106
  *
@@ -1273,7 +1270,7 @@ for (const i in EventEmitter.prototype) {
1273
1270
  *
1274
1271
  * #### Example:
1275
1272
  *
1276
- * const eventSchema = new Schema({ thing: { type: 'string', unique: true }})
1273
+ * const eventSchema = new Schema({ thing: { type: 'string', unique: true } })
1277
1274
  * // This calls `Event.init()` implicitly, so you don't need to call
1278
1275
  * // `Event.init()` on your own.
1279
1276
  * const Event = mongoose.model('Event', eventSchema);
@@ -1491,7 +1488,7 @@ Model.syncIndexes = function syncIndexes(options, callback) {
1491
1488
  * Model.syncIndexes().
1492
1489
  *
1493
1490
  * @param {Object} [options]
1494
- * @param {Function} callback optional callback
1491
+ * @param {Function} [callback] optional callback
1495
1492
  * @returns {Promise} which contains an object, {toDrop, toCreate}, which
1496
1493
  * are indexes that would be dropped in MongoDB and indexes that would be created in MongoDB.
1497
1494
  */
@@ -1655,7 +1652,7 @@ Model.listIndexes = function init(callback) {
1655
1652
  *
1656
1653
  * #### Example:
1657
1654
  *
1658
- * const eventSchema = new Schema({ thing: { type: 'string', unique: true }})
1655
+ * const eventSchema = new Schema({ thing: { type: 'string', unique: true } })
1659
1656
  * const Event = mongoose.model('Event', eventSchema);
1660
1657
  *
1661
1658
  * Event.on('index', function (err) {
@@ -1890,6 +1887,7 @@ Model.discriminators;
1890
1887
  * .exec(function(err, characters) {})
1891
1888
  *
1892
1889
  * #### Note:
1890
+ *
1893
1891
  * Only translate arguments of object type anything else is returned raw
1894
1892
  *
1895
1893
  * @param {Object} fields fields/conditions that may contain aliased keys
@@ -2386,7 +2384,7 @@ Model.count = function count(conditions, callback) {
2386
2384
  *
2387
2385
  * #### Example:
2388
2386
  *
2389
- * Link.distinct('url', { clicks: {$gt: 100}}, function (err, result) {
2387
+ * Link.distinct('url', { clicks: { $gt: 100 } }, function (err, result) {
2390
2388
  * if (err) return handleError(err);
2391
2389
  *
2392
2390
  * assert(Array.isArray(result));
@@ -2422,7 +2420,7 @@ Model.distinct = function distinct(field, conditions, callback) {
2422
2420
  *
2423
2421
  * For example, instead of writing:
2424
2422
  *
2425
- * User.find({age: {$gte: 21, $lte: 65}}, callback);
2423
+ * User.find({ age: { $gte: 21, $lte: 65 } }, callback);
2426
2424
  *
2427
2425
  * we can instead write:
2428
2426
  *
@@ -2476,19 +2474,6 @@ Model.$where = function $where() {
2476
2474
  *
2477
2475
  * Finds a matching document, updates it according to the `update` arg, passing any `options`, and returns the found document (if any) to the callback. The query executes if `callback` is passed else a Query object is returned.
2478
2476
  *
2479
- * #### Options:
2480
- *
2481
- * - `new`: bool - if true, return the modified document rather than the original. defaults to false (changed in 4.0)
2482
- * - `upsert`: bool - creates the object if it doesn't exist. defaults to false.
2483
- * - `overwrite`: bool - if true, replace the entire document.
2484
- * - `fields`: {Object|String} - Field selection. Equivalent to `.select(fields).findOneAndUpdate()`
2485
- * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
2486
- * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
2487
- * - `runValidators`: if true, runs [update validators](/docs/validation.html#update-validators) on this command. Update validators validate the update operation against the model's schema.
2488
- * - `setDefaultsOnInsert`: `true` by default. If `setDefaultsOnInsert` and `upsert` are true, mongoose will apply the [defaults](https://mongoosejs.com/docs/defaults.html) specified in the model's schema if a new document is created.
2489
- * - `rawResult`: if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
2490
- * - `strict`: overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict) for this update
2491
- *
2492
2477
  * #### Examples:
2493
2478
  *
2494
2479
  * A.findOneAndUpdate(conditions, update, options, callback) // executes
@@ -2534,6 +2519,13 @@ Model.$where = function $where() {
2534
2519
  * @param {Boolean} [options.overwrite=false] By default, if you don't include any [update operators](https://docs.mongodb.com/manual/reference/operator/update/) in `update`, Mongoose will wrap `update` in `$set` for you. This prevents you from accidentally overwriting the document. This option tells Mongoose to skip adding `$set`. An alternative to this would be using [Model.findOneAndReplace(conditions, update, options, callback)](https://mongoosejs.com/docs/api/model.html#model_Model.findOneAndReplace).
2535
2520
  * @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
2536
2521
  * @param {Object|String|String[]} [options.projection=null] optional fields to return, see [`Query.prototype.select()`](#query_Query-select)
2522
+ * @param {Boolean} [options.new=false] if true, return the modified document rather than the original
2523
+ * @param {Object|String} [options.fields] Field selection. Equivalent to `.select(fields).findOneAndUpdate()`
2524
+ * @param {Number} [options.maxTimeMS] puts a time limit on the query - requires mongodb >= 2.6.0
2525
+ * @param {Object|String} [options.sort] if multiple docs are found by the conditions, sets the sort order to choose which doc to update.
2526
+ * @param {Boolean} [options.runValidators] if true, runs [update validators](/docs/validation.html#update-validators) on this command. Update validators validate the update operation against the model's schema
2527
+ * @param {Boolean} [options.setDefaultsOnInsert=true] If `setDefaultsOnInsert` and `upsert` are true, mongoose will apply the [defaults](https://mongoosejs.com/docs/defaults.html) specified in the model's schema if a new document is created
2528
+ * @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
2537
2529
  * @param {Function} [callback]
2538
2530
  * @return {Query}
2539
2531
  * @see Tutorial /docs/tutorials/findoneandupdate.html
@@ -2614,17 +2606,6 @@ function _decorateUpdateWithVersionKey(update, options, versionKey) {
2614
2606
  *
2615
2607
  * - `findOneAndUpdate()`
2616
2608
  *
2617
- * #### Options:
2618
- *
2619
- * - `new`: bool - true to return the modified document rather than the original. defaults to false
2620
- * - `upsert`: bool - creates the object if it doesn't exist. defaults to false.
2621
- * - `runValidators`: if true, runs [update validators](/docs/validation.html#update-validators) on this command. Update validators validate the update operation against the model's schema.
2622
- * - `setDefaultsOnInsert`: `true` by default. If `setDefaultsOnInsert` and `upsert` are true, mongoose will apply the [defaults](https://mongoosejs.com/docs/defaults.html) specified in the model's schema if a new document is created.
2623
- * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
2624
- * - `select`: sets the document fields to return
2625
- * - `rawResult`: if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
2626
- * - `strict`: overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict) for this update
2627
- *
2628
2609
  * #### Examples:
2629
2610
  *
2630
2611
  * A.findByIdAndUpdate(id, update, options, callback) // executes
@@ -2654,11 +2635,9 @@ function _decorateUpdateWithVersionKey(update, options, versionKey) {
2654
2635
  * If you need full-fledged validation, use the traditional approach of first
2655
2636
  * retrieving the document.
2656
2637
  *
2657
- * Model.findById(id, function (err, doc) {
2658
- * if (err) ..
2659
- * doc.name = 'jason bourne';
2660
- * doc.save(callback);
2661
- * });
2638
+ * const doc = await Model.findById(id)
2639
+ * doc.name = 'jason bourne';
2640
+ * await doc.save();
2662
2641
  *
2663
2642
  * @param {Object|Number|String} id value of `_id` to query by
2664
2643
  * @param {Object} [update]
@@ -2669,6 +2648,13 @@ function _decorateUpdateWithVersionKey(update, options, versionKey) {
2669
2648
  * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
2670
2649
  * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
2671
2650
  * @param {Boolean} [options.overwrite=false] By default, if you don't include any [update operators](https://docs.mongodb.com/manual/reference/operator/update/) in `update`, Mongoose will wrap `update` in `$set` for you. This prevents you from accidentally overwriting the document. This option tells Mongoose to skip adding `$set`. An alternative to this would be using [Model.findOneAndReplace({ _id: id }, update, options, callback)](https://mongoosejs.com/docs/api/model.html#model_Model.findOneAndReplace).
2651
+ * @param {Object|String} [options.sort] if multiple docs are found by the conditions, sets the sort order to choose which doc to update.
2652
+ * @param {Boolean} [options.runValidators] if true, runs [update validators](/docs/validation.html#update-validators) on this command. Update validators validate the update operation against the model's schema
2653
+ * @param {Boolean} [options.setDefaultsOnInsert=true] If `setDefaultsOnInsert` and `upsert` are true, mongoose will apply the [defaults](https://mongoosejs.com/docs/defaults.html) specified in the model's schema if a new document is created
2654
+ * @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
2655
+ * @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
2656
+ * @param {Boolean} [options.new=false] if true, return the modified document rather than the original
2657
+ * @param {Object|String} [options.select] sets the document fields to return.
2672
2658
  * @param {Function} [callback]
2673
2659
  * @return {Query}
2674
2660
  * @see Model.findOneAndUpdate #model_Model.findOneAndUpdate
@@ -2717,15 +2703,6 @@ Model.findByIdAndUpdate = function(id, update, options, callback) {
2717
2703
  * this distinction is purely pedantic. You should use `findOneAndDelete()`
2718
2704
  * unless you have a good reason not to.
2719
2705
  *
2720
- * #### Options:
2721
- *
2722
- * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
2723
- * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
2724
- * - `select`: sets the document fields to return, ex. `{ projection: { _id: 0 } }`
2725
- * - `projection`: equivalent to `select`
2726
- * - `rawResult`: if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
2727
- * - `strict`: overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict) for this update
2728
- *
2729
2706
  * #### Examples:
2730
2707
  *
2731
2708
  * A.findOneAndDelete(conditions, options, callback) // executes
@@ -2740,17 +2717,19 @@ Model.findByIdAndUpdate = function(id, update, options, callback) {
2740
2717
  * If you need full-fledged validation, use the traditional approach of first
2741
2718
  * retrieving the document.
2742
2719
  *
2743
- * Model.findById(id, function (err, doc) {
2744
- * if (err) ..
2745
- * doc.name = 'jason bourne';
2746
- * doc.save(callback);
2747
- * });
2720
+ * const doc = await Model.findById(id)
2721
+ * doc.name = 'jason bourne';
2722
+ * await doc.save();
2748
2723
  *
2749
2724
  * @param {Object} conditions
2750
2725
  * @param {Object} [options] optional see [`Query.prototype.setOptions()`](https://mongoosejs.com/docs/api.html#query_Query-setOptions)
2751
2726
  * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
2752
2727
  * @param {Object|String|String[]} [options.projection=null] optional fields to return, see [`Query.prototype.select()`](#query_Query-select)
2753
2728
  * @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](/docs/transactions.html).
2729
+ * @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
2730
+ * @param {Object|String} [options.sort] if multiple docs are found by the conditions, sets the sort order to choose which doc to update.
2731
+ * @param {Object|String} [options.select] sets the document fields to return.
2732
+ * @param {Number} [options.maxTimeMS] puts a time limit on the query - requires mongodb >= 2.6.0
2754
2733
  * @param {Function} [callback]
2755
2734
  * @return {Query}
2756
2735
  * @api public
@@ -2830,15 +2809,6 @@ Model.findByIdAndDelete = function(id, options, callback) {
2830
2809
  *
2831
2810
  * - `findOneAndReplace()`
2832
2811
  *
2833
- * #### Options:
2834
- *
2835
- * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
2836
- * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
2837
- * - `select`: sets the document fields to return
2838
- * - `projection`: like select, it determines which fields to return, ex. `{ projection: { _id: 0 } }`
2839
- * - `rawResult`: if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
2840
- * - `strict`: overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict) for this update
2841
- *
2842
2812
  * #### Examples:
2843
2813
  *
2844
2814
  * A.findOneAndReplace(filter, replacement, options, callback) // executes
@@ -2856,6 +2826,10 @@ Model.findByIdAndDelete = function(id, options, callback) {
2856
2826
  * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
2857
2827
  * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
2858
2828
  * @param {Object|String|String[]} [options.projection=null] optional fields to return, see [`Query.prototype.select()`](#query_Query-select)
2829
+ * @param {Object|String} [options.sort] if multiple docs are found by the conditions, sets the sort order to choose which doc to update.
2830
+ * @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
2831
+ * @param {Object|String} [options.select] sets the document fields to return.
2832
+ * @param {Number} [options.maxTimeMS] puts a time limit on the query - requires mongodb >= 2.6.0
2859
2833
  * @param {Function} [callback]
2860
2834
  * @return {Query}
2861
2835
  * @api public
@@ -2909,15 +2883,6 @@ Model.findOneAndReplace = function(filter, replacement, options, callback) {
2909
2883
  *
2910
2884
  * - `findOneAndRemove()`
2911
2885
  *
2912
- * #### Options:
2913
- *
2914
- * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
2915
- * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
2916
- * - `select`: sets the document fields to return
2917
- * - `projection`: like select, it determines which fields to return, ex. `{ projection: { _id: 0 } }`
2918
- * - `rawResult`: if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
2919
- * - `strict`: overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict) for this update
2920
- *
2921
2886
  * #### Examples:
2922
2887
  *
2923
2888
  * A.findOneAndRemove(conditions, options, callback) // executes
@@ -2932,17 +2897,19 @@ Model.findOneAndReplace = function(filter, replacement, options, callback) {
2932
2897
  * If you need full-fledged validation, use the traditional approach of first
2933
2898
  * retrieving the document.
2934
2899
  *
2935
- * Model.findById(id, function (err, doc) {
2936
- * if (err) ..
2937
- * doc.name = 'jason bourne';
2938
- * doc.save(callback);
2939
- * });
2900
+ * const doc = await Model.findById(id);
2901
+ * doc.name = 'jason bourne';
2902
+ * await doc.save();
2940
2903
  *
2941
2904
  * @param {Object} conditions
2942
2905
  * @param {Object} [options] optional see [`Query.prototype.setOptions()`](https://mongoosejs.com/docs/api.html#query_Query-setOptions)
2943
2906
  * @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](/docs/transactions.html).
2944
2907
  * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
2945
2908
  * @param {Object|String|String[]} [options.projection=null] optional fields to return, see [`Query.prototype.select()`](#query_Query-select)
2909
+ * @param {Object|String} [options.sort] if multiple docs are found by the conditions, sets the sort order to choose which doc to update.
2910
+ * @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
2911
+ * @param {Object|String} [options.select] sets the document fields to return.
2912
+ * @param {Number} [options.maxTimeMS] puts a time limit on the query - requires mongodb >= 2.6.0
2946
2913
  * @param {Function} [callback]
2947
2914
  * @return {Query}
2948
2915
  * @see mongodb https://www.mongodb.org/display/DOCS/findAndModify+Command
@@ -2989,13 +2956,6 @@ Model.findOneAndRemove = function(conditions, options, callback) {
2989
2956
  *
2990
2957
  * - `findOneAndRemove()`
2991
2958
  *
2992
- * #### Options:
2993
- *
2994
- * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
2995
- * - `select`: sets the document fields to return
2996
- * - `rawResult`: if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
2997
- * - `strict`: overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict) for this update
2998
- *
2999
2959
  * #### Examples:
3000
2960
  *
3001
2961
  * A.findByIdAndRemove(id, options, callback) // executes
@@ -3009,6 +2969,9 @@ Model.findOneAndRemove = function(conditions, options, callback) {
3009
2969
  * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
3010
2970
  * @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](/docs/transactions.html).
3011
2971
  * @param {Object|String|String[]} [options.projection=null] optional fields to return, see [`Query.prototype.select()`](#query_Query-select)
2972
+ * @param {Object|String} [options.sort] if multiple docs are found by the conditions, sets the sort order to choose which doc to update.
2973
+ * @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
2974
+ * @param {Object|String} [options.select] sets the document fields to return.
3012
2975
  * @param {Function} [callback]
3013
2976
  * @return {Query}
3014
2977
  * @see Model.findOneAndRemove #model_Model.findOneAndRemove
@@ -3396,7 +3359,7 @@ Model.$__insertMany = function(arr, options, callback) {
3396
3359
  if (doc.$__schema.options.versionKey) {
3397
3360
  doc[doc.$__schema.options.versionKey] = 0;
3398
3361
  }
3399
- if (doc.initializeTimestamps) {
3362
+ if ((!options || options.timestamps !== false) && doc.initializeTimestamps) {
3400
3363
  return doc.initializeTimestamps().toObject(internalToObjectOptions);
3401
3364
  }
3402
3365
  return doc.toObject(internalToObjectOptions);
@@ -3687,11 +3650,13 @@ function handleSuccessfulWrite(document, resolve, reject) {
3687
3650
  }
3688
3651
 
3689
3652
  /**
3653
+ * Build bulk write operations for `bulkSave()`.
3690
3654
  *
3691
3655
  * @param {Array<Document>} documents The array of documents to build write operations of
3692
3656
  * @param {Object} options
3693
3657
  * @param {Boolean} options.skipValidation defaults to `false`, when set to true, building the write operations will bypass validating the documents.
3694
3658
  * @return {Array<Promise>} Returns a array of all Promises the function executes to be awaited.
3659
+ * @api private
3695
3660
  */
3696
3661
  Model.buildBulkWriteOperations = function buildBulkWriteOperations(documents, options) {
3697
3662
  if (!Array.isArray(documents)) {
@@ -3856,7 +3821,6 @@ Model.hydrate = function(obj, projection) {
3856
3821
  * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
3857
3822
  * @param {Boolean} [options.overwrite=false] By default, if you don't include any [update operators](https://docs.mongodb.com/manual/reference/operator/update/) in `doc`, Mongoose will wrap `doc` in `$set` for you. This prevents you from accidentally overwriting the document. This option tells Mongoose to skip adding `$set`.
3858
3823
  * @param {Function} [callback] params are (error, [updateWriteOpResult](https://mongodb.github.io/node-mongodb-native/3.6/api/Collection.html#~updateWriteOpResult))
3859
- * @param {Function} [callback]
3860
3824
  * @return {Query}
3861
3825
  * @see MongoDB docs https://docs.mongodb.com/manual/reference/command/update/#update-command-output
3862
3826
  * @see writeOpResult https://mongodb.github.io/node-mongodb-native/3.6/api/Collection.html#~updateWriteOpResult
@@ -4022,54 +3986,34 @@ function _update(model, op, conditions, doc, options, callback) {
4022
3986
  /**
4023
3987
  * Executes a mapReduce command.
4024
3988
  *
4025
- * `o` is an object specifying all mapReduce options as well as the map and reduce functions. All options are delegated to the driver implementation. See [node-mongodb-native mapReduce() documentation](https://mongodb.github.io/node-mongodb-native/api-generated/collection.html#mapreduce) for more detail about options.
3989
+ * `opts` is an object specifying all mapReduce options as well as the map and reduce functions. All options are delegated to the driver implementation. See [node-mongodb-native mapReduce() documentation](https://mongodb.github.io/node-mongodb-native/api-generated/collection.html#mapreduce) for more detail about options.
4026
3990
  *
4027
3991
  * This function does not trigger any middleware.
4028
3992
  *
4029
3993
  * #### Example:
4030
3994
  *
4031
- * const o = {};
3995
+ * const opts = {};
4032
3996
  * // `map()` and `reduce()` are run on the MongoDB server, not Node.js,
4033
3997
  * // these functions are converted to strings
4034
- * o.map = function () { emit(this.name, 1) };
4035
- * o.reduce = function (k, vals) { return vals.length };
4036
- * User.mapReduce(o, function (err, results) {
3998
+ * opts.map = function () { emit(this.name, 1) };
3999
+ * opts.reduce = function (k, vals) { return vals.length };
4000
+ * User.mapReduce(opts, function (err, results) {
4037
4001
  * console.log(results)
4038
4002
  * })
4039
4003
  *
4040
- * #### Other options:
4041
- *
4042
- * - `query` {Object} query filter object.
4043
- * - `sort` {Object} sort input objects using this key
4044
- * - `limit` {Number} max number of documents
4045
- * - `keeptemp` {Boolean, default:false} keep temporary data
4046
- * - `finalize` {Function} finalize function
4047
- * - `scope` {Object} scope variables exposed to map/reduce/finalize during execution
4048
- * - `jsMode` {Boolean, default:false} it is possible to make the execution stay in JS. Provided in MongoDB > 2.0.X
4049
- * - `verbose` {Boolean, default:false} provide statistics on job execution time.
4050
- * - `readPreference` {String}
4051
- * - `out*` {Object, default: {inline:1}} sets the output target for the map reduce job.
4052
- *
4053
- * #### * out options:
4054
- *
4055
- * - `{inline:1}` the results are returned in an array
4056
- * - `{replace: 'collectionName'}` add the results to collectionName: the results replace the collection
4057
- * - `{reduce: 'collectionName'}` add the results to collectionName: if dups are detected, uses the reducer / finalize functions
4058
- * - `{merge: 'collectionName'}` add the results to collectionName: if dups exist the new docs overwrite the old
4059
- *
4060
- * If `options.out` is set to `replace`, `merge`, or `reduce`, a Model instance is returned that can be used for further querying. Queries run against this model are all executed with the [`lean` option](/docs/tutorials/lean.html); meaning only the js object is returned and no Mongoose magic is applied (getters, setters, etc).
4004
+ * If `opts.out` is set to `replace`, `merge`, or `reduce`, a Model instance is returned that can be used for further querying. Queries run against this model are all executed with the [`lean` option](/docs/tutorials/lean.html); meaning only the js object is returned and no Mongoose magic is applied (getters, setters, etc).
4061
4005
  *
4062
4006
  * #### Example:
4063
4007
  *
4064
- * const o = {};
4008
+ * const opts = {};
4065
4009
  * // You can also define `map()` and `reduce()` as strings if your
4066
4010
  * // linter complains about `emit()` not being defined
4067
- * o.map = 'function () { emit(this.name, 1) }';
4068
- * o.reduce = 'function (k, vals) { return vals.length }';
4069
- * o.out = { replace: 'createdCollectionNameForResults' }
4070
- * o.verbose = true;
4011
+ * opts.map = 'function () { emit(this.name, 1) }';
4012
+ * opts.reduce = 'function (k, vals) { return vals.length }';
4013
+ * opts.out = { replace: 'createdCollectionNameForResults' }
4014
+ * opts.verbose = true;
4071
4015
  *
4072
- * User.mapReduce(o, function (err, model, stats) {
4016
+ * User.mapReduce(opts, function (err, model, stats) {
4073
4017
  * console.log('map reduce took %d ms', stats.processtime)
4074
4018
  * model.find().where('value').gt(10).exec(function (err, docs) {
4075
4019
  * console.log(docs);
@@ -4078,8 +4022,8 @@ function _update(model, op, conditions, doc, options, callback) {
4078
4022
  *
4079
4023
  * // `mapReduce()` returns a promise. However, ES6 promises can only
4080
4024
  * // resolve to exactly one value,
4081
- * o.resolveToObject = true;
4082
- * const promise = User.mapReduce(o);
4025
+ * opts.resolveToObject = true;
4026
+ * const promise = User.mapReduce(opts);
4083
4027
  * promise.then(function (res) {
4084
4028
  * const model = res.model;
4085
4029
  * const stats = res.stats;
@@ -4089,14 +4033,28 @@ function _update(model, op, conditions, doc, options, callback) {
4089
4033
  * console.log(docs);
4090
4034
  * }).then(null, handleError).end()
4091
4035
  *
4092
- * @param {Object} o an object specifying map-reduce options
4036
+ * @param {Object} opts an object specifying map-reduce options
4037
+ * @param {Boolean} [opts.verbose=false] provide statistics on job execution time
4038
+ * @param {ReadPreference|String} [opts.readPreference] a read-preference string or a read-preference instance
4039
+ * @param {Boolean} [opts.jsMode=false] it is possible to make the execution stay in JS. Provided in MongoDB > 2.0.X
4040
+ * @param {Object} [opts.scope] scope variables exposed to map/reduce/finalize during execution
4041
+ * @param {Function} [opts.finalize] finalize function
4042
+ * @param {Boolean} [opts.keeptemp=false] keep temporary data
4043
+ * @param {Number} [opts.limit] max number of documents
4044
+ * @param {Object} [opts.sort] sort input objects using this key
4045
+ * @param {Object} [opts.query] query filter object
4046
+ * @param {Object} [opts.out] sets the output target for the map reduce job
4047
+ * @param {Number} [opts.out.inline=1] the results are returned in an array
4048
+ * @param {String} [opts.out.replace] add the results to collectionName: the results replace the collection
4049
+ * @param {String} [opts.out.reduce] add the results to collectionName: if dups are detected, uses the reducer / finalize functions
4050
+ * @param {String} [opts.out.merge] add the results to collectionName: if dups exist the new docs overwrite the old
4093
4051
  * @param {Function} [callback] optional callback
4094
4052
  * @see https://www.mongodb.org/display/DOCS/MapReduce
4095
4053
  * @return {Promise}
4096
4054
  * @api public
4097
4055
  */
4098
4056
 
4099
- Model.mapReduce = function mapReduce(o, callback) {
4057
+ Model.mapReduce = function mapReduce(opts, callback) {
4100
4058
  _checkContext(this, 'mapReduce');
4101
4059
 
4102
4060
  callback = this.$handleCallbackError(callback);
@@ -4109,20 +4067,20 @@ Model.mapReduce = function mapReduce(o, callback) {
4109
4067
  Model.mapReduce.schema = new Schema({}, opts);
4110
4068
  }
4111
4069
 
4112
- if (!o.out) o.out = { inline: 1 };
4113
- if (o.verbose !== false) o.verbose = true;
4070
+ if (!opts.out) opts.out = { inline: 1 };
4071
+ if (opts.verbose !== false) opts.verbose = true;
4114
4072
 
4115
- o.map = String(o.map);
4116
- o.reduce = String(o.reduce);
4073
+ opts.map = String(opts.map);
4074
+ opts.reduce = String(opts.reduce);
4117
4075
 
4118
- if (o.query) {
4119
- let q = new this.Query(o.query);
4076
+ if (opts.query) {
4077
+ let q = new this.Query(opts.query);
4120
4078
  q.cast(this);
4121
- o.query = q._conditions;
4079
+ opts.query = q._conditions;
4122
4080
  q = undefined;
4123
4081
  }
4124
4082
 
4125
- this.$__collection.mapReduce(null, null, o, (err, res) => {
4083
+ this.$__collection.mapReduce(null, null, opts, (err, res) => {
4126
4084
  if (err) {
4127
4085
  return cb(err);
4128
4086
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "6.4.4",
4
+ "version": "6.4.5",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -60,7 +60,7 @@
60
60
  "serve-handler": "6.1.3",
61
61
  "sinon": "14.0.0",
62
62
  "stream-browserify": "3.0.0",
63
- "ts-benchmark": "^1.0.2",
63
+ "ts-benchmark": "^1.1.5",
64
64
  "tsd": "0.20.0",
65
65
  "typescript": "4.7.4",
66
66
  "uuid": "8.3.2",
@@ -98,8 +98,8 @@
98
98
  "test-tsd": "node ./test/types/check-types-filename && tsd",
99
99
  "tdd": "mocha ./test/*.test.js --inspect --watch --recursive --watch-files ./**/*.{js,ts}",
100
100
  "test-coverage": "nyc --reporter=html --reporter=text npm test",
101
- "ts-benchmark": "node ./benchmarks/typescript.js",
102
- "ts-benchmark-watch": "ts-benchmark -p ./benchmarks/typescript/simple -w ./types -i -s -f 17 18 29 32 -b master"
101
+ "ts-benchmark": "ts-benchmark -p ./benchmarks/typescript/simple -f 17/100000 18 29 32",
102
+ "ts-benchmark-watch": "ts-benchmark -p ./benchmarks/typescript/simple -w ./types -i -s -f 17/100000 18 29 32 -b master"
103
103
  },
104
104
  "main": "./index.js",
105
105
  "types": "./types/index.d.ts",
@@ -1067,13 +1067,13 @@ declare module 'mongoose' {
1067
1067
  * - $case
1068
1068
  * - $then
1069
1069
  */
1070
- $branches: { $case: Expression, then: Expression }[];
1070
+ branches: { case: Expression, then: Expression }[];
1071
1071
  /**
1072
1072
  * The path to take if no branch case expression evaluates to true.
1073
1073
  *
1074
1074
  * Although optional, if default is unspecified and no branch case evaluates to true, $switch returns an error.
1075
1075
  */
1076
- $default: Expression;
1076
+ default: Expression;
1077
1077
  };
1078
1078
  }
1079
1079
 
@@ -1104,7 +1104,7 @@ declare module 'mongoose' {
1104
1104
  * @version 3.2
1105
1105
  * @see https://docs.mongodb.com/manual/reference/operator/aggregation/concatArrays/#mongodb-expression-exp.-concatArrays
1106
1106
  */
1107
- $concatArrays: ArrayExpression[];
1107
+ $concatArrays: Expression[];
1108
1108
  }
1109
1109
 
1110
1110
  export interface Filter {
@@ -2448,7 +2448,8 @@ declare module 'mongoose' {
2448
2448
  BinaryExpression |
2449
2449
  FunctionExpression |
2450
2450
  ObjectIdExpression |
2451
- ConditionalExpressionOperator;
2451
+ ConditionalExpressionOperator |
2452
+ any;
2452
2453
 
2453
2454
  export type ObjectIdExpression =
2454
2455
  TypeExpressionOperatorReturningObjectId;
package/types/index.d.ts CHANGED
@@ -109,9 +109,7 @@ declare module 'mongoose' {
109
109
  }
110
110
 
111
111
  export type Require_id<T> = T extends { _id?: infer U }
112
- ? U extends any
113
- ? (T & { _id: Types.ObjectId })
114
- : T & Required<{ _id: U }>
112
+ ? IfAny<U, T & { _id: Types.ObjectId }, T & Required<{ _id: U }>>
115
113
  : T & { _id: Types.ObjectId };
116
114
 
117
115
  export type RequireOnlyTypedId<T> = T extends { _id?: infer U; }
@@ -439,6 +437,10 @@ declare module 'mongoose' {
439
437
 
440
438
  export type SortOrder = -1 | 1 | 'asc' | 'ascending' | 'desc' | 'descending';
441
439
 
440
+ type Mutable<T> = {
441
+ -readonly [K in keyof T]: T[K];
442
+ };
443
+
442
444
  type _UpdateQuery<TSchema> = {
443
445
  /** @see https://docs.mongodb.com/manual/reference/operator/update-field/ */
444
446
  $currentDate?: AnyKeys<TSchema> & AnyObject;
@@ -452,10 +454,10 @@ declare module 'mongoose' {
452
454
  $unset?: AnyKeys<TSchema> & AnyObject;
453
455
 
454
456
  /** @see https://docs.mongodb.com/manual/reference/operator/update-array/ */
455
- $addToSet?: mongodb.SetFields<TSchema>;
457
+ $addToSet?: Mutable<mongodb.SetFields<TSchema>>;
456
458
  $pop?: AnyKeys<TSchema> & AnyObject;
457
- $pull?: mongodb.PullOperator<TSchema>;
458
- $push?: mongodb.PushOperator<TSchema>;
459
+ $pull?: Mutable<mongodb.PullOperator<TSchema>>;
460
+ $push?: Mutable<mongodb.PushOperator<TSchema>>;
459
461
  $pullAll?: mongodb.PullAllOperator<TSchema>;
460
462
 
461
463
  /** @see https://docs.mongodb.com/manual/reference/operator/update-bitwise/ */
@@ -539,7 +541,7 @@ declare module 'mongoose' {
539
541
  export type SchemaDefinitionType<T> = T extends Document ? Omit<T, Exclude<keyof Document, '_id' | 'id' | '__v'>> : T;
540
542
 
541
543
  // Helpers to simplify checks
542
- type IfAny<IFTYPE, THENTYPE> = 0 extends (1 & IFTYPE) ? THENTYPE : IFTYPE;
544
+ type IfAny<IFTYPE, THENTYPE, ELSETYPE = IFTYPE> = 0 extends (1 & IFTYPE) ? THENTYPE : ELSETYPE;
543
545
  type IfUnknown<IFTYPE, THENTYPE> = unknown extends IFTYPE ? THENTYPE : IFTYPE;
544
546
 
545
547
  // tests for these two types are located in test/types/lean.test.ts
@@ -51,8 +51,8 @@ declare module 'mongoose' {
51
51
  * the model's schema except the `_id` index, and build any indexes that
52
52
  * are in your schema but not in MongoDB.
53
53
  */
54
- syncIndexes(options: mongodb.CreateIndexesOptions | null, callback: Callback<Array<string>>): void;
55
- syncIndexes(options?: mongodb.CreateIndexesOptions): Promise<Array<string>>;
54
+ syncIndexes(options: SyncIndexesOptions | null, callback: Callback<Array<string>>): void;
55
+ syncIndexes(options?: SyncIndexesOptions): Promise<Array<string>>;
56
56
  }
57
57
 
58
58
  interface IndexesDiff {
@@ -1,4 +1,18 @@
1
- import { Schema, InferSchemaType, SchemaType, SchemaTypeOptions, TypeKeyBaseType, Types, NumberSchemaDefinition, StringSchemaDefinition, BooleanSchemaDefinition, DateSchemaDefinition } from 'mongoose';
1
+ import {
2
+ Schema,
3
+ InferSchemaType,
4
+ SchemaType,
5
+ SchemaTypeOptions,
6
+ TypeKeyBaseType,
7
+ Types,
8
+ NumberSchemaDefinition,
9
+ StringSchemaDefinition,
10
+ BooleanSchemaDefinition,
11
+ DateSchemaDefinition,
12
+ ObtainDocumentType,
13
+ DefaultTypeKey,
14
+ ObjectIdSchemaDefinition
15
+ } from 'mongoose';
2
16
 
3
17
  declare module 'mongoose' {
4
18
  /**
@@ -75,9 +89,9 @@ type IsPathRequired<P, TypeKey extends TypeKeyBaseType> =
75
89
  ? P extends { default: undefined }
76
90
  ? false
77
91
  : true
78
- : P extends (Record<TypeKey, NumberSchemaDefinition | StringSchemaDefinition | BooleanSchemaDefinition | DateSchemaDefinition>)
79
- ? P extends { default: ResolvePathType<P[TypeKey]> }
80
- ? true
92
+ : P extends (Record<TypeKey, any>)
93
+ ? P extends { default: any }
94
+ ? IfEquals<P['default'], undefined, false, true>
81
95
  : false
82
96
  : false;
83
97
 
@@ -138,7 +152,8 @@ type ObtainDocumentPathType<PathValueType, TypeKey extends TypeKeyBaseType> = Pa
138
152
  ? InferSchemaType<PathValueType>
139
153
  : ResolvePathType<
140
154
  PathValueType extends PathWithTypePropertyBaseType<TypeKey> ? PathValueType[TypeKey] : PathValueType,
141
- PathValueType extends PathWithTypePropertyBaseType<TypeKey> ? Omit<PathValueType, TypeKey> : {}
155
+ PathValueType extends PathWithTypePropertyBaseType<TypeKey> ? Omit<PathValueType, TypeKey> : {},
156
+ TypeKey
142
157
  >;
143
158
 
144
159
  /**
@@ -151,17 +166,18 @@ type PathEnumOrString<T extends SchemaTypeOptions<string>['enum']> = T extends (
151
166
  * @summary Resolve path type by returning the corresponding type.
152
167
  * @param {PathValueType} PathValueType Document definition path type.
153
168
  * @param {Options} Options Document definition path options except path type.
154
- * @returns Number, "Number" or "number" will be resolved to string type.
169
+ * @param {TypeKey} TypeKey A generic of literal string type."Refers to the property used for path type definition".
170
+ * @returns Number, "Number" or "number" will be resolved to number type.
155
171
  */
156
- type ResolvePathType<PathValueType, Options extends SchemaTypeOptions<PathValueType> = {}> =
172
+ type ResolvePathType<PathValueType, Options extends SchemaTypeOptions<PathValueType> = {}, TypeKey extends TypeKeyBaseType = DefaultTypeKey> =
157
173
  PathValueType extends Schema ? InferSchemaType<PathValueType> :
158
- PathValueType extends (infer Item)[] ? IfEquals<Item, never, any, ResolvePathType<Item>>[] :
174
+ PathValueType extends (infer Item)[] ? IfEquals<Item, never, any[], Item extends Schema ? Types.DocumentArray<ResolvePathType<Item>> : ResolvePathType<Item>[]> :
159
175
  PathValueType extends StringSchemaDefinition ? PathEnumOrString<Options['enum']> :
160
176
  PathValueType extends NumberSchemaDefinition ? number :
161
177
  PathValueType extends DateSchemaDefinition ? Date :
162
178
  PathValueType extends typeof Buffer | 'buffer' | 'Buffer' | typeof Schema.Types.Buffer ? Buffer :
163
179
  PathValueType extends BooleanSchemaDefinition ? boolean :
164
- PathValueType extends 'objectId' | 'ObjectId' | typeof Schema.Types.ObjectId ? Types.ObjectId :
180
+ PathValueType extends ObjectIdSchemaDefinition ? Types.ObjectId :
165
181
  PathValueType extends 'decimal128' | 'Decimal128' | typeof Schema.Types.Decimal128 ? Types.Decimal128 :
166
182
  PathValueType extends MapConstructor ? Map<string, ResolvePathType<Options['of']>> :
167
183
  PathValueType extends ArrayConstructor ? any[] :
@@ -169,5 +185,5 @@ type ResolvePathType<PathValueType, Options extends SchemaTypeOptions<PathValueT
169
185
  IfEquals<PathValueType, ObjectConstructor> extends true ? any:
170
186
  IfEquals<PathValueType, {}> extends true ? any:
171
187
  PathValueType extends typeof SchemaType ? PathValueType['prototype'] :
172
- PathValueType extends {} ? PathValueType :
188
+ PathValueType extends Record<string, any> ? ObtainDocumentType<PathValueType, any, TypeKey> :
173
189
  unknown;