mongoose 9.3.0 → 9.3.1

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 CHANGED
@@ -170,7 +170,7 @@ Aggregate.prototype.append = function() {
170
170
  : [...arguments];
171
171
 
172
172
  if (!args.every(isOperator)) {
173
- throw new Error('Arguments must be aggregate pipeline operators');
173
+ throw new MongooseError('Arguments must be aggregate pipeline operators');
174
174
  }
175
175
 
176
176
  this._pipeline = this._pipeline.concat(args);
@@ -203,7 +203,7 @@ Aggregate.prototype.append = function() {
203
203
  */
204
204
  Aggregate.prototype.addFields = function(arg) {
205
205
  if (typeof arg !== 'object' || arg === null || Array.isArray(arg)) {
206
- throw new Error('Invalid addFields() argument. Must be an object');
206
+ throw new MongooseError('Invalid addFields() argument. Must be an object');
207
207
  }
208
208
  return this.append({ $addFields: Object.assign({}, arg) });
209
209
  };
@@ -259,7 +259,7 @@ Aggregate.prototype.project = function(arg) {
259
259
  fields[field] = include;
260
260
  });
261
261
  } else {
262
- throw new Error('Invalid project() argument. Must be string or object');
262
+ throw new MongooseError('Invalid project() argument. Must be string or object');
263
263
  }
264
264
 
265
265
  return this.append({ $project: fields });
@@ -462,7 +462,7 @@ Aggregate.prototype.unwind = function() {
462
462
  $unwind: (arg[0] === '$') ? arg : '$' + arg
463
463
  });
464
464
  } else {
465
- throw new Error('Invalid arg "' + arg + '" to unwind(), ' +
465
+ throw new MongooseError('Invalid arg "' + arg + '" to unwind(), ' +
466
466
  'must be string or object');
467
467
  }
468
468
  }
