mongoose 8.5.2 → 8.5.3

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/document.js CHANGED
@@ -2770,15 +2770,6 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip) {
2770
2770
  }
2771
2771
  }
2772
2772
 
2773
- for (const path of paths) {
2774
- // Single nested paths (paths embedded under single nested subdocs) will
2775
- // be validated on their own when we call `validate()` on the subdoc itself.
2776
- // Re: gh-8468
2777
- if (doc.$__schema.singleNestedPaths.hasOwnProperty(path)) {
2778
- paths.delete(path);
2779
- continue;
2780
- }
2781
- }
2782
2773
 
2783
2774
  if (Array.isArray(pathsToValidate)) {
2784
2775
  paths = _handlePathsToValidate(paths, pathsToValidate);
@@ -2800,7 +2791,10 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip) {
2800
2791
  _v = _v.toObject({ transform: false });
2801
2792
  }
2802
2793
  const flat = flatten(_v, pathToCheck, flattenOptions, doc.$__schema);
2803
- Object.keys(flat).forEach(addToPaths);
2794
+ // Single nested paths (paths embedded under single nested subdocs) will
2795
+ // be validated on their own when we call `validate()` on the subdoc itself.
2796
+ // Re: gh-8468
2797
+ Object.keys(flat).filter(path => !doc.$__schema.singleNestedPaths.hasOwnProperty(path)).forEach(addToPaths);
2804
2798
  }
2805
2799
  }
2806
2800
 
@@ -3801,7 +3795,7 @@ Document.prototype.$__handleReject = function handleReject(err) {
3801
3795
  };
3802
3796
 
3803
3797
  /**
3804
- * Internal helper for toObject() and toJSON() that doesn't manipulate options
3798
+ * Internal common logic for toObject() and toJSON()
3805
3799
  *
3806
3800
  * @return {Object}
3807
3801
  * @api private
@@ -3834,14 +3828,17 @@ Document.prototype.$toObject = function(options, json) {
3834
3828
  }
3835
3829
 
3836
3830
  const depopulate = options._calledWithOptions.depopulate
3837
- ?? options._parentOptions?.depopulate
3838
3831
  ?? defaultOptions?.depopulate
3832
+ ?? options.depopulate
3839
3833
  ?? false;
3840
3834
  // _isNested will only be true if this is not the top level document, we
3841
3835
  // should never depopulate the top-level document
3842
3836
  if (depopulate && options._isNested && this.$__.wasPopulated) {
3843
3837
  return clone(this.$__.wasPopulated.value || this._doc._id, options);
3844
3838
  }
3839
+ if (depopulate) {
3840
+ options.depopulate = true;
3841
+ }
3845
3842
 
3846
3843
  // merge default options with input options.
3847
3844
  if (defaultOptions != null) {
@@ -3855,7 +3852,9 @@ Document.prototype.$toObject = function(options, json) {
3855
3852
  options.json = json;
3856
3853
  options.minimize = _minimize;
3857
3854
 
3858
- options._parentOptions = options;
3855
+ const parentOptions = options._parentOptions;
3856
+ // Parent options should only bubble down for subdocuments, not populated docs
3857
+ options._parentOptions = this.$isSubdocument ? options : null;
3859
3858
 
3860
3859
  options._skipSingleNestedGetters = false;
3861
3860
  // remember the root transform function
@@ -3886,6 +3885,7 @@ Document.prototype.$toObject = function(options, json) {
3886
3885
 
3887
3886
  const virtuals = options._calledWithOptions.virtuals
3888
3887
  ?? defaultOptions.virtuals
3888
+ ?? parentOptions?.virtuals
3889
3889
  ?? undefined;
3890
3890
 
3891
3891
  if (virtuals || (getters && virtuals !== false)) {
@@ -4768,7 +4768,23 @@ Document.prototype.depopulate = function(path) {
4768
4768
  continue;
4769
4769
  }
4770
4770
  delete populated[key];
4771
- utils.setValue(key, populatedIds, this._doc);
4771
+ if (Array.isArray(populatedIds)) {
4772
+ const arr = utils.getValue(key, this._doc);
4773
+ if (arr.isMongooseArray) {
4774
+ const rawArray = arr.__array;
4775
+ for (let i = 0; i < rawArray.length; ++i) {
4776
+ const subdoc = rawArray[i];
4777
+ if (subdoc == null) {
4778
+ continue;
4779
+ }
4780
+ rawArray[i] = subdoc instanceof Document ? subdoc._doc._id : subdoc._id;
4781
+ }
4782
+ } else {
4783
+ utils.setValue(key, populatedIds, this._doc);
4784
+ }
4785
+ } else {
4786
+ utils.setValue(key, populatedIds, this._doc);
4787
+ }
4772
4788
  }
4773
4789
  return this;
4774
4790
  }
@@ -4781,7 +4797,23 @@ Document.prototype.depopulate = function(path) {
4781
4797
  delete this.$$populatedVirtuals[singlePath];
4782
4798
  delete this._doc[singlePath];
4783
4799
  } else if (populatedIds) {
4784
- utils.setValue(singlePath, populatedIds, this._doc);
4800
+ if (Array.isArray(populatedIds)) {
4801
+ const arr = utils.getValue(singlePath, this._doc);
4802
+ if (arr.isMongooseArray) {
4803
+ const rawArray = arr.__array;
4804
+ for (let i = 0; i < rawArray.length; ++i) {
4805
+ const subdoc = rawArray[i];
4806
+ if (subdoc == null) {
4807
+ continue;
4808
+ }
4809
+ rawArray[i] = subdoc instanceof Document ? subdoc._doc._id : subdoc._id;
4810
+ }
4811
+ } else {
4812
+ utils.setValue(singlePath, populatedIds, this._doc);
4813
+ }
4814
+ } else {
4815
+ utils.setValue(singlePath, populatedIds, this._doc);
4816
+ }
4785
4817
  }
4786
4818
  }
4787
4819
  return this;
package/lib/model.js CHANGED
@@ -4468,7 +4468,7 @@ function _assign(model, vals, mod, assignmentOpts) {
4468
4468
  rawOrder[key].push(i);
4469
4469
  } else if (isVirtual ||
4470
4470
  rawDocs[key].constructor !== val.constructor ||
4471
- String(rawDocs[key]._doc._id) !== String(val._doc._id)) {
4471
+ (rawDocs[key] instanceof Document ? String(rawDocs[key]._doc._id) : String(rawDocs[key]._id)) !== (val instanceof Document ? String(val._doc._id) : String(val._id))) {
4472
4472
  // May need to store multiple docs with the same id if there's multiple models
4473
4473
  // if we have discriminators or a ref function. But avoid converting to an array
4474
4474
  // if we have multiple queries on the same model because of `perDocumentLimit` re: gh-9906
@@ -721,6 +721,7 @@ const methods = {
721
721
  }
722
722
 
723
723
  this._registerAtomic('$push', atomic);
724
+
724
725
  return ret;
725
726
  },
726
727
 
package/lib/types/map.js CHANGED
@@ -68,10 +68,17 @@ class MongooseMap extends Map {
68
68
  * and change tracking. Note that Mongoose maps _only_ support strings and
69
69
  * ObjectIds as keys.
70
70
  *
71
+ * Keys also cannot:
72
+ * - be named after special properties `prototype`, `constructor`, and `__proto__`
73
+ * - start with a dollar sign (`$`)
74
+ * - contain any dots (`.`)
75
+ *
71
76
  * #### Example:
72
77
  *
73
78
  * doc.myMap.set('test', 42); // works
74
79
  * doc.myMap.set({ obj: 42 }, 42); // Throws "Mongoose maps only support string keys"
80
+ * doc.myMap.set(10, 42); // Throws "Mongoose maps only support string keys"
81
+ * doc.myMap.set("$test", 42); // Throws "Mongoose maps do not support keys that start with "$", got "$test""
75
82
  *
76
83
  * @api public
77
84
  * @method set
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "8.5.2",
4
+ "version": "8.5.3",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -29,7 +29,7 @@
29
29
  },
30
30
  "devDependencies": {
31
31
  "@babel/core": "7.24.7",
32
- "@babel/preset-env": "7.24.7",
32
+ "@babel/preset-env": "7.25.3",
33
33
  "@typescript-eslint/eslint-plugin": "^6.21.0",
34
34
  "@typescript-eslint/parser": "^6.21.0",
35
35
  "acquit": "1.3.0",
@@ -49,13 +49,13 @@
49
49
  "eslint-plugin-mocha-no-only": "1.2.0",
50
50
  "express": "^4.19.2",
51
51
  "fs-extra": "~11.2.0",
52
- "highlight.js": "11.9.0",
52
+ "highlight.js": "11.10.0",
53
53
  "lodash.isequal": "4.5.0",
54
54
  "lodash.isequalwith": "4.4.0",
55
55
  "markdownlint-cli2": "^0.13.0",
56
56
  "marked": "4.3.0",
57
57
  "mkdirp": "^3.0.1",
58
- "mocha": "10.6.0",
58
+ "mocha": "10.7.0",
59
59
  "moment": "2.30.1",
60
60
  "mongodb-memory-server": "10.0.0",
61
61
  "ncp": "^2.0.0",
@@ -65,9 +65,9 @@
65
65
  "sinon": "18.0.0",
66
66
  "stream-browserify": "3.0.0",
67
67
  "tsd": "0.31.1",
68
- "typescript": "5.5.3",
68
+ "typescript": "5.5.4",
69
69
  "uuid": "10.0.0",
70
- "webpack": "5.92.1"
70
+ "webpack": "5.93.0"
71
71
  },
72
72
  "directories": {
73
73
  "lib": "./lib/mongoose"
@@ -72,7 +72,7 @@ declare module 'mongoose' {
72
72
  readonly config: any;
73
73
 
74
74
  /** The mongodb.Db instance, set when the connection is opened */
75
- readonly db: mongodb.Db;
75
+ readonly db: mongodb.Db | undefined;
76
76
 
77
77
  /**
78
78
  * Helper for `createCollection()`. Will explicitly create the given collection
package/types/cursor.d.ts CHANGED
@@ -51,7 +51,7 @@ declare module 'mongoose' {
51
51
  * Get the next document from this cursor. Will return `null` when there are
52
52
  * no documents left.
53
53
  */
54
- next(): Promise<DocType>;
54
+ next(): Promise<DocType | null>;
55
55
 
56
56
  options: Options;
57
57
  }
package/types/index.d.ts CHANGED
@@ -157,8 +157,37 @@ declare module 'mongoose' {
157
157
  >
158
158
  >
159
159
  >;
160
- export type HydratedSingleSubdocument<DocType, TOverrides = {}> = Types.Subdocument<unknown, Record<string, never>, DocType> & Require_id<DocType> & TOverrides;
161
- export type HydratedArraySubdocument<DocType, TOverrides = {}> = Types.ArraySubdocument<unknown, Record<string, never>, DocType> & Require_id<DocType> & TOverrides;
160
+ export type HydratedSingleSubdocument<
161
+ DocType,
162
+ TOverrides = {}
163
+ > = IfAny<
164
+ DocType,
165
+ any,
166
+ TOverrides extends Record<string, never> ?
167
+ Types.Subdocument<unknown, Record<string, never>, DocType> & Require_id<DocType> :
168
+ IfAny<
169
+ TOverrides,
170
+ Types.Subdocument<unknown, Record<string, never>, DocType> & Require_id<DocType>,
171
+ Types.Subdocument<unknown, Record<string, never>, DocType> & MergeType<
172
+ Require_id<DocType>,
173
+ TOverrides
174
+ >
175
+ >
176
+ >;
177
+ export type HydratedArraySubdocument<DocType, TOverrides = {}> = IfAny<
178
+ DocType,
179
+ any,
180
+ TOverrides extends Record<string, never> ?
181
+ Types.ArraySubdocument<unknown, Record<string, never>, DocType> & Require_id<DocType> :
182
+ IfAny<
183
+ TOverrides,
184
+ Types.ArraySubdocument<unknown, Record<string, never>, DocType> & Require_id<DocType>,
185
+ Types.ArraySubdocument<unknown, Record<string, never>, DocType> & MergeType<
186
+ Require_id<DocType>,
187
+ TOverrides
188
+ >
189
+ >
190
+ >;
162
191
 
163
192
  export type HydratedDocumentFromSchema<TSchema extends Schema> = HydratedDocument<
164
193
  InferSchemaType<TSchema>,
@@ -10,12 +10,12 @@ declare module 'mongoose' {
10
10
  export type InferRawDocType<
11
11
  DocDefinition,
12
12
  TSchemaOptions extends Record<any, any> = DefaultSchemaOptions
13
- > = {
13
+ > = ApplySchemaOptions<{
14
14
  [
15
15
  K in keyof (RequiredPaths<DocDefinition, TSchemaOptions['typeKey']> &
16
16
  OptionalPaths<DocDefinition, TSchemaOptions['typeKey']>)
17
17
  ]: ObtainRawDocumentPathType<DocDefinition[K], TSchemaOptions['typeKey']>;
18
- };
18
+ }, TSchemaOptions>;
19
19
 
20
20
  /**
21
21
  * @summary Obtains schema Path type.
@@ -74,14 +74,25 @@ declare module 'mongoose' {
74
74
 
75
75
  type ApplySchemaOptions<T, O = DefaultSchemaOptions> = ResolveTimestamps<T, O>;
76
76
 
77
- type ResolveTimestamps<T, O> = O extends { timestamps: true }
77
+ type ResolveTimestamps<T, O> = O extends { methods: any } | { statics: any } | { virtuals: any } | { timestamps?: false } ? T
78
78
  // For some reason, TypeScript sets all the document properties to unknown
79
79
  // if we use methods, statics, or virtuals. So avoid inferring timestamps
80
80
  // if any of these are set for now. See gh-12807
81
- ? O extends { methods: any } | { statics: any } | { virtuals: any }
82
- ? T
83
- : { createdAt: NativeDate; updatedAt: NativeDate; } & T
84
- : T;
81
+ : O extends { timestamps: infer TimestampOptions } ? TimestampOptions extends true
82
+ ? { createdAt: NativeDate; updatedAt: NativeDate; } & T
83
+ : TimestampOptions extends SchemaTimestampsConfig
84
+ ? {
85
+ -readonly [K in keyof Pick<
86
+ TimestampOptions,
87
+ 'createdAt' | 'updatedAt'
88
+ > as TimestampOptions[K] extends true
89
+ ? K
90
+ : TimestampOptions[K] extends string
91
+ ? TimestampOptions[K]
92
+ : never]: NativeDate;
93
+ } & T
94
+ : T
95
+ : T;
85
96
  }
86
97
 
87
98
  type IsPathDefaultUndefined<PathType> = PathType extends { default: undefined } ?