mongoose 7.1.0 → 7.1.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.
@@ -0,0 +1,100 @@
1
+ /*!
2
+ * Module dependencies.
3
+ */
4
+
5
+ 'use strict';
6
+
7
+ const MongooseError = require('../error/mongooseError');
8
+ const SchemaType = require('../schematype');
9
+ const SubdocumentPath = require('./SubdocumentPath');
10
+ const getConstructor = require('../helpers/discriminator/getConstructor');
11
+
12
+ /**
13
+ * DocumentArrayElement SchemaType constructor.
14
+ *
15
+ * @param {String} path
16
+ * @param {Object} options
17
+ * @inherits SchemaType
18
+ * @api public
19
+ */
20
+
21
+ function DocumentArrayElement(path, options) {
22
+ this.$parentSchemaType = options && options.$parentSchemaType;
23
+ if (!this.$parentSchemaType) {
24
+ throw new MongooseError('Cannot create DocumentArrayElement schematype without a parent');
25
+ }
26
+ delete options.$parentSchemaType;
27
+
28
+ SchemaType.call(this, path, options, 'DocumentArrayElement');
29
+
30
+ this.$isMongooseDocumentArrayElement = true;
31
+ }
32
+
33
+ /**
34
+ * This schema type's name, to defend against minifiers that mangle
35
+ * function names.
36
+ *
37
+ * @api public
38
+ */
39
+ DocumentArrayElement.schemaName = 'DocumentArrayElement';
40
+
41
+ DocumentArrayElement.defaultOptions = {};
42
+
43
+ /*!
44
+ * Inherits from SchemaType.
45
+ */
46
+ DocumentArrayElement.prototype = Object.create(SchemaType.prototype);
47
+ DocumentArrayElement.prototype.constructor = DocumentArrayElement;
48
+
49
+ /**
50
+ * Casts `val` for DocumentArrayElement.
51
+ *
52
+ * @param {Object} value to cast
53
+ * @api private
54
+ */
55
+
56
+ DocumentArrayElement.prototype.cast = function(...args) {
57
+ return this.$parentSchemaType.cast(...args)[0];
58
+ };
59
+
60
+ /**
61
+ * Casts contents for queries.
62
+ *
63
+ * @param {String} $cond
64
+ * @param {any} [val]
65
+ * @api private
66
+ */
67
+
68
+ DocumentArrayElement.prototype.doValidate = function(value, fn, scope, options) {
69
+ const Constructor = getConstructor(this.caster, value);
70
+
71
+ if (value && !(value instanceof Constructor)) {
72
+ value = new Constructor(value, scope, null, null, options && options.index != null ? options.index : null);
73
+ }
74
+
75
+ return SubdocumentPath.prototype.doValidate.call(this, value, fn, scope, options);
76
+ };
77
+
78
+ /**
79
+ * Clone the current SchemaType
80
+ *
81
+ * @return {DocumentArrayElement} The cloned instance
82
+ * @api private
83
+ */
84
+
85
+ DocumentArrayElement.prototype.clone = function() {
86
+ this.options.$parentSchemaType = this.$parentSchemaType;
87
+ const ret = SchemaType.prototype.clone.apply(this, arguments);
88
+ delete this.options.$parentSchemaType;
89
+
90
+ ret.caster = this.caster;
91
+ ret.schema = this.schema;
92
+
93
+ return ret;
94
+ };
95
+
96
+ /*!
97
+ * Module exports.
98
+ */
99
+
100
+ module.exports = DocumentArrayElement;
@@ -84,6 +84,7 @@ function _createConstructor(schema, baseClass) {
84
84
  _embedded.prototype = Object.create(proto);
85
85
  _embedded.prototype.$__setSchema(schema);
86
86
  _embedded.prototype.constructor = _embedded;
87
+ _embedded.base = schema.base;
87
88
  _embedded.schema = schema;
88
89
  _embedded.$isSingleNested = true;
89
90
  _embedded.events = new EventEmitter();
@@ -6,11 +6,11 @@
6
6
 
7
7
  const ArrayType = require('./array');
8
8
  const CastError = require('../error/cast');
9
+ const DocumentArrayElement = require('./DocumentArrayElement');
9
10
  const EventEmitter = require('events').EventEmitter;
10
11
  const SchemaDocumentArrayOptions =
11
12
  require('../options/SchemaDocumentArrayOptions');
12
13
  const SchemaType = require('../schematype');
13
- const SubdocumentPath = require('./SubdocumentPath');
14
14
  const discriminator = require('../helpers/model/discriminator');
15
15
  const handleIdOption = require('../helpers/schema/handleIdOption');
16
16
  const handleSpreadDoc = require('../helpers/document/handleSpreadDoc');
@@ -74,25 +74,14 @@ function DocumentArrayPath(key, schema, options, schemaOptions) {
74
74
  });