@@ -761,7 +761,7 @@ Aggregate.prototype.redact = function(expression, thenExpr, elseExpr) {
761
761
  if (arguments.length === 3) {
762
762
  if ((typeof thenExpr === 'string' && !validRedactStringValues.has(thenExpr)) ||
763
763
  (typeof elseExpr === 'string' && !validRedactStringValues.has(elseExpr))) {
764
- throw new Error('If thenExpr or elseExpr is string, it must be either $$DESCEND, $$PRUNE or $$KEEP');
764
+ throw new MongooseError('If thenExpr or elseExpr is string, it must be either $$DESCEND, $$PRUNE or $$KEEP');
765
765
  }
766
766
 
767
767
  expression = {
@@ -796,7 +796,7 @@ Aggregate.prototype.explain = async function explain(verbosity) {
796
796
  const model = this._model;
797
797
 
798
798
  if (!this._pipeline.length) {
799
- throw new Error('Aggregate has empty pipeline');
799
+ throw new MongooseError('Aggregate has empty pipeline');
800
800
  }
801
801
 
802
802
  prepareDiscriminatorPipeline(this._pipeline, this._model.schema);
@@ -1058,7 +1058,7 @@ Aggregate.prototype.pipelineForUnionWith = function pipelineForUnionWith() {
1058
1058
 
1059
1059
  Aggregate.prototype.exec = async function exec() {
1060
1060
  if (!this._model && !this._connection) {
1061
- throw new Error('Aggregate not bound to any Model');
1061
+ throw new MongooseError('Aggregate not bound to any Model');
1062
1062
  }
1063
1063
  if (typeof arguments[0] === 'function') {
1064
1064
  throw new MongooseError('Aggregate.prototype.exec() no longer accepts a callback');
@@ -132,7 +132,7 @@ QueryCursor.prototype._read = function() {
132
132
  }
133
133
  if (!doc) {
134
134
  this.push(null);
135
- this.cursor.close(function(error) {
135
+ this.cursor.close((error) => {
136
136
  if (error) {
137
137
  return this.emit('error', error);
138
138
  }
@@ -1,8 +1,13 @@
1
1
  'use strict';
2
2
 
3
3
  /**
4
- * Convert a string or array into a projection object, retaining all
5
- * `-` and `+` paths.
4
+ * Convert a string or array into a projection object. Treats `-foo` as
5
+ * equivalent to `foo: 0` depending on `retainMinusPaths`. If `retainMinusPaths`
6
+ * is true, then `-foo` will be included in the projection as `'-foo': 0`.
7
+ *
8
+ * @param {object|string|string[]} v
9
+ * @param {boolean} [retainMinusPaths]
10
+ * @return {object}
6
11
  */
7
12
 
8
13
  module.exports = function parseProjection(v, retainMinusPaths) {
@@ -22,9 +27,9 @@ module.exports = function parseProjection(v, retainMinusPaths) {
22
27
  if (!field) {
23
28
  continue;
24
29
  }
25
- const include = '-' == field[0] ? 0 : 1;
30
+ const include = field.charAt(0) === '-' ? 0 : 1;
26
31
  if (!retainMinusPaths && include === 0) {
27
- field = field.substring(1);
32
+ field = field.slice(1);
28
33
  }
29
34
  ret[field] = include;
30
35
  }
package/lib/model.js CHANGED
@@ -61,6 +61,7 @@ const decorateDiscriminatorIndexOptions = require('./helpers/indexes/decorateDis
61
61
  const isPathSelectedInclusive = require('./helpers/projection/isPathSelectedInclusive');
62
62
  const leanPopulateMap = require('./helpers/populate/leanPopulateMap');
63
63
  const parallelLimit = require('./helpers/parallelLimit');
64
+ const parseProjection = require('./helpers/projection/parseProjection');
64
65
  const prepareDiscriminatorPipeline = require('./helpers/aggregate/prepareDiscriminatorPipeline');
65
66
  const pushNestedArrayPaths = require('./helpers/model/pushNestedArrayPaths');
66
67
  const removeDeselectedForeignField = require('./helpers/populate/removeDeselectedForeignField');
@@ -189,7 +190,7 @@ Model.prototype.db;
189
190
 
190
191
  Model.useConnection = function useConnection(connection) {
191
192
  if (!connection) {
192
- throw new Error('Please provide a connection.');
193
+ throw new MongooseError('Please provide a connection.');
193
194
  }
194
195
  if (this.db) {
195
196
  delete this.db.models[this.modelName];
@@ -824,7 +825,7 @@ Model.prototype.deleteOne = function deleteOne(options) {
824
825
  // `self` is passed to pre hooks as argument for backwards compatibility, but that
825
826
  // isn't the actual arguments passed to the wrapped function.
826
827
  if (res[0] !== self || res[1] !== options) {
827
- throw new Error('Document deleteOne pre hooks cannot overwrite arguments');
828
+ throw new MongooseError('Document deleteOne pre hooks cannot overwrite arguments');
828
829
  }
829
830
  query.deleteOne(where, options);
830
831
  // Apply custom where conditions _after_ document deleteOne middleware for
@@ -3458,7 +3459,7 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
3458
3459
  sort((v1, v2) => v1.index - v2.index).
3459
3460
  map(v => v.error);
3460
3461
 
3461
- const validOps = validOpIndexes.sort().map(index => ops[index]);
3462
+ const validOps = validOpIndexes.sort((a, b) => a - b).map(index => ops[index]);
3462
3463
 
3463
3464
  if (validOps.length === 0) {
3464
3465
  if (options.throwOnValidationError && validationErrors.length) {
@@ -3609,7 +3610,7 @@ async function buildPreSavePromise(document, options) {
3609
3610
  const preFilter = buildMiddlewareFilter(options, 'pre');
3610
3611
  const [newOptions] = await document.schema.s.hooks.execPre('save', document, [options], { filter: preFilter });
3611
3612
  if (newOptions !== options) {
3612
- throw new Error('Cannot overwrite options in pre("save") hook on bulkSave()');
3613
+ throw new MongooseError('Cannot overwrite options in pre("save") hook on bulkSave()');
3613
3614
  }
3614
3615
  }
3615
3616
 
@@ -3849,7 +3850,7 @@ Model.castObject = function castObject(obj, options) {
3849
3850
 
3850
3851
  Model.buildBulkWriteOperations = function buildBulkWriteOperations(documents, options) {
3851
3852
  if (!Array.isArray(documents)) {
3852
- throw new Error(`bulkSave expects an array of documents to be passed, received \`${documents}\` instead`);
3853
+ throw new MongooseError(`bulkSave expects an array of documents to be passed, received \`${documents}\` instead`);
3853
3854
  }
3854
3855
 
3855
3856
  setDefaultOptions();
@@ -3857,7 +3858,7 @@ Model.buildBulkWriteOperations = function buildBulkWriteOperations(documents, op
3857
3858
  const writeOperations = documents.map((document, i) => {
3858
3859
  if (!options.skipValidation) {
3859
3860
  if (!(document instanceof Document)) {
3860
- throw new Error(`documents.${i} was not a mongoose document, documents must be an array of mongoose documents (instanceof mongoose.Document).`);
3861
+ throw new MongooseError(`documents.${i} was not a mongoose document, documents must be an array of mongoose documents (instanceof mongoose.Document).`);
3861
3862
  }
3862
3863
  if (options.validateBeforeSave == null || options.validateBeforeSave) {
3863
3864
  const err = document.validateSync();
@@ -3935,7 +3936,7 @@ Model.buildBulkWriteOperations = function buildBulkWriteOperations(documents, op
3935
3936
  * @api public
3936
3937
  */
3937
3938
 
3938
- Model.hydrate = function(obj, projection, options) {
3939
+ Model.hydrate = function hydrate(obj, projection, options) {
3939
3940
  _checkContext(this, 'hydrate');
3940
3941
 
3941
3942
  if (options?.virtuals && options?.hydratedPopulatedDocs === false) {
@@ -3946,6 +3947,7 @@ Model.hydrate = function(obj, projection, options) {
3946
3947
  if (obj?.$__ != null) {
3947
3948
  obj = obj.toObject(internalToObjectOptions);
3948
3949
  }
3950
+ projection = parseProjection(projection);
3949
3951
  obj = applyProjection(obj, projection);
3950
3952
  }
3951
3953
  const document = require('./queryHelpers').createModel(this, obj, projection, projection, options);
@@ -4947,7 +4949,7 @@ Model.compile = function compile(name, schema, collectionName, connection, base)
4947
4949
  Model.clientEncryption = function clientEncryption() {
4948
4950
  const ClientEncryption = this.base.driver.get().ClientEncryption;
4949
4951
  if (!ClientEncryption) {
4950
- throw new Error('The mongodb driver must be used to obtain a ClientEncryption object.');
4952
+ throw new MongooseError('The mongodb driver must be used to obtain a ClientEncryption object.');
4951
4953
  }
4952
4954
 
4953
4955
  const client = this.collection?.conn?.client;
package/lib/schema.js CHANGED
@@ -205,7 +205,7 @@ function aliasFields(schema, paths) {
205
205
  if (Array.isArray(alias)) {
206
206
  for (const a of alias) {
207
207
  if (typeof a !== 'string') {
208
- throw new Error('Invalid value for alias option on ' + prop + ', got ' + a);
208
+ throw new MongooseError('Invalid value for alias option on ' + prop + ', got ' + a);
209
209
  }
210
210
 
211
211
  schema.aliases[a] = prop;
@@ -231,7 +231,7 @@ function aliasFields(schema, paths) {
231
231
  }
232
232
 
233
233
  if (typeof alias !== 'string') {
234
- throw new Error('Invalid value for alias option on ' + prop + ', got ' + alias);
234
+ throw new MongooseError('Invalid value for alias option on ' + prop + ', got ' + alias);
235
235
  }
236
236
 
237
237
  schema.aliases[alias] = prop;
@@ -750,7 +750,7 @@ Schema.prototype.encryptionType = function encryptionType(encryptionType) {
750
750
  return this.options.encryptionType;
751
751
  }
752
752
  if (!(typeof encryptionType === 'string' || encryptionType === null)) {
753
- throw new Error('invalid `encryptionType`: ${encryptionType}');
753
+ throw new MongooseError('invalid `encryptionType`: ${encryptionType}');
754
754
  }
755
755
  this.options.encryptionType = encryptionType;
756
756
  };
@@ -909,7 +909,7 @@ Schema.prototype.add = function add(obj, prefix) {
909
909
  if (val.instanceOfSchema && val.encryptionType() != null) {
910
910
  // schema.add({ field: <instance of encrypted schema> })
911
911
  if (this.encryptionType() != val.encryptionType()) {
912
- throw new Error('encryptionType of a nested schema must match the encryption type of the parent schema.');
912
+ throw new MongooseError('encryptionType of a nested schema must match the encryption type of the parent schema.');
913
913
  }
914
914
 
915
915
  for (const [encryptedField, encryptedFieldConfig] of Object.entries(val.encryptedFields)) {
@@ -921,7 +921,7 @@ Schema.prototype.add = function add(obj, prefix) {
921
921
  const { encrypt } = val;
922
922
 
923
923
  if (this.encryptionType() == null) {
924
- throw new Error('encryptionType must be provided');
924
+ throw new MongooseError('encryptionType must be provided');
925
925
  }
926
926
 
927
927
  this._addEncryptedField(fullPath, encrypt);
@@ -948,7 +948,7 @@ Schema.prototype.add = function add(obj, prefix) {
948
948
  Schema.prototype._addEncryptedField = function _addEncryptedField(path, fieldConfig) {
949
949
  const type = this.path(path).autoEncryptionType();
950
950
  if (type == null) {
951
- throw new Error(`Invalid BSON type for FLE field: '${path}'`);
951
+ throw new MongooseError(`Invalid BSON type for FLE field: '${path}'`);
952
952
  }
953
953
 
954
954
  this.encryptedFields[path] = clone(fieldConfig);
@@ -1113,11 +1113,11 @@ Schema.prototype.alias = function alias(path, alias) {
1113
1113
 
1114
1114
  Schema.prototype.removeIndex = function removeIndex(index) {
1115
1115
  if (arguments.length > 1) {
1116
- throw new Error('removeIndex() takes only 1 argument');
1116
+ throw new MongooseError('removeIndex() takes only 1 argument');
1117
1117
  }
1118
1118
 
1119
1119
  if (typeof index !== 'object' && typeof index !== 'string') {
1120
- throw new Error('removeIndex() may only take either an object or a string as an argument');
1120
+ throw new MongooseError('removeIndex() may only take either an object or a string as an argument');
1121
1121
  }
1122
1122
 
1123
1123
  if (typeof index === 'object') {
@@ -1318,7 +1318,7 @@ Schema.prototype.path = function(path, obj) {
1318
1318
 
1319
1319
  for (const sub of subpaths) {
1320
1320
  if (utils.specialProperties.has(sub)) {
1321
- throw new Error('Cannot set special property `' + sub + '` on a schema');
1321
+ throw new MongooseError('Cannot set special property `' + sub + '` on a schema');
1322
1322
  }
1323
1323
  fullPath = fullPath += (fullPath.length > 0 ? '.' : '') + sub;
1324
1324
  if (!branch[sub]) {
@@ -1331,7 +1331,7 @@ Schema.prototype.path = function(path, obj) {
1331
1331
  + fullPath
1332
1332
  + '` already set to type ' + branch[sub].name
1333
1333
  + '.';
1334
- throw new Error(msg);
1334
+ throw new MongooseError(msg);
1335
1335
  }
1336
1336
  branch = branch[sub];
1337
1337
  }
@@ -2205,7 +2205,7 @@ Schema.prototype.post = function(name) {
2205
2205
 
2206
2206
  Schema.prototype.plugin = function(fn, opts) {
2207
2207
  if (typeof fn !== 'function') {
2208
- throw new Error('First param to `schema.plugin()` must be a function, ' +
2208
+ throw new MongooseError('First param to `schema.plugin()` must be a function, ' +
2209
2209
  'got "' + (typeof fn) + '"');
2210
2210
  }
2211
2211
 
@@ -2480,7 +2480,7 @@ Object.defineProperty(Schema, 'indexTypes', {
2480
2480
  return indexTypes;
2481
2481
  },
2482
2482
  set: function() {
2483
- throw new Error('Cannot overwrite Schema.indexTypes');
2483
+ throw new MongooseError('Cannot overwrite Schema.indexTypes');
2484
2484
  }
2485
2485
  });
2486
2486
 
@@ -2542,11 +2542,11 @@ Schema.prototype.virtual = function(name, options) {
2542
2542
 
2543
2543
  if (utils.hasUserDefinedProperty(options, ['ref', 'refPath'])) {
2544
2544
  if (options.localField == null) {
2545
- throw new Error('Reference virtuals require `localField` option');
2545
+ throw new MongooseError('Reference virtuals require `localField` option');
2546
2546
  }
2547
2547
 
2548
2548
  if (options.foreignField == null) {
2549
- throw new Error('Reference virtuals require `foreignField` option');
2549
+ throw new MongooseError('Reference virtuals require `foreignField` option');
2550
2550
  }
2551
2551
 
2552
2552
  const virtual = this.virtual(name);
@@ -2642,7 +2642,7 @@ Schema.prototype.virtual = function(name, options) {
2642
2642
  const parts = name.split('.');
2643
2643
 
2644
2644
  if (this.pathType(name) === 'real') {
2645
- throw new Error('Virtual path "' + name + '"' +
2645
+ throw new MongooseError('Virtual path "' + name + '"' +
2646
2646
  ' conflicts with a real path in the schema');
2647
2647
  }
2648
2648
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "9.3.0",
4
+ "version": "9.3.1",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
package/types/index.d.ts CHANGED
@@ -379,7 +379,12 @@ declare module 'mongoose' {
379
379
  >,
380
380
  TMethods = TSchemaOptions extends { methods: infer M } ? { [K in keyof M]: OmitThisParameter<M[K]> } : {},
381
381
  TStatics = TSchemaOptions extends { statics: infer S } ? { [K in keyof S]: OmitThisParameter<S[K]> } : {}
382
- >(def: TSchemaDefinition, options: TSchemaOptions): Schema<
382
+ >(def: TSchemaDefinition, options: TSchemaOptions & {
383
+ statics?: SchemaOptionsStaticsPropertyType<
384
+ TStatics,
385
+ Model<RawDocType>
386
+ >
387
+ }): Schema<
383
388
  RawDocType,
384
389
  Model<RawDocType, any, any, any>,
385
390
  TMethods,
@@ -497,6 +502,7 @@ declare module 'mongoose' {
497
502
 
498
503
  /** Registers a plugin for this schema. */
499
504
  plugin<PFunc extends PluginFunction<DocType, TModelType, any, any, any, any>, POptions extends Parameters<PFunc>[1] = Parameters<PFunc>[1]>(fn: PFunc, opts?: POptions): this;
505
+ plugin<PFunc extends PluginFunction<DocType, Model<DocType, any, any, any, any, any>, any, any, any, any>, POptions extends Parameters<PFunc>[1] = Parameters<PFunc>[1]>(fn: PFunc, opts?: POptions): this;
500
506
 
501
507
  /** Defines a post hook for the model. */
502
508
 
@@ -7,6 +7,13 @@ declare module 'mongoose' {
7
7
  currentTime?: () => (NativeDate | number);
8
8
  }
9
9
 
10
+ type SchemaOptionsStaticsPropertyType<TStaticMethods, TModelType> = IfEquals<
11
+ TStaticMethods,
12
+ {},
13
+ Record<string, (...args: any[]) => unknown> & ThisType<TModelType>,
14
+ { [K in keyof TStaticMethods]: OmitThisParameter<TStaticMethods[K]> } & ThisType<TModelType>
15
+ >;
16
+
10
17
  type TypeKeyBaseType = string;
11
18
 
12
19
  type DefaultTypeKey = 'type';
@@ -222,12 +229,7 @@ declare module 'mongoose' {
222
229
  /**
223
230
  * Model Statics methods.
224
231
  */
225
- statics?: IfEquals<
226
- TStaticMethods,
227
- {},
228
- { [name: string]: (this: TModelType, ...args: any[]) => unknown },
229
- AddThisParameter<TStaticMethods, TModelType>
230
- >
232
+ statics?: SchemaOptionsStaticsPropertyType<TStaticMethods, TModelType>
231
233
 
232
234
  /**
233
235
  * Document instance methods.