mongoose 8.8.4 → 8.9.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/dist/browser.umd.js +1 -1
- package/lib/cast/double.js +50 -0
- package/lib/cast/int32.js +36 -0
- package/lib/connection.js +220 -18
- package/lib/cursor/aggregationCursor.js +1 -2
- package/lib/document.js +19 -7
- package/lib/drivers/node-mongodb-native/collection.js +0 -1
- package/lib/drivers/node-mongodb-native/connection.js +0 -4
- package/lib/helpers/clone.js +5 -0
- package/lib/helpers/model/castBulkWrite.js +218 -205
- package/lib/helpers/model/discriminator.js +1 -0
- package/lib/helpers/populate/getModelsMapForPopulate.js +7 -0
- package/lib/helpers/schema/getIndexes.js +5 -0
- package/lib/model.js +71 -107
- package/lib/mongoose.js +20 -20
- package/lib/query.js +6 -20
- package/lib/queryHelpers.js +13 -32
- package/lib/schema/bigint.js +2 -2
- package/lib/schema/double.js +212 -0
- package/lib/schema/index.js +2 -0
- package/lib/schema/int32.js +249 -0
- package/lib/schema/string.js +10 -10
- package/lib/schema.js +60 -7
- package/lib/schemaType.js +36 -8
- package/lib/validOptions.js +1 -0
- package/package.json +5 -5
- package/types/expressions.d.ts +102 -0
- package/types/index.d.ts +1 -1
- package/types/indexes.d.ts +4 -2
- package/types/inferschematype.d.ts +29 -27
- package/types/populate.d.ts +2 -0
- package/types/schematypes.d.ts +34 -1
- package/types/types.d.ts +5 -3
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/*!
|
|
4
|
+
* Module dependencies.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const CastError = require('../error/cast');
|
|
8
|
+
const SchemaType = require('../schemaType');
|
|
9
|
+
const castDouble = require('../cast/double');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Double SchemaType constructor.
|
|
13
|
+
*
|
|
14
|
+
* @param {String} path
|
|
15
|
+
* @param {Object} options
|
|
16
|
+
* @inherits SchemaType
|
|
17
|
+
* @api public
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
function SchemaDouble(path, options) {
|
|
21
|
+
SchemaType.call(this, path, options, 'Double');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* This schema type's name, to defend against minifiers that mangle
|
|
26
|
+
* function names.
|
|
27
|
+
*
|
|
28
|
+
* @api public
|
|
29
|
+
*/
|
|
30
|
+
SchemaDouble.schemaName = 'Double';
|
|
31
|
+
|
|
32
|
+
SchemaDouble.defaultOptions = {};
|
|
33
|
+
|
|
34
|
+
/*!
|
|
35
|
+
* Inherits from SchemaType.
|
|
36
|
+
*/
|
|
37
|
+
SchemaDouble.prototype = Object.create(SchemaType.prototype);
|
|
38
|
+
SchemaDouble.prototype.constructor = SchemaDouble;
|
|
39
|
+
|
|
40
|
+
/*!
|
|
41
|
+
* ignore
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
SchemaDouble._cast = castDouble;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Sets a default option for all Double instances.
|
|
48
|
+
*
|
|
49
|
+
* #### Example:
|
|
50
|
+
*
|
|
51
|
+
* // Make all Double fields required by default
|
|
52
|
+
* mongoose.Schema.Double.set('required', true);
|
|
53
|
+
*
|
|
54
|
+
* @param {String} option The option you'd like to set the value for
|
|
55
|
+
* @param {Any} value value for option
|
|
56
|
+
* @return {undefined}
|
|
57
|
+
* @function set
|
|
58
|
+
* @static
|
|
59
|
+
* @api public
|
|
60
|
+
*/
|
|
61
|
+
|
|
62
|
+
SchemaDouble.set = SchemaType.set;
|
|
63
|
+
|
|
64
|
+
SchemaDouble.setters = [];
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Attaches a getter for all Double instances
|
|
68
|
+
*
|
|
69
|
+
* #### Example:
|
|
70
|
+
*
|
|
71
|
+
* // Converts Double to be a represent milliseconds upon access
|
|
72
|
+
* mongoose.Schema.Double.get(v => v == null ? '0.000 ms' : v.toString() + ' ms');
|
|
73
|
+
*
|
|
74
|
+
* @param {Function} getter
|
|
75
|
+
* @return {this}
|
|
76
|
+
* @function get
|
|
77
|
+
* @static
|
|
78
|
+
* @api public
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
SchemaDouble.get = SchemaType.get;
|
|
82
|
+
|
|
83
|
+
/*!
|
|
84
|
+
* ignore
|
|
85
|
+
*/
|
|
86
|
+
|
|
87
|
+
SchemaDouble._defaultCaster = v => {
|
|
88
|
+
if (v != null) {
|
|
89
|
+
if (v._bsontype !== 'Double') {
|
|
90
|
+
throw new Error();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return v;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Get/set the function used to cast arbitrary values to IEEE 754-2008 floating points
|
|
99
|
+
*
|
|
100
|
+
* #### Example:
|
|
101
|
+
*
|
|
102
|
+
* // Make Mongoose cast any NaNs to 0
|
|
103
|
+
* const defaultCast = mongoose.Schema.Types.Double.cast();
|
|
104
|
+
* mongoose.Schema.Types.Double.cast(v => {
|
|
105
|
+
* if (isNaN(v)) {
|
|
106
|
+
* return 0;
|
|
107
|
+
* }
|
|
108
|
+
* return defaultCast(v);
|
|
109
|
+
* });
|
|
110
|
+
*
|
|
111
|
+
* // Or disable casting for Doubles entirely (only JS numbers are permitted)
|
|
112
|
+
* mongoose.Schema.Double.cast(false);
|
|
113
|
+
*
|
|
114
|
+
*
|
|
115
|
+
* @param {Function} caster
|
|
116
|
+
* @return {Function}
|
|
117
|
+
* @function get
|
|
118
|
+
* @static
|
|
119
|
+
* @api public
|
|
120
|
+
*/
|
|
121
|
+
|
|
122
|
+
SchemaDouble.cast = function cast(caster) {
|
|
123
|
+
if (arguments.length === 0) {
|
|
124
|
+
return this._cast;
|
|
125
|
+
}
|
|
126
|
+
if (caster === false) {
|
|
127
|
+
caster = this._defaultCaster;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
this._cast = caster;
|
|
131
|
+
|
|
132
|
+
return this._cast;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
/*!
|
|
137
|
+
* ignore
|
|
138
|
+
*/
|
|
139
|
+
|
|
140
|
+
SchemaDouble._checkRequired = v => v != null;
|
|
141
|
+
/**
|
|
142
|
+
* Override the function the required validator uses to check whether a value
|
|
143
|
+
* passes the `required` check.
|
|
144
|
+
*
|
|
145
|
+
* @param {Function} fn
|
|
146
|
+
* @return {Function}
|
|
147
|
+
* @function checkRequired
|
|
148
|
+
* @static
|
|
149
|
+
* @api public
|
|
150
|
+
*/
|
|
151
|
+
|
|
152
|
+
SchemaDouble.checkRequired = SchemaType.checkRequired;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Check if the given value satisfies a required validator.
|
|
156
|
+
*
|
|
157
|
+
* @param {Any} value
|
|
158
|
+
* @return {Boolean}
|
|
159
|
+
* @api public
|
|
160
|
+
*/
|
|
161
|
+
|
|
162
|
+
SchemaDouble.prototype.checkRequired = function(value) {
|
|
163
|
+
return this.constructor._checkRequired(value);
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Casts to Double
|
|
168
|
+
*
|
|
169
|
+
* @param {Object} value
|
|
170
|
+
* @param {Object} model this value is optional
|
|
171
|
+
* @api private
|
|
172
|
+
*/
|
|
173
|
+
|
|
174
|
+
SchemaDouble.prototype.cast = function(value) {
|
|
175
|
+
let castDouble;
|
|
176
|
+
if (typeof this._castFunction === 'function') {
|
|
177
|
+
castDouble = this._castFunction;
|
|
178
|
+
} else if (typeof this.constructor.cast === 'function') {
|
|
179
|
+
castDouble = this.constructor.cast();
|
|
180
|
+
} else {
|
|
181
|
+
castDouble = SchemaDouble.cast();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
return castDouble(value);
|
|
186
|
+
} catch (error) {
|
|
187
|
+
throw new CastError('Double', value, this.path, error, this);
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
/*!
|
|
192
|
+
* ignore
|
|
193
|
+
*/
|
|
194
|
+
|
|
195
|
+
function handleSingle(val) {
|
|
196
|
+
return this.cast(val);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
SchemaDouble.prototype.$conditionalHandlers = {
|
|
200
|
+
...SchemaType.prototype.$conditionalHandlers,
|
|
201
|
+
$gt: handleSingle,
|
|
202
|
+
$gte: handleSingle,
|
|
203
|
+
$lt: handleSingle,
|
|
204
|
+
$lte: handleSingle
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
/*!
|
|
209
|
+
* Module exports.
|
|
210
|
+
*/
|
|
211
|
+
|
|
212
|
+
module.exports = SchemaDouble;
|
package/lib/schema/index.js
CHANGED
|
@@ -19,6 +19,8 @@ exports.ObjectId = require('./objectId');
|
|
|
19
19
|
exports.String = require('./string');
|
|
20
20
|
exports.Subdocument = require('./subdocument');
|
|
21
21
|
exports.UUID = require('./uuid');
|
|
22
|
+
exports.Double = require('./double');
|
|
23
|
+
exports.Int32 = require('./int32');
|
|
22
24
|
|
|
23
25
|
// alias
|
|
24
26
|
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/*!
|
|
4
|
+
* Module dependencies.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const CastError = require('../error/cast');
|
|
8
|
+
const SchemaType = require('../schemaType');
|
|
9
|
+
const castInt32 = require('../cast/int32');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Int32 SchemaType constructor.
|
|
13
|
+
*
|
|
14
|
+
* @param {String} path
|
|
15
|
+
* @param {Object} options
|
|
16
|
+
* @inherits SchemaType
|
|
17
|
+
* @api public
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
function SchemaInt32(path, options) {
|
|
21
|
+
SchemaType.call(this, path, options, 'Int32');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* This schema type's name, to defend against minifiers that mangle
|
|
26
|
+
* function names.
|
|
27
|
+
*
|
|
28
|
+
* @api public
|
|
29
|
+
*/
|
|
30
|
+
SchemaInt32.schemaName = 'Int32';
|
|
31
|
+
|
|
32
|
+
SchemaInt32.defaultOptions = {};
|
|
33
|
+
|
|
34
|
+
/*!
|
|
35
|
+
* Inherits from SchemaType.
|
|
36
|
+
*/
|
|
37
|
+
SchemaInt32.prototype = Object.create(SchemaType.prototype);
|
|
38
|
+
SchemaInt32.prototype.constructor = SchemaInt32;
|
|
39
|
+
|
|
40
|
+
/*!
|
|
41
|
+
* ignore
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
SchemaInt32._cast = castInt32;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Sets a default option for all Int32 instances.
|
|
48
|
+
*
|
|
49
|
+
* #### Example:
|
|
50
|
+
*
|
|
51
|
+
* // Make all Int32 fields required by default
|
|
52
|
+
* mongoose.Schema.Int32.set('required', true);
|
|
53
|
+
*
|
|
54
|
+
* @param {String} option The option you'd like to set the value for
|
|
55
|
+
* @param {Any} value value for option
|
|
56
|
+
* @return {undefined}
|
|
57
|
+
* @function set
|
|
58
|
+
* @static
|
|
59
|
+
* @api public
|
|
60
|
+
*/
|
|
61
|
+
|
|
62
|
+
SchemaInt32.set = SchemaType.set;
|
|
63
|
+
|
|
64
|
+
SchemaInt32.setters = [];
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Attaches a getter for all Int32 instances
|
|
68
|
+
*
|
|
69
|
+
* #### Example:
|
|
70
|
+
*
|
|
71
|
+
* // Converts int32 to be a represent milliseconds upon access
|
|
72
|
+
* mongoose.Schema.Int32.get(v => v == null ? '0 ms' : v.toString() + ' ms');
|
|
73
|
+
*
|
|
74
|
+
* @param {Function} getter
|
|
75
|
+
* @return {this}
|
|
76
|
+
* @function get
|
|
77
|
+
* @static
|
|
78
|
+
* @api public
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
SchemaInt32.get = SchemaType.get;
|
|
82
|
+
|
|
83
|
+
/*!
|
|
84
|
+
* ignore
|
|
85
|
+
*/
|
|
86
|
+
|
|
87
|
+
SchemaInt32._defaultCaster = v => {
|
|
88
|
+
const INT32_MAX = 0x7FFFFFFF;
|
|
89
|
+
const INT32_MIN = -0x80000000;
|
|
90
|
+
|
|
91
|
+
if (v != null) {
|
|
92
|
+
if (typeof v !== 'number' || v !== (v | 0) || v < INT32_MIN || v > INT32_MAX) {
|
|
93
|
+
throw new Error();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return v;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Get/set the function used to cast arbitrary values to 32-bit integers
|
|
102
|
+
*
|
|
103
|
+
* #### Example:
|
|
104
|
+
*
|
|
105
|
+
* // Make Mongoose cast NaN to 0
|
|
106
|
+
* const defaultCast = mongoose.Schema.Types.Int32.cast();
|
|
107
|
+
* mongoose.Schema.Types.Int32.cast(v => {
|
|
108
|
+
* if (isNaN(v)) {
|
|
109
|
+
* return 0;
|
|
110
|
+
* }
|
|
111
|
+
* return defaultCast(v);
|
|
112
|
+
* });
|
|
113
|
+
*
|
|
114
|
+
* // Or disable casting for Int32s entirely (only JS numbers within 32-bit integer bounds and null-ish values are permitted)
|
|
115
|
+
* mongoose.Schema.Int32.cast(false);
|
|
116
|
+
*
|
|
117
|
+
*
|
|
118
|
+
* @param {Function} caster
|
|
119
|
+
* @return {Function}
|
|
120
|
+
* @function get
|
|
121
|
+
* @static
|
|
122
|
+
* @api public
|
|
123
|
+
*/
|
|
124
|
+
|
|
125
|
+
SchemaInt32.cast = function cast(caster) {
|
|
126
|
+
if (arguments.length === 0) {
|
|
127
|
+
return this._cast;
|
|
128
|
+
}
|
|
129
|
+
if (caster === false) {
|
|
130
|
+
caster = this._defaultCaster;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
this._cast = caster;
|
|
134
|
+
|
|
135
|
+
return this._cast;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
/*!
|
|
140
|
+
* ignore
|
|
141
|
+
*/
|
|
142
|
+
|
|
143
|
+
SchemaInt32._checkRequired = v => v != null;
|
|
144
|
+
/**
|
|
145
|
+
* Override the function the required validator uses to check whether a value
|
|
146
|
+
* passes the `required` check.
|
|
147
|
+
*
|
|
148
|
+
* @param {Function} fn
|
|
149
|
+
* @return {Function}
|
|
150
|
+
* @function checkRequired
|
|
151
|
+
* @static
|
|
152
|
+
* @api public
|
|
153
|
+
*/
|
|
154
|
+
|
|
155
|
+
SchemaInt32.checkRequired = SchemaType.checkRequired;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Check if the given value satisfies a required validator.
|
|
159
|
+
*
|
|
160
|
+
* @param {Any} value
|
|
161
|
+
* @return {Boolean}
|
|
162
|
+
* @api public
|
|
163
|
+
*/
|
|
164
|
+
|
|
165
|
+
SchemaInt32.prototype.checkRequired = function(value) {
|
|
166
|
+
return this.constructor._checkRequired(value);
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Casts to Int32
|
|
171
|
+
*
|
|
172
|
+
* @param {Object} value
|
|
173
|
+
* @param {Object} model this value is optional
|
|
174
|
+
* @api private
|
|
175
|
+
*/
|
|
176
|
+
|
|
177
|
+
SchemaInt32.prototype.cast = function(value) {
|
|
178
|
+
let castInt32;
|
|
179
|
+
if (typeof this._castFunction === 'function') {
|
|
180
|
+
castInt32 = this._castFunction;
|
|
181
|
+
} else if (typeof this.constructor.cast === 'function') {
|
|
182
|
+
castInt32 = this.constructor.cast();
|
|
183
|
+
} else {
|
|
184
|
+
castInt32 = SchemaInt32.cast();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
return castInt32(value);
|
|
189
|
+
} catch (error) {
|
|
190
|
+
throw new CastError('Int32', value, this.path, error, this);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
/*!
|
|
195
|
+
* ignore
|
|
196
|
+
*/
|
|
197
|
+
|
|
198
|
+
SchemaInt32.$conditionalHandlers = {
|
|
199
|
+
...SchemaType.prototype.$conditionalHandlers,
|
|
200
|
+
$gt: handleSingle,
|
|
201
|
+
$gte: handleSingle,
|
|
202
|
+
$lt: handleSingle,
|
|
203
|
+
$lte: handleSingle
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
/*!
|
|
207
|
+
* ignore
|
|
208
|
+
*/
|
|
209
|
+
|
|
210
|
+
function handleSingle(val, context) {
|
|
211
|
+
return this.castForQuery(null, val, context);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Casts contents for queries.
|
|
216
|
+
*
|
|
217
|
+
* @param {String} $conditional
|
|
218
|
+
* @param {any} val
|
|
219
|
+
* @api private
|
|
220
|
+
*/
|
|
221
|
+
|
|
222
|
+
SchemaInt32.prototype.castForQuery = function($conditional, val, context) {
|
|
223
|
+
let handler;
|
|
224
|
+
if ($conditional != null) {
|
|
225
|
+
handler = SchemaInt32.$conditionalHandlers[$conditional];
|
|
226
|
+
|
|
227
|
+
if (handler) {
|
|
228
|
+
return handler.call(this, val);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return this.applySetters(null, val, context);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
return this.applySetters(val, context);
|
|
236
|
+
} catch (err) {
|
|
237
|
+
if (err instanceof CastError && err.path === this.path && this.$fullPath != null) {
|
|
238
|
+
err.path = this.$fullPath;
|
|
239
|
+
}
|
|
240
|
+
throw err;
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
/*!
|
|
246
|
+
* Module exports.
|
|
247
|
+
*/
|
|
248
|
+
|
|
249
|
+
module.exports = SchemaInt32;
|
package/lib/schema/string.js
CHANGED
|
@@ -181,11 +181,11 @@ SchemaString.checkRequired = SchemaType.checkRequired;
|
|
|
181
181
|
* const s = new Schema({ state: { type: String, enum: states }})
|
|
182
182
|
* const M = db.model('M', s)
|
|
183
183
|
* const m = new M({ state: 'invalid' })
|
|
184
|
-
* m.save(
|
|
185
|
-
* console.error(
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
184
|
+
* await m.save()
|
|
185
|
+
* .catch((err) => console.error(err)); // ValidationError: `invalid` is not a valid enum value for path `state`.
|
|
186
|
+
* m.state = 'open';
|
|
187
|
+
* await m.save();
|
|
188
|
+
* // success
|
|
189
189
|
*
|
|
190
190
|
* // or with custom error messages
|
|
191
191
|
* const enum = {
|
|
@@ -195,11 +195,11 @@ SchemaString.checkRequired = SchemaType.checkRequired;
|
|
|
195
195
|
* const s = new Schema({ state: { type: String, enum: enum })
|
|
196
196
|
* const M = db.model('M', s)
|
|
197
197
|
* const m = new M({ state: 'invalid' })
|
|
198
|
-
* m.save(
|
|
199
|
-
* console.error(
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
198
|
+
* await m.save()
|
|
199
|
+
* .catch((err) => console.error(err)); // ValidationError: enum validator failed for path `state` with value `invalid`
|
|
200
|
+
* m.state = 'open';
|
|
201
|
+
* await m.save();
|
|
202
|
+
* // success
|
|
203
203
|
*
|
|
204
204
|
* @param {...String|Object} [args] enumeration values
|
|
205
205
|
* @return {SchemaType} this
|
package/lib/schema.js
CHANGED
|
@@ -441,7 +441,7 @@ Schema.prototype._clone = function _clone(Constructor) {
|
|
|
441
441
|
}
|
|
442
442
|
}
|
|
443
443
|
}
|
|
444
|
-
s.
|
|
444
|
+
s._gatherChildSchemas();
|
|
445
445
|
|
|
446
446
|
s.virtuals = clone(this.virtuals);
|
|
447
447
|
s.$globalPluginsApplied = this.$globalPluginsApplied;
|
|
@@ -1238,20 +1238,32 @@ Schema.prototype.path = function(path, obj) {
|
|
|
1238
1238
|
* ignore
|
|
1239
1239
|
*/
|
|
1240
1240
|
|
|
1241
|
-
function
|
|
1241
|
+
Schema.prototype._gatherChildSchemas = function _gatherChildSchemas() {
|
|
1242
1242
|
const childSchemas = [];
|
|
1243
1243
|
|
|
1244
|
-
for (const path of Object.keys(
|
|
1245
|
-
|
|
1244
|
+
for (const path of Object.keys(this.paths)) {
|
|
1245
|
+
if (typeof path !== 'string') {
|
|
1246
|
+
continue;
|
|
1247
|
+
}
|
|
1248
|
+
const schematype = this.paths[path];
|
|
1246
1249
|
if (schematype.$isMongooseDocumentArray || schematype.$isSingleNested) {
|
|
1247
|
-
childSchemas.push({
|
|
1250
|
+
childSchemas.push({
|
|
1251
|
+
schema: schematype.schema,
|
|
1252
|
+
model: schematype.caster,
|
|
1253
|
+
path: path
|
|
1254
|
+
});
|
|
1248
1255
|
} else if (schematype.$isSchemaMap && schematype.$__schemaType.$isSingleNested) {
|
|
1249
|
-
childSchemas.push({
|
|
1256
|
+
childSchemas.push({
|
|
1257
|
+
schema: schematype.$__schemaType.schema,
|
|
1258
|
+
model: schematype.$__schemaType.caster,
|
|
1259
|
+
path: path
|
|
1260
|
+
});
|
|
1250
1261
|
}
|
|
1251
1262
|
}
|
|
1252
1263
|
|
|
1264
|
+
this.childSchemas = childSchemas;
|
|
1253
1265
|
return childSchemas;
|
|
1254
|
-
}
|
|
1266
|
+
};
|
|
1255
1267
|
|
|
1256
1268
|
/*!
|
|
1257
1269
|
* ignore
|
|
@@ -2134,6 +2146,12 @@ Schema.prototype.index = function(fields, options) {
|
|
|
2134
2146
|
}
|
|
2135
2147
|
}
|
|
2136
2148
|
|
|
2149
|
+
for (const existingIndex of this.indexes()) {
|
|
2150
|
+
if (util.isDeepStrictEqual(existingIndex[0], fields)) {
|
|
2151
|
+
throw new MongooseError(`Schema already has an index on ${JSON.stringify(fields)}`);
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
|
|
2137
2155
|
this._indexes.push([fields, options]);
|
|
2138
2156
|
return this;
|
|
2139
2157
|
};
|
|
@@ -2810,6 +2828,39 @@ Schema.prototype._getPathType = function(path) {
|
|
|
2810
2828
|
return search(path.split('.'), _this);
|
|
2811
2829
|
};
|
|
2812
2830
|
|
|
2831
|
+
/**
|
|
2832
|
+
* Transforms the duplicate key error by checking for duplicate key error messages by path.
|
|
2833
|
+
* If no duplicate key error messages are found, returns the original error.
|
|
2834
|
+
*
|
|
2835
|
+
* @param {Error} error The error to transform
|
|
2836
|
+
* @returns {Error} The transformed error
|
|
2837
|
+
* @api private
|
|
2838
|
+
*/
|
|
2839
|
+
|
|
2840
|
+
Schema.prototype._transformDuplicateKeyError = function _transformDuplicateKeyError(error) {
|
|
2841
|
+
if (!this._duplicateKeyErrorMessagesByPath) {
|
|
2842
|
+
return error;
|
|
2843
|
+
}
|
|
2844
|
+
if (error.code !== 11000 && error.code !== 11001) {
|
|
2845
|
+
return error;
|
|
2846
|
+
}
|
|
2847
|
+
|
|
2848
|
+
if (error.keyPattern != null) {
|
|
2849
|
+
const keyPattern = error.keyPattern;
|
|
2850
|
+
const keys = Object.keys(keyPattern);
|
|
2851
|
+
if (keys.length !== 1) {
|
|
2852
|
+
return error;
|
|
2853
|
+
}
|
|
2854
|
+
const firstKey = keys[0];
|
|
2855
|
+
if (!this._duplicateKeyErrorMessagesByPath.hasOwnProperty(firstKey)) {
|
|
2856
|
+
return error;
|
|
2857
|
+
}
|
|
2858
|
+
return new MongooseError(this._duplicateKeyErrorMessagesByPath[firstKey], { cause: error });
|
|
2859
|
+
}
|
|
2860
|
+
|
|
2861
|
+
return error;
|
|
2862
|
+
};
|
|
2863
|
+
|
|
2813
2864
|
/*!
|
|
2814
2865
|
* ignore
|
|
2815
2866
|
*/
|
|
@@ -2859,6 +2910,8 @@ module.exports = exports = Schema;
|
|
|
2859
2910
|
* - [Mixed](https://mongoosejs.com/docs/schematypes.html#mixed)
|
|
2860
2911
|
* - [UUID](https://mongoosejs.com/docs/schematypes.html#uuid)
|
|
2861
2912
|
* - [BigInt](https://mongoosejs.com/docs/schematypes.html#bigint)
|
|
2913
|
+
* - [Double] (https://mongoosejs.com/docs/schematypes.html#double)
|
|
2914
|
+
* - [Int32](https://mongoosejs.com/docs/schematypes.html#int32)
|
|
2862
2915
|
*
|
|
2863
2916
|
* Using this exposed access to the `Mixed` SchemaType, we can use them in our schema.
|
|
2864
2917
|
*
|
package/lib/schemaType.js
CHANGED
|
@@ -74,7 +74,6 @@ function SchemaType(path, options, instance) {
|
|
|
74
74
|
this.options = new Options(options);
|
|
75
75
|
this._index = null;
|
|
76
76
|
|
|
77
|
-
|
|
78
77
|
if (utils.hasUserDefinedProperty(this.options, 'immutable')) {
|
|
79
78
|
this.$immutable = this.options.immutable;
|
|
80
79
|
|
|
@@ -447,21 +446,38 @@ SchemaType.prototype.index = function(options) {
|
|
|
447
446
|
*
|
|
448
447
|
* _NOTE: violating the constraint returns an `E11000` error from MongoDB when saving, not a Mongoose validation error._
|
|
449
448
|
*
|
|
450
|
-
*
|
|
449
|
+
* You can optionally specify an error message to replace MongoDB's default `E11000 duplicate key error` message.
|
|
450
|
+
* The following will throw a "Email must be unique" error if `save()`, `updateOne()`, `updateMany()`, `replaceOne()`,
|
|
451
|
+
* `findOneAndUpdate()`, or `findOneAndReplace()` throws a duplicate key error:
|
|
452
|
+
*
|
|
453
|
+
* ```javascript
|
|
454
|
+
* new Schema({
|
|
455
|
+
* email: {
|
|
456
|
+
* type: String,
|
|
457
|
+
* unique: [true, 'Email must be unique']
|
|
458
|
+
* }
|
|
459
|
+
* });
|
|
460
|
+
* ```
|
|
461
|
+
*
|
|
462
|
+
* Note that the above syntax does **not** work for `bulkWrite()` or `insertMany()`. `bulkWrite()` and `insertMany()`
|
|
463
|
+
* will still throw MongoDB's default `E11000 duplicate key error` message.
|
|
464
|
+
*
|
|
465
|
+
* @param {Boolean} value
|
|
466
|
+
* @param {String} [message]
|
|
451
467
|
* @return {SchemaType} this
|
|
452
468
|
* @api public
|
|
453
469
|
*/
|
|
454
470
|
|
|
455
|
-
SchemaType.prototype.unique = function(
|
|
471
|
+
SchemaType.prototype.unique = function unique(value, message) {
|
|
456
472
|
if (this._index === false) {
|
|
457
|
-
if (!
|
|
473
|
+
if (!value) {
|
|
458
474
|
return;
|
|
459
475
|
}
|
|
460
476
|
throw new Error('Path "' + this.path + '" may not have `index` set to ' +
|
|
461
477
|
'false and `unique` set to true');
|
|
462
478
|
}
|
|
463
479
|
|
|
464
|
-
if (!this.options.hasOwnProperty('index') &&
|
|
480
|
+
if (!this.options.hasOwnProperty('index') && value === false) {
|
|
465
481
|
return this;
|
|
466
482
|
}
|
|
467
483
|
|
|
@@ -471,7 +487,10 @@ SchemaType.prototype.unique = function(bool) {
|
|
|
471
487
|
this._index = { type: this._index };
|
|
472
488
|
}
|
|
473
489
|
|
|
474
|
-
this._index.unique =
|
|
490
|
+
this._index.unique = !!value;
|
|
491
|
+
if (typeof message === 'string') {
|
|
492
|
+
this._duplicateKeyErrorMessage = message;
|
|
493
|
+
}
|
|
475
494
|
return this;
|
|
476
495
|
};
|
|
477
496
|
|
|
@@ -1567,8 +1586,9 @@ SchemaType.prototype._castRef = function _castRef(value, doc, init) {
|
|
|
1567
1586
|
!doc.$__.populated[path].options ||
|
|
1568
1587
|
!doc.$__.populated[path].options.options ||
|
|
1569
1588
|
!doc.$__.populated[path].options.options.lean) {
|
|
1570
|
-
|
|
1571
|
-
ret
|
|
1589
|
+
const PopulatedModel = pop ? pop.options[populateModelSymbol] : doc.constructor.db.model(this.options.ref);
|
|
1590
|
+
ret = new PopulatedModel(value);
|
|
1591
|
+
ret.$__.wasPopulated = { value: ret._doc._id, options: { [populateModelSymbol]: PopulatedModel } };
|
|
1572
1592
|
}
|
|
1573
1593
|
|
|
1574
1594
|
return ret;
|
|
@@ -1743,6 +1763,14 @@ SchemaType.prototype.getEmbeddedSchemaType = function getEmbeddedSchemaType() {
|
|
|
1743
1763
|
return this.$embeddedSchemaType;
|
|
1744
1764
|
};
|
|
1745
1765
|
|
|
1766
|
+
/*!
|
|
1767
|
+
* If _duplicateKeyErrorMessage is a string, replace unique index errors "E11000 duplicate key error" with this string.
|
|
1768
|
+
*
|
|
1769
|
+
* @api private
|
|
1770
|
+
*/
|
|
1771
|
+
|
|
1772
|
+
SchemaType.prototype._duplicateKeyErrorMessage = null;
|
|
1773
|
+
|
|
1746
1774
|
/*!
|
|
1747
1775
|
* Module exports.
|
|
1748
1776
|
*/
|