75
75
  }
76
76
 
77
- const parentSchemaType = this;
78
- this.$embeddedSchemaType = new SchemaType(key + '.$', {
77
+ const $parentSchemaType = this;
78
+ this.$embeddedSchemaType = new DocumentArrayElement(key + '.$', {
79
79
  required: this &&
80
80
  this.schemaOptions &&
81
- this.schemaOptions.required || false
81
+ this.schemaOptions.required || false,
82
+ $parentSchemaType
82
83
  });
83
- this.$embeddedSchemaType.cast = function(value, doc, init) {
84
- return parentSchemaType.cast(value, doc, init)[0];
85
- };
86
- this.$embeddedSchemaType.doValidate = function(value, fn, scope, options) {
87
- const Constructor = getConstructor(this.caster, value);
88
-
89
- if (value && !(value instanceof Constructor)) {
90
- value = new Constructor(value, scope, null, null, options && options.index != null ? options.index : null);
91
- }
92
84
 
93
- return SubdocumentPath.prototype.doValidate.call(this, value, fn, scope, options);
94
- };
95
- this.$embeddedSchemaType.$isMongooseDocumentArrayElement = true;
96
85
  this.$embeddedSchemaType.caster = this.Constructor;
97
86
  this.$embeddedSchemaType.schema = this.schema;
98
87
  }
@@ -202,6 +202,7 @@ SchemaString.checkRequired = SchemaType.checkRequired;
202
202
  * @param {...String|Object} [args] enumeration values
203
203
  * @return {SchemaType} this
204
204
  * @see Customized Error Messages https://mongoosejs.com/docs/api/error.html#Error.messages
205
+ * @see Enums in JavaScript https://masteringjs.io/tutorials/fundamentals/enum
205
206
  * @api public
206
207
  */
207
208
 
package/lib/schema.js CHANGED
@@ -78,6 +78,7 @@ let id = 0;
78
78
  * - [skipVersioning](https://mongoosejs.com/docs/guide.html#skipVersioning): object - paths to exclude from versioning
79
79
  * - [timestamps](https://mongoosejs.com/docs/guide.html#timestamps): object or boolean - defaults to `false`. If true, Mongoose adds `createdAt` and `updatedAt` properties to your schema and manages those properties for you.
80
80
  * - [pluginTags](https://mongoosejs.com/docs/guide.html#pluginTags): array of strings - defaults to `undefined`. If set and plugin called with `tags` option, will only apply that plugin to schemas with a matching tag.
81
+ * - [virtuals](https://mongoosejs.com/docs/tutorials/virtuals.html#virtuals-via-schema-options): object - virtuals to define, alias for [`.virtual`](https://mongoosejs.com/docs/api/schema.html#Schema.prototype.virtual())
81
82
  *
82
83
  * #### Options for Nested Schemas:
83
84
  *
@@ -739,6 +740,10 @@ Schema.prototype.add = function add(obj, prefix) {
739
740
  if (this._userProvidedOptions.typeKey) {
740
741
  childSchemaOptions.typeKey = this._userProvidedOptions.typeKey;
741
742
  }
743
+ // propagate 'strict' option to child schema
744
+ if (this._userProvidedOptions.strict != null) {
745
+ childSchemaOptions.strict = this._userProvidedOptions.strict;
746
+ }
742
747
 
743
748
  const _schema = new Schema(_typeDef, childSchemaOptions);
744
749
  _schema.$implicitlyCreated = true;
@@ -2059,9 +2064,31 @@ Schema.prototype.set = function(key, value, tags) {
2059
2064
  break;
2060
2065
  }
2061
2066
 
2067
+ // Propagate `strict` and `strictQuery` changes down to implicitly created schemas
2068
+ if (key === 'strict') {
2069
+ _propagateOptionsToImplicitlyCreatedSchemas(this, { strict: value });
2070
+ }
2071
+ if (key === 'strictQuery') {
2072
+ _propagateOptionsToImplicitlyCreatedSchemas(this, { strictQuery: value });
2073
+ }
2074
+
2062
2075
  return this;
2063
2076
  };
2064
2077
 
2078
+ /*!
2079
+ * Recursively set options on implicitly created schemas
2080
+ */
2081
+
2082
+ function _propagateOptionsToImplicitlyCreatedSchemas(baseSchema, options) {
2083
+ for (const { schema } of baseSchema.childSchemas) {
2084
+ if (!schema.$implicitlyCreated) {
2085
+ continue;
2086
+ }
2087
+ Object.assign(schema.options, options);
2088
+ _propagateOptionsToImplicitlyCreatedSchemas(schema, options);
2089
+ }
2090
+ }
2091
+
2065
2092
  /**
2066
2093
  * Gets a schema option.
2067
2094
  *
package/lib/types/map.js CHANGED
@@ -96,9 +96,10 @@ class MongooseMap extends Map {
96
96
  return;
97
97
  }
98
98
 
99
- const fullPath = this.$__path + '.' + key;
100
- const populated = this.$__parent != null && this.$__parent.$__ ?
101
- this.$__parent.$populated(fullPath, true) || this.$__parent.$populated(this.$__path, true) :
99
+ let _fullPath;
100
+ const parent = this.$__parent;
101
+ const populated = parent != null && parent.$__ && parent.$__.populated ?
102
+ parent.$populated(fullPath.call(this), true) || parent.$populated(this.$__path, true) :
102
103
  null;
103
104
  const priorVal = this.get(key);
104
105
 
@@ -127,11 +128,19 @@ class MongooseMap extends Map {
127
128
  }
128
129
  } else {
129
130
  try {
130
- value = this.$__schemaType.
131
- applySetters(value, this.$__parent, false, this.get(key), { path: fullPath });
131
+ const options = this.$__schemaType.$isMongooseDocumentArray || this.$__schemaType.$isSingleNested ?
132
+ { path: fullPath.call(this) } :
133
+ null;
134
+ value = this.$__schemaType.applySetters(
135
+ value,
136
+ this.$__parent,
137
+ false,
138
+ this.get(key),
139
+ options
140
+ );
132
141
  } catch (error) {
133
142
  if (this.$__parent != null && this.$__parent.$__ != null) {
134
- this.$__parent.invalidate(fullPath, error);
143
+ this.$__parent.invalidate(fullPath.call(this), error);
135
144
  return;
136
145
  }
137
146
  throw error;
@@ -140,13 +149,18 @@ class MongooseMap extends Map {
140
149
 
141
150
  super.set(key, value);
142
151
 
143
- if (value != null && value.$isSingleNested) {
144
- value.$basePath = this.$__path + '.' + key;
152
+ if (parent != null && parent.$__ != null && !deepEqual(value, priorVal)) {
153
+ parent.markModified(fullPath.call(this));
145
154
  }
146
155
 
147
- const parent = this.$__parent;
148
- if (parent != null && parent.$__ != null && !deepEqual(value, priorVal)) {
149
- parent.markModified(this.$__path + '.' + key);
156
+ // Delay calculating full path unless absolutely necessary, because string
157
+ // concatenation is a bottleneck re: #13171
158
+ function fullPath() {
159
+ if (_fullPath) {
160
+ return _fullPath;
161
+ }
162
+ _fullPath = this.$__path + '.' + key;
163
+ return _fullPath;
150
164
  }
151
165
  }
152
166
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "7.1.0",
4
+ "version": "7.1.2",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -28,10 +28,10 @@
28
28
  "sift": "16.0.1"
29
29
  },
30
30
  "devDependencies": {
31
- "@babel/core": "7.21.4",
32
- "@babel/preset-env": "7.21.4",
33
- "@typescript-eslint/eslint-plugin": "5.57.0",
34
- "@typescript-eslint/parser": "5.57.0",
31
+ "@babel/core": "7.21.8",
32
+ "@babel/preset-env": "7.21.5",
33
+ "@typescript-eslint/eslint-plugin": "5.59.2",
34
+ "@typescript-eslint/parser": "5.59.2",
35
35
  "acquit": "1.3.0",
36
36
  "acquit-ignore": "0.2.1",
37
37
  "acquit-require": "0.1.1",
@@ -39,34 +39,35 @@
39
39
  "axios": "1.1.3",
40
40
  "babel-loader": "8.2.5",
41
41
  "benchmark": "2.1.4",
42
+ "bluebird": "3.7.2",
42
43
  "broken-link-checker": "^0.7.8",
43
44
  "buffer": "^5.6.0",
44
45
  "cheerio": "1.0.0-rc.12",
45
46
  "crypto-browserify": "3.12.0",
46
47
  "dotenv": "16.0.3",
47
48
  "dox": "1.0.0",
48
- "eslint": "8.37.0",
49
+ "eslint": "8.39.0",
49
50
  "eslint-plugin-markdown": "^3.0.0",
50
51
  "eslint-plugin-mocha-no-only": "1.1.1",
51
52
  "express": "^4.18.1",
52
- "highlight.js": "11.7.0",
53
+ "highlight.js": "11.8.0",
53
54
  "lodash.isequal": "4.5.0",
54
55
  "lodash.isequalwith": "4.4.0",
55
56
  "marked": "4.3.0",
56
57
  "mkdirp": "^2.1.3",
57
58
  "mocha": "10.2.0",
58
59
  "moment": "2.x",
59
- "mongodb-memory-server": "8.12.1",
60
+ "mongodb-memory-server": "8.12.2",
60
61
  "ncp": "^2.0.0",
61
62
  "nyc": "15.1.0",
62
63
  "pug": "3.0.2",
63
64
  "q": "1.5.1",
64
- "sinon": "15.0.3",
65
+ "sinon": "15.0.4",
65
66
  "stream-browserify": "3.0.0",
66
67
  "tsd": "0.25.0",
67
- "typescript": "5.0.3",
68
+ "typescript": "5.0.4",
68
69
  "uuid": "9.0.0",
69
- "webpack": "5.77.0",
70
+ "webpack": "5.81.0",
70
71
  "fs-extra": "~11.1.1"
71
72
  },
72
73
  "directories": {
@@ -79,6 +80,7 @@
79
80
  "docs:clean:6x": "rimraf index.html && rimraf -rf ./docs/6.x && rimraf -rf ./docs/source/_docs && rimraf -rf ./tmp",
80
81
  "docs:copy:tmp": "mkdirp ./tmp/docs/css && mkdirp ./tmp/docs/js && mkdirp ./tmp/docs/images && mkdirp ./tmp/docs/tutorials && mkdirp ./tmp/docs/typescript && mkdirp ./tmp/docs/api && ncp ./docs/css ./tmp/docs/css --filter=.css$ && ncp ./docs/js ./tmp/docs/js --filter=.js$ && ncp ./docs/images ./tmp/docs/images && ncp ./docs/tutorials ./tmp/docs/tutorials && ncp ./docs/typescript ./tmp/docs/typescript && ncp ./docs/api ./tmp/docs/api && cp index.html ./tmp && cp docs/*.html ./tmp/docs/",
81
82
  "docs:copy:tmp:5x": "rimraf ./docs/5.x && ncp ./tmp ./docs/5.x",
83
+ "docs:move:6x:tmp": "mv ./docs/6.x ./tmp",
82
84
  "docs:copy:tmp:6x": "rimraf ./docs/6.x && ncp ./tmp ./docs/6.x",
83
85
  "docs:checkout:gh-pages": "git checkout gh-pages",
84
86
  "docs:checkout:5x": "git checkout 5.x",
@@ -93,7 +95,7 @@
93
95
  "docs:view": "node ./scripts/static.js",
94
96
  "docs:prepare:publish:stable": "npm run docs:checkout:gh-pages && npm run docs:merge:stable && npm run docs:clean:stable && npm run docs:generate && npm run docs:generate:search",
95
97
  "docs:prepare:publish:5x": "npm run docs:checkout:5x && npm run docs:merge:5x && npm run docs:clean:stable && npm run docs:generate && npm run docs:copy:tmp && npm run docs:checkout:gh-pages && npm run docs:copy:tmp:5x",
96
- "docs:prepare:publish:6x": "npm run docs:checkout:6x && npm run docs:merge:6x && npm run docs:clean:stable && npm run docs:generate && npm run docs:copy:tmp && npm run docs:checkout:gh-pages && npm run docs:copy:tmp:6x",
98
+ "docs:prepare:publish:6x": "npm run docs:checkout:6x && npm run docs:merge:6x && npm run docs:clean:stable && env DOCS_DEPLOY=true npm run docs:generate && npm run docs:move:6x:tmp && npm run docs:checkout:gh-pages && npm run docs:copy:tmp:6x",
97
99
  "docs:check-links": "blc http://127.0.0.1:8089 -ro",
98
100
  "lint": "eslint .",
99
101
  "lint-js": "eslint . --ext .js",
@@ -90,9 +90,9 @@ declare module 'mongoose' {
90
90
  $session(session?: ClientSession | null): ClientSession | null;
91
91
 
92
92
  /** Alias for `set()`, used internally to avoid conflicts */
93
- $set(path: string, val: any, type: any, options?: DocumentSetOptions): this;
94
- $set(path: string, val: any, options?: DocumentSetOptions): this;
95
- $set(value: any): this;
93
+ $set(path: string | Record<string, any>, val: any, type: any, options?: DocumentSetOptions): this;
94
+ $set(path: string | Record<string, any>, val: any, options?: DocumentSetOptions): this;
95
+ $set(value: string | Record<string, any>): this;
96
96
 
97
97
  /** Set this property to add additional query filters when Mongoose saves this document and `isNew` is false. */
98
98
  $where: Record<string, unknown>;
@@ -107,7 +107,7 @@ declare module 'mongoose' {
107
107
  db: Connection;
108
108
 
109
109
  /** Removes this document from the db. */
110
- deleteOne(options?: QueryOptions): QueryWithHelpers<any, this, TQueryHelpers>;
110
+ deleteOne(options?: QueryOptions): Promise<this>;
111
111
 
112
112
  /**
113
113
  * Takes a populated field and returns it to its unpopulated state. If called with
@@ -216,9 +216,9 @@ declare module 'mongoose' {
216
216
  schema: Schema;
217
217
 
218
218
  /** Sets the value of a path, or many paths. */
219
- set(path: string, val: any, type: any, options?: any): this;
220
- set(path: string, val: any, options?: any): this;
221
- set(value: any): this;
219
+ set(path: string | Record<string, any>, val: any, type: any, options?: DocumentSetOptions): this;
220
+ set(path: string | Record<string, any>, val: any, options?: DocumentSetOptions): this;
221
+ set(value: string | Record<string, any>): this;
222
222
 
223
223
  /** The return value of this method is used in calls to JSON.stringify(doc). */
224
224
  toJSON<T = Require_id<DocType>>(options?: ToObjectOptions & { flattenMaps?: true }): FlattenMaps<T>;
package/types/index.d.ts CHANGED
@@ -594,11 +594,18 @@ declare module 'mongoose' {
594
594
  export type UpdateQuery<T> = _UpdateQuery<T> & AnyObject;
595
595
 
596
596
  export type FlattenMaps<T> = {
597
- [K in keyof T]: T[K] extends Map<any, infer V>
598
- ? Record<string, V> : T[K] extends TreatAsPrimitives
599
- ? T[K] : FlattenMaps<T[K]>;
597
+ [K in keyof T]: FlattenProperty<T[K]>;
600
598
  };
601
599
 
600
+ /**
601
+ * Separate type is needed for properties of union type (for example, Types.DocumentArray | undefined) to apply conditional check to each member of it
602
+ * https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types
603
+ */
604
+ type FlattenProperty<T> = T extends Map<any, infer V>
605
+ ? Record<string, V> : T extends TreatAsPrimitives
606
+ ? T : T extends Types.DocumentArray<infer ItemType>
607
+ ? Types.DocumentArray<FlattenMaps<ItemType>> : FlattenMaps<T>;
608
+
602
609
  export type actualPrimitives = string | boolean | number | bigint | symbol | null | undefined;
603
610
  export type TreatAsPrimitives = actualPrimitives | NativeDate | RegExp | symbol | Error | BigInt | Types.ObjectId | Buffer | Function;
604
611