mongoose 8.17.2 → 8.18.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.
@@ -43,5 +43,5 @@ msg.Date.max = 'Path `{PATH}` ({VALUE}) is after maximum allowed value ({MAX}).'
43
43
  msg.String = {};
44
44
  msg.String.enum = '`{VALUE}` is not a valid enum value for path `{PATH}`.';
45
45
  msg.String.match = 'Path `{PATH}` is invalid ({VALUE}).';
46
- msg.String.minlength = 'Path `{PATH}` (`{VALUE}`) is shorter than the minimum allowed length ({MINLENGTH}).';
47
- msg.String.maxlength = 'Path `{PATH}` (`{VALUE}`) is longer than the maximum allowed length ({MAXLENGTH}).';
46
+ msg.String.minlength = 'Path `{PATH}` (`{VALUE}`, length {LENGTH}) is shorter than the minimum allowed length ({MINLENGTH}).';
47
+ msg.String.maxlength = 'Path `{PATH}` (`{VALUE}`, length {LENGTH}) is longer than the maximum allowed length ({MAXLENGTH}).';
@@ -0,0 +1,32 @@
1
+ 'use strict';
2
+
3
+ const SchemaTypeOptions = require('./schemaTypeOptions');
4
+
5
+ /**
6
+ * The options defined on a Union schematype.
7
+ *
8
+ * @api public
9
+ * @inherits SchemaTypeOptions
10
+ * @constructor SchemaUnionOptions
11
+ */
12
+
13
+ class SchemaUnionOptions extends SchemaTypeOptions {}
14
+
15
+ const opts = require('./propertyOptions');
16
+
17
+ /**
18
+ * If set, specifies the types that this union can take. Mongoose will cast
19
+ * the value to one of the given types.
20
+ *
21
+ * If not set, Mongoose will not cast the value to any specific type.
22
+ *
23
+ * @api public
24
+ * @property of
25
+ * @memberOf SchemaUnionOptions
26
+ * @type {Function|Function[]|string|string[]}
27
+ * @instance
28
+ */
29
+
30
+ Object.defineProperty(SchemaUnionOptions.prototype, 'of', opts);
31
+
32
+ module.exports = SchemaUnionOptions;
@@ -12,6 +12,8 @@ exports.Buffer = require('./buffer');
12
12
  exports.Date = require('./date');
13
13
  exports.Decimal128 = exports.Decimal = require('./decimal128');
14
14
  exports.DocumentArray = require('./documentArray');
15
+ exports.Double = require('./double');
16
+ exports.Int32 = require('./int32');
15
17
  exports.Map = require('./map');
16
18
  exports.Mixed = require('./mixed');
17
19
  exports.Number = require('./number');
@@ -19,8 +21,7 @@ exports.ObjectId = require('./objectId');
19
21
  exports.String = require('./string');
20
22
  exports.Subdocument = require('./subdocument');
21
23
  exports.UUID = require('./uuid');
22
- exports.Double = require('./double');
23
- exports.Int32 = require('./int32');
24
+ exports.Union = require('./union');
24
25
 
25
26
  // alias
26
27
 
