mongoose 9.10.0 → 9.10.2

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.
@@ -197,6 +197,11 @@ function cloneObject(obj, options, isArrayChild) {
197
197
  }
198
198
 
199
199
  function cloneArray(arr, options) {
200
+ const seen = options?._seen;
201
+ if (seen && seen.has(arr)) {
202
+ return seen.get(arr);
203
+ }
204
+
200
205
  let i = 0;
201
206
  const len = arr.length;
202
207
 
@@ -218,6 +223,10 @@ function cloneArray(arr, options) {
218
223
  ret = new Array(len);
219
224
  }
220
225
 
226
+ if (seen) {
227
+ seen.set(arr, ret);
228
+ }
229
+
221
230
  arr = isMongooseArray(arr) ? arr.__array : arr;
222
231
  if (ret.isMongooseDocumentArray) {
223
232
  // Create new options object to avoid mutating the shared options.
package/lib/model.js CHANGED
@@ -3951,6 +3951,18 @@ Model.castObject = function castObject(obj, options) {
3951
3951
  }
3952
3952
 
3953
3953
  if (error != null) {
3954
+ // `{MODEL}` is replaced for query casting and document validation, so do it
3955
+ // here too. Only the top-level call knows the model: the recursive calls for
3956
+ // subdocuments are invoked on the subdocument constructor, which has no
3957
+ // `modelName`, so this runs once over every collected error. (gh-8300)
3958
+ if (this.modelName != null) {
3959
+ for (const key of Object.keys(error.errors)) {
3960
+ const err = error.errors[key];
3961
+ if (typeof err.setModel === 'function') {
3962
+ err.setModel(this);
3963
+ }
3964
+ }
3965
+ }
3954
3966
  throw error;
3955
3967
  }
3956
3968
 
package/lib/schema/map.js CHANGED
@@ -30,20 +30,6 @@ class SchemaMap extends SchemaType {
30
30
  this._createNestedSchemaType(parentSchema, key, options, schemaOptions);
31
31
  }
32
32
 
33
- /**
34
- * Sets a default option for all Map instances.
35
- *
36
- * @param {string} option The option you'd like to set the value for
37
- * @param {any} value value for option
38
- * @return {undefined}
39
- * @function set
40
- * @api public
41
- */
42
-
43
- set(option, value) {
44
- return SchemaType.set(option, value);
45
- }
46
-
47
33
  /**
48
34
  * Casts to Map
49
35
  *
@@ -143,6 +129,19 @@ class SchemaMap extends SchemaType {
143
129
  }
144
130
  }
145
131
 
132
+ /**
133
+ * Sets a default option for all Map instances.
134
+ *
135
+ * @param {string} option The option you'd like to set the value for
136
+ * @param {any} value value for option
137
+ * @return {undefined}
138
+ * @function set
139
+ * @static
140
+ * @api public
141
+ */
142
+
143
+ SchemaMap.set = SchemaType.set;
144
+
146
145
  /**
147
146
  * This schema type's name, to defend against minifiers that mangle
148
147
  * function names.
package/lib/schema.js CHANGED
@@ -595,12 +595,6 @@ Schema.prototype.omit = function(paths, options) {
595
595
 
596
596
  newSchema.remove(paths);
597
597
 
598
- for (const nested in newSchema.singleNestedPaths) {
599
- if (paths.includes(nested)) {
600
- delete newSchema.singleNestedPaths[nested];
601
- }
602
- }
603
-
604
598
  return newSchema;
605
599
  };
606
600
 
@@ -2831,6 +2825,7 @@ Schema.prototype.remove = function(path) {
2831
2825
  this.mapPaths = this.mapPaths.filter(
2832
2826
  schemaType => !schemaType.path.startsWith(name + '.')
2833
2827
  );
2828
+ _deleteSubpaths(this, name);
2834
2829
 
2835
2830
  delete this.nested[name];
2836
2831
  _deletePath(this, name);
@@ -2849,6 +2844,11 @@ Schema.prototype.remove = function(path) {
2849
2844
  this.mapPaths = this.mapPaths.filter(
2850
2845
  schemaType => !schemaType.path.startsWith(name + '.')
2851
2846
  );
2847
+ // A document array registers its element paths under `subpaths` and a
2848
+ // single nested subdocument registers its paths under `singleNestedPaths`.
2849
+ // Left behind, they keep answering `path()` and `pathType()`, and queries
2850
+ // on the removed path keep being cast.
2851
+ _deleteSubpaths(this, name);
2852
2852
  _deletePath(this, name);
2853
2853
 
2854
2854
  this._removeEncryptedField(name);
@@ -2861,6 +2861,20 @@ Schema.prototype.remove = function(path) {
2861
2861
  * ignore
2862
2862
  */
2863
2863
 
2864
+ function _deleteSubpaths(schema, name) {
2865
+ const prefix = name + '.';
2866
+ for (const subpath of Object.keys(schema.subpaths)) {
2867
+ if (subpath === name || subpath.startsWith(prefix)) {
2868
+ delete schema.subpaths[subpath];
2869
+ }
2870
+ }
2871
+ for (const subpath of Object.keys(schema.singleNestedPaths)) {
2872
+ if (subpath === name || subpath.startsWith(prefix)) {
2873
+ delete schema.singleNestedPaths[subpath];
2874
+ }
2875
+ }
2876
+ }
2877
+
2864
2878
  function _deletePath(schema, name) {
2865
2879
  const pieces = name.split('.');
2866
2880
  const last = pieces.pop();
@@ -211,6 +211,26 @@ const methods = {
211
211
  return this.constructor.prototype.toObject.apply(this, arguments);
212
212
  },
213
213
 
214
+ /**
215
+ * Wraps [`MongooseArray#addToSet`](https://mongoosejs.com/docs/api/array.html#MongooseArray.prototype.addToSet())
216
+ * with proper change tracking.
217
+ *
218
+ * @param {...object} [args]
219
+ * @api public
220
+ * @method addToSet
221
+ * @memberOf MongooseDocumentArray
222
+ */
223
+
224
+ addToSet() {
225
+ // Arguments are cast before duplicates are skipped, so any value added
226
+ // after a skipped duplicate is cast with an index that is too high.
227
+ const ret = ArrayMethods.addToSet.apply(this, arguments);
228
+
229
+ _updateSubdocIndexes(this);
230
+
231
+ return ret;
232
+ },
233
+
214
234
  /**
215
235
  * Wraps [`Array#push`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) with proper change tracking.
216
236
  *
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "9.10.0",
4
+ "version": "9.10.2",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -125,7 +125,7 @@ declare module 'mongoose' {
125
125
  * Binds this aggregate to a model.
126
126
  * @param model the model to which the aggregate is to be bound
127
127
  */
128
- model(model: Model<any>): this;
128
+ model(model: Model<any, any, any, any>): this;
129
129
 
130
130
  /**
131
131
  * Returns the current model bound to this aggregate object
@@ -252,7 +252,7 @@ declare module 'mongoose' {
252
252
 
253
253
  /** Populates document references. */
254
254
  populate<Paths = {}>(path: string | PopulateOptions | (string | PopulateOptions)[]): Promise<PopulateDocumentResult<this, Paths, PopulatedPathsDocumentType<DocType, Paths>, DocType>>;
255
- populate<Paths = {}>(path: string, select?: string | AnyObject, model?: Model<any>, match?: AnyObject, options?: PopulateOptions): Promise<PopulateDocumentResult<this, Paths, PopulatedPathsDocumentType<DocType, Paths>, DocType>>;
255
+ populate<Paths = {}>(path: string, select?: string | AnyObject, model?: Model<any, any, any, any>, match?: AnyObject, options?: PopulateOptions): Promise<PopulateDocumentResult<this, Paths, PopulatedPathsDocumentType<DocType, Paths>, DocType>>;
256
256
 
257
257
  /** Gets _id(s) used during population of the given `path`. If the path was not populated, returns `undefined`. */
258
258
  populated(path: string): any;
@@ -60,7 +60,7 @@ declare module 'mongoose' {
60
60
  /** query conditions to match */
61
61
  match?: any;
62
62
  /** optional model to use for population */
63
- model?: string | Model<any>;
63
+ model?: string | Model<any, any, any, any>;
64
64
  /** by default, Mongoose removes null and undefined values from populated arrays. Use this option to make `populate()` retain `null` and `undefined` array entries. */
65
65
  retainNullValues?: boolean;
66
66
  /** if true, Mongoose will call any getters defined on the `localField`. By default, Mongoose gets the raw value of `localField`. */
@@ -120,7 +120,7 @@ declare module 'mongoose' {
120
120
  /**
121
121
  * The model that `populate()` should use if populating this path.
122
122
  */
123
- ref?: string | Model<any> | ((this: any, doc: any) => string | Model<any>);
123
+ ref?: string | Model<any, any, any, any> | ((this: any, doc: any) => string | Model<any, any, any, any>);
124
124
 
125
125
  /**
126
126
  * The path in the document that `populate()` should use to find the model
@@ -354,7 +354,7 @@ declare module 'mongoose' {
354
354
  * Set the model that this path refers to. This is the option that [populate](https://mongoosejs.com/docs/populate.html)
355
355
  * looks at to determine the foreign collection it should query.
356
356
  */
357
- ref(ref: string | boolean | Model<any>): this;
357
+ ref(ref: string | boolean | Model<any, any, any, any>): this;
358
358
 
359
359
  /**
360
360
  * Adds a required validator to this SchemaType. The validator gets added