@@ -0,0 +1,105 @@
1
+ 'use strict';
2
+
3
+ /*!
4
+ * ignore
5
+ */
6
+
7
+ const SchemaUnionOptions = require('../options/schemaUnionOptions');
8
+ const SchemaType = require('../schemaType');
9
+
10
+ const firstValueSymbol = Symbol('firstValue');
11
+
12
+ /*!
13
+ * ignore
14
+ */
15
+
16
+ class Union extends SchemaType {
17
+ constructor(key, options, schemaOptions = {}) {
18
+ super(key, options, 'Union');
19
+ if (!options || !Array.isArray(options.of) || options.of.length === 0) {
20
+ throw new Error('Union schema type requires an array of types');
21
+ }
22
+ this.schemaTypes = options.of.map(obj => options.parentSchema.interpretAsType(key, obj, schemaOptions));
23
+ }
24
+
25
+ cast(val, doc, init, prev, options) {
26
+ let firstValue = firstValueSymbol;
27
+ let lastError;
28
+ // Loop through each schema type in the union. If one of the schematypes returns a value that is `=== val`, then
29
+ // use `val`. Otherwise, if one of the schematypes casted successfully, use the first successfully casted value.
30
+ // Finally, if none of the schematypes casted successfully, throw the error from the last schema type in the union.
31
+ // The `=== val` check is a workaround to ensure that the original value is returned if it matches one of the schema types,
32
+ // avoiding cases like where numbers are casted to strings or dates even if the schema type is a number.
33
+ for (let i = 0; i < this.schemaTypes.length; ++i) {
34
+ try {
35
+ const casted = this.schemaTypes[i].cast(val, doc, init, prev, options);
36
+ if (casted === val) {
37
+ return casted;
38
+ }
39
+ if (firstValue === firstValueSymbol) {
40
+ firstValue = casted;
41
+ }
42
+ } catch (error) {
43
+ lastError = error;
44
+ }
45
+ }
46
+ if (firstValue !== firstValueSymbol) {
47
+ return firstValue;
48
+ }
49
+ throw lastError;
50
+ }
51
+
52
+ // Setters also need to be aware of casting - we need to apply the setters of the entry in the union we choose.
53
+ applySetters(val, doc, init, prev, options) {
54
+ let firstValue = firstValueSymbol;
55
+ let lastError;
56
+ // Loop through each schema type in the union. If one of the schematypes returns a value that is `=== val`, then
57
+ // use `val`. Otherwise, if one of the schematypes casted successfully, use the first successfully casted value.
58
+ // Finally, if none of the schematypes casted successfully, throw the error from the last schema type in the union.
59
+ // The `=== val` check is a workaround to ensure that the original value is returned if it matches one of the schema types,
60
+ // avoiding cases like where numbers are casted to strings or dates even if the schema type is a number.
61
+ for (let i = 0; i < this.schemaTypes.length; ++i) {
62
+ try {
63
+ let castedVal = this.schemaTypes[i]._applySetters(val, doc, init, prev, options);
64
+ if (castedVal == null) {
65
+ castedVal = this.schemaTypes[i]._castNullish(castedVal);
66
+ } else {
67
+ castedVal = this.schemaTypes[i].cast(castedVal, doc, init, prev, options);
68
+ }
69
+ if (castedVal === val) {
70
+ return castedVal;
71
+ }
72
+ if (firstValue === firstValueSymbol) {
73
+ firstValue = castedVal;
74
+ }
75
+ } catch (error) {
76
+ lastError = error;
77
+ }
78
+ }
79
+ if (firstValue !== firstValueSymbol) {
80
+ return firstValue;
81
+ }
82
+ throw lastError;
83
+ }
84
+
85
+ clone() {
86
+ const schematype = super.clone();
87
+
88
+ schematype.schemaTypes = this.schemaTypes.map(schemaType => schemaType.clone());
89
+ return schematype;
90
+ }
91
+ }
92
+
93
+ /**
94
+ * This schema type's name, to defend against minifiers that mangle
95
+ * function names.
96
+ *
97
+ * @api public
98
+ */
99
+ Union.schemaName = 'Union';
100
+
101
+ Union.defaultOptions = {};
102
+
103
+ Union.prototype.OptionsConstructor = SchemaUnionOptions;
104
+
105
+ module.exports = Union;
package/lib/schema.js CHANGED
@@ -1525,7 +1525,7 @@ Object.defineProperty(Schema.prototype, 'base', {
1525
1525
  *
1526
1526
  * @param {String} path
1527
1527
  * @param {Object} obj constructor
1528
- * @param {Object} options
1528
+ * @param {Object} options schema options
1529
1529
  * @api private
1530
1530
  */
1531
1531
 
@@ -1539,7 +1539,6 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
1539
1539
  return clone;
1540
1540
  }
1541
1541
 
1542
-
1543
1542
  // If this schema has an associated Mongoose object, use the Mongoose object's
1544
1543
  // copy of SchemaTypes re: gh-7158 gh-6933
1545
1544
  const MongooseTypes = this.base != null ? this.base.Schema.Types : Schema.Types;
@@ -1740,7 +1739,10 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
1740
1739
  'https://bit.ly/mongoose-schematypes for a list of valid schema types.');
1741
1740
  }
1742
1741
 
1743
- const schemaType = new MongooseTypes[name](path, obj);
1742
+ if (name === 'Union') {
1743
+ obj.parentSchema = this;
1744
+ }
1745
+ const schemaType = new MongooseTypes[name](path, obj, options);
1744
1746
 
1745
1747
  if (schemaType.$isSchemaMap) {
1746
1748
  createMapNestedSchemaType(this, schemaType, path, obj, options);
package/lib/schemaType.js CHANGED
@@ -1349,6 +1349,12 @@ SchemaType.prototype.doValidate = function(value, fn, scope, options) {
1349
1349
  validatorProperties.path = options && options.path ? options.path : path;
1350
1350
  validatorProperties.fullPath = this.$fullPath;
1351
1351
  validatorProperties.value = value;
1352
+ if (typeof value === 'string') {
1353
+ validatorProperties.length = value.length;
1354
+ if (validatorProperties.value.length > 30) {
1355
+ validatorProperties.value = validatorProperties.value.slice(0, 30) + '...';
1356
+ }
1357
+ }
1352
1358
 
1353
1359
  if (validator instanceof RegExp) {
1354
1360
  validate(validator.test(value), validatorProperties, scope);
@@ -1470,6 +1476,12 @@ SchemaType.prototype.doValidateSync = function(value, scope, options) {
1470
1476
  validatorProperties.path = options && options.path ? options.path : path;
1471
1477
  validatorProperties.fullPath = this.$fullPath;
1472
1478
  validatorProperties.value = value;
1479
+ if (typeof value === 'string') {
1480
+ validatorProperties.length = value.length;
1481
+ if (validatorProperties.value.length > 30) {
1482
+ validatorProperties.value = validatorProperties.value.slice(0, 30) + '...';
1483
+ }
1484
+ }
1473
1485
  let ok = false;
1474
1486
 
1475
1487
  // Skip any explicit async validators. Validators that return a promise
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "8.17.2",
4
+ "version": "8.18.0",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -1,46 +1,49 @@
1
1
  declare module 'mongoose' {
2
2
  import mongodb = require('mongodb');
3
3
 
4
- /*
5
- * section collection.js
6
- */
7
- interface CollectionBase<T extends mongodb.Document> extends mongodb.Collection<T> {
8
- /*
9
- * Abstract methods. Some of these are already defined on the
10
- * mongodb.Collection interface so they've been commented out.
4
+ export class BaseCollection<T extends mongodb.Document> extends mongodb.Collection<T> {
5
+ /**
6
+ * Collection constructor
7
+ * @param name name of the collection
8
+ * @param conn A MongooseConnection instance
9
+ * @param opts optional collection options
11
10
  */
11
+ constructor(name: string, conn: Connection, opts?: any);
12
+
13
+ /*
14
+ * Abstract methods. Some of these are already defined on the
15
+ * mongodb.Collection interface so they've been commented out.
16
+ */
12
17
  ensureIndex(...args: any[]): any;
13
18
  findAndModify(...args: any[]): any;
14
19
  getIndexes(...args: any[]): any;
15
20
 
21
+ /** Formatter for debug print args */
22
+ $format(arg: any, color?: boolean, shell?: boolean): string;
23
+ /** Debug print helper */
24
+ $print(name: string, i: string | number, args: any[], color?: boolean, shell?: boolean): void;
25
+
16
26
  /** The collection name */
17
- collectionName: string;
27
+ get collectionName(): string;
18
28
  /** The Connection instance */
19
29
  conn: Connection;
20
30
  /** The collection name */
21
31
  name: string;
22
32
  }
23
33
 
24
- export type BaseCollection<T extends mongodb.Document> = CollectionBase<T>;
25
-
26
34
  /*
27
35
  * section drivers/node-mongodb-native/collection.js
28
36
  */
29
- interface Collection<T extends mongodb.Document = mongodb.Document> extends CollectionBase<T> {
37
+ class Collection<T extends mongodb.Document = mongodb.Document> extends BaseCollection<T> {
30
38
  /**
31
39
  * Collection constructor
32
40
  * @param name name of the collection
33
41
  * @param conn A MongooseConnection instance
34
42
  * @param opts optional collection options
35
43
  */
36
- // eslint-disable-next-line @typescript-eslint/no-misused-new
37
- new(name: string, conn: Connection, opts?: any): Collection<T>;
38
- /** Formatter for debug print args */
39
- $format(arg: any, color?: boolean, shell?: boolean): string;
40
- /** Debug print helper */
41
- $print(name: string, i: string | number, args: any[], color?: boolean, shell?: boolean): void;
44
+ constructor(name: string, conn: Connection, opts?: any);
45
+
42
46
  /** Retrieves information about this collections indexes. */
43
47
  getIndexes(): ReturnType<mongodb.Collection<T>['indexInformation']>;
44
48
  }
45
- let Collection: Collection;
46
49
  }
@@ -71,8 +71,6 @@ declare module 'mongoose' {
71
71
  };
72
72
  }[keyof SchemaMap];
73
73
 
74
- export type BaseConnection = Connection;
75
-
76
74
  class Connection extends events.EventEmitter implements SessionStarter {
77
75
  /** Runs a [db-level aggregate()](https://www.mongodb.com/docs/manual/reference/method/db.aggregate/) on this connection's underlying `db` */
78
76
  aggregate<ResultType = unknown>(pipeline?: PipelineStage[] | null, options?: AggregateOptions): Aggregate<Array<ResultType>>;
@@ -286,4 +284,5 @@ declare module 'mongoose' {
286
284
  withSession<T = any>(executor: (session: ClientSession) => Promise<T>): Promise<T>;
287
285
  }
288
286
 
287
+ export class BaseConnection extends Connection {}
289
288
  }
@@ -35,6 +35,10 @@ declare module 'mongoose' {
35
35
  TypeKey
36
36
  >;
37
37
 
38
+ type UnionToRawPathType<T extends readonly any[]> = T[number] extends infer U
39
+ ? ResolveRawPathType<U>
40
+ : never;
41
+
38
42
  /**
39
43
  * Same as inferSchemaType, except:
40
44
  *
@@ -109,11 +113,12 @@ declare module 'mongoose' {
109
113
  IfEquals<PathValueType, Schema.Types.UUID> extends true ? Buffer :
110
114
  PathValueType extends MapConstructor | 'Map' ? Map<string, ResolveRawPathType<Options['of']>> :
111
115
  IfEquals<PathValueType, typeof Schema.Types.Map> extends true ? Map<string, ResolveRawPathType<Options['of']>> :
112
- PathValueType extends ArrayConstructor ? any[] :
113
- PathValueType extends typeof Schema.Types.Mixed ? any:
114
- IfEquals<PathValueType, ObjectConstructor> extends true ? any:
115
- IfEquals<PathValueType, {}> extends true ? any:
116
- PathValueType extends typeof SchemaType ? PathValueType['prototype'] :
117
- PathValueType extends Record<string, any> ? InferRawDocType<PathValueType> :
118
- unknown;
116
+ PathValueType extends 'Union' | 'union' | typeof Schema.Types.Union ? Options['of'] extends readonly any[] ? UnionToRawPathType<Options['of']> : never :
117
+ PathValueType extends ArrayConstructor ? any[] :
118
+ PathValueType extends typeof Schema.Types.Mixed ? any:
119
+ IfEquals<PathValueType, ObjectConstructor> extends true ? any:
120
+ IfEquals<PathValueType, {}> extends true ? any:
121
+ PathValueType extends typeof SchemaType ? PathValueType['prototype'] :
122
+ PathValueType extends Record<string, any> ? InferRawDocType<PathValueType> :
123
+ unknown;
119
124
  }
@@ -75,10 +75,7 @@ declare module 'mongoose' {
75
75
 
76
76
  type ApplySchemaOptions<T, O = DefaultSchemaOptions> = ResolveTimestamps<T, O>;
77
77
 
78
- type ResolveTimestamps<T, O> = O extends { methods: any } | { statics: any } | { virtuals: any } | { timestamps?: false } ? T
79
- // For some reason, TypeScript sets all the document properties to unknown
80
- // if we use methods, statics, or virtuals. So avoid inferring timestamps
81
- // if any of these are set for now. See gh-12807
78
+ type ResolveTimestamps<T, O> = O extends { timestamps?: false } ? T
82
79
  : O extends { timestamps: infer TimestampOptions } ? TimestampOptions extends true
83
80
  ? { createdAt: NativeDate; updatedAt: NativeDate; } & T
84
81
  : TimestampOptions extends SchemaTimestampsConfig
@@ -206,6 +203,10 @@ TypeHint<PathValueType>
206
203
  */
207
204
  type PathEnumOrString<T extends SchemaTypeOptions<string>['enum']> = T extends ReadonlyArray<infer E> ? E : T extends { values: any } ? PathEnumOrString<T['values']> : T extends Record<string, infer V> ? V : string;
208
205
 
206
+ type UnionToType<T extends readonly any[]> = T[number] extends infer U
207
+ ? ResolvePathType<U>
208
+ : never;
209
+
209
210
  type IsSchemaTypeFromBuiltinClass<T> = T extends (typeof String)
210
211
  ? true
211
212
  : T extends (typeof Number)
@@ -317,11 +318,12 @@ type ResolvePathType<PathValueType, Options extends SchemaTypeOptions<PathValueT
317
318
  IfEquals<PathValueType, Schema.Types.UUID> extends true ? Buffer :
318
319
  PathValueType extends MapConstructor | 'Map' ? Map<string, ResolvePathType<Options['of']>> :
319
320
  IfEquals<PathValueType, typeof Schema.Types.Map> extends true ? Map<string, ResolvePathType<Options['of']>> :
320
- PathValueType extends ArrayConstructor ? any[] :
321
- PathValueType extends typeof Schema.Types.Mixed ? any:
322
- IfEquals<PathValueType, ObjectConstructor> extends true ? any:
323
- IfEquals<PathValueType, {}> extends true ? any:
324
- PathValueType extends typeof SchemaType ? PathValueType['prototype'] :
325
- PathValueType extends Record<string, any> ? ObtainDocumentType<PathValueType, any, { typeKey: TypeKey }> :
326
- unknown,
321
+ PathValueType extends 'Union' | 'union' | typeof Schema.Types.Union ? Options['of'] extends readonly any[] ? UnionToType<Options['of']> : never :
322
+ PathValueType extends ArrayConstructor ? any[] :
323
+ PathValueType extends typeof Schema.Types.Mixed ? any:
324
+ IfEquals<PathValueType, ObjectConstructor> extends true ? any:
325
+ IfEquals<PathValueType, {}> extends true ? any:
326
+ PathValueType extends typeof SchemaType ? PathValueType['prototype'] :
327
+ PathValueType extends Record<string, any> ? ObtainDocumentType<PathValueType, any, { typeKey: TypeKey }> :
328
+ unknown,
327
329
  TypeHint>;
@@ -188,7 +188,7 @@ declare module 'mongoose' {
188
188
  _id?: boolean;
189
189
 
190
190
  /** If set, specifies the type of this map's values. Mongoose will cast this map's values to the given type. */
191
- of?: Function | SchemaDefinitionProperty<any>;
191
+ of?: Function | SchemaDefinitionProperty<any> | (Function | SchemaDefinitionProperty<any>)[];
192
192
 
193
193
  /** If true, uses Mongoose's default `_id` settings. Only allowed for ObjectIds */
194
194
  auto?: boolean;
@@ -569,6 +569,13 @@ declare module 'mongoose' {
569
569
  static defaultOptions: Record<string, any>;
570
570
  }
571
571
 
572
+ class Union extends SchemaType {
573
+ static schemaName: 'Union';
574
+
575
+ /** Default options for this SchemaType */
576
+ static defaultOptions: Record<string, any>;
577
+ }
578
+
572
579
  class UUID extends SchemaType {
573
580
  /** This schema type's name, to defend against minifiers that mangle function names. */
574
581
  static schemaName: 'UUID';