mongoose 8.0.2 → 8.0.4

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.
Files changed (39) hide show
  1. package/dist/browser.umd.js +1 -1
  2. package/lib/cursor/changeStream.js +0 -12
  3. package/lib/document.js +19 -6
  4. package/lib/helpers/clone.js +1 -1
  5. package/lib/helpers/discriminator/applyEmbeddedDiscriminators.js +30 -0
  6. package/lib/helpers/document/applyDefaults.js +3 -1
  7. package/lib/helpers/indexes/getRelatedIndexes.js +5 -1
  8. package/lib/helpers/model/castBulkWrite.js +8 -6
  9. package/lib/helpers/populate/assignVals.js +5 -0
  10. package/lib/helpers/projection/hasIncludedChildren.js +1 -0
  11. package/lib/helpers/projection/isExclusive.js +2 -3
  12. package/lib/helpers/projection/isNestedProjection.js +8 -0
  13. package/lib/helpers/query/castUpdate.js +5 -1
  14. package/lib/model.js +3 -1
  15. package/lib/mongoose.js +3 -0
  16. package/lib/query.js +11 -36
  17. package/lib/queryHelpers.js +3 -2
  18. package/lib/schema/array.js +2 -2
  19. package/lib/schema/bigint.js +11 -4
  20. package/lib/schema/boolean.js +9 -4
  21. package/lib/schema/buffer.js +21 -12
  22. package/lib/schema/date.js +15 -8
  23. package/lib/schema/decimal128.js +7 -8
  24. package/lib/schema/documentArray.js +1 -7
  25. package/lib/schema/number.js +22 -13
  26. package/lib/schema/objectId.js +7 -7
  27. package/lib/schema/string.js +11 -3
  28. package/lib/schema/subdocument.js +3 -7
  29. package/lib/schema/uuid.js +12 -5
  30. package/lib/schema.js +11 -9
  31. package/lib/schemaType.js +8 -1
  32. package/lib/types/subdocument.js +3 -3
  33. package/lib/utils.js +0 -33
  34. package/package.json +8 -8
  35. package/types/document.d.ts +2 -2
  36. package/types/index.d.ts +3 -0
  37. package/types/inferschematype.d.ts +13 -12
  38. package/types/models.d.ts +21 -12
  39. package/types/query.d.ts +57 -39
@@ -60,12 +60,6 @@ class ChangeStream extends EventEmitter {
60
60
 
61
61
  driverChangeStreamEvents.forEach(ev => {
62
62
  this.driverChangeStream.on(ev, data => {
63
- // Sometimes Node driver still polls after close, so
64
- // avoid any uncaught exceptions due to closed change streams
65
- // See tests for gh-7022
66
- if (ev === 'error' && this.closed) {
67
- return;
68
- }
69
63
  if (data != null && data.fullDocument != null && this.options && this.options.hydrate) {
70
64
  data.fullDocument = this.options.model.hydrate(data.fullDocument);
71
65
  }
@@ -83,12 +77,6 @@ class ChangeStream extends EventEmitter {
83
77
 
84
78
  driverChangeStreamEvents.forEach(ev => {
85
79
  this.driverChangeStream.on(ev, data => {
86
- // Sometimes Node driver still polls after close, so
87
- // avoid any uncaught exceptions due to closed change streams
88
- // See tests for gh-7022
89
- if (ev === 'error' && this.closed) {
90
- return;
91
- }
92
80
  if (data != null && data.fullDocument != null && this.options && this.options.hydrate) {
93
81
  data.fullDocument = this.options.model.hydrate(data.fullDocument);
94
82
  }
package/lib/document.js CHANGED
@@ -1122,6 +1122,8 @@ Document.prototype.$set = function $set(path, val, type, options) {
1122
1122
  } else {
1123
1123
  throw new StrictModeError(key);
1124
1124
  }
1125
+ } else if (pathtype === 'nested' && valForKey == null) {
1126
+ this.$set(pathName, valForKey, constructing, options);
1125
1127
  }
1126
1128
  } else if (valForKey !== void 0) {
1127
1129
  this.$set(pathName, valForKey, constructing, options);
@@ -2229,12 +2231,15 @@ Document.prototype[documentModifiedPaths] = Document.prototype.modifiedPaths;
2229
2231
  * doc.isDirectModified('documents') // false
2230
2232
  *
2231
2233
  * @param {String} [path] optional
2234
+ * @param {Object} [options]
2235
+ * @param {Boolean} [options.ignoreAtomics=false] If true, doesn't return true if path is underneath an array that was modified with atomic operations like `push()`
2232
2236
  * @return {Boolean}
2233
2237
  * @api public
2234
2238
  */
2235
2239
 
2236
- Document.prototype.isModified = function(paths, modifiedPaths) {
2240
+ Document.prototype.isModified = function(paths, options, modifiedPaths) {
2237
2241
  if (paths) {
2242
+ const ignoreAtomics = options && options.ignoreAtomics;
2238
2243
  const directModifiedPathsObj = this.$__.activePaths.states.modify;
2239
2244
  if (directModifiedPathsObj == null) {
2240
2245
  return false;
@@ -2255,7 +2260,16 @@ Document.prototype.isModified = function(paths, modifiedPaths) {
2255
2260
  return !!~modified.indexOf(path);
2256
2261
  });
2257
2262
 
2258
- const directModifiedPaths = Object.keys(directModifiedPathsObj);
2263
+ let directModifiedPaths = Object.keys(directModifiedPathsObj);
2264
+ if (ignoreAtomics) {
2265
+ directModifiedPaths = directModifiedPaths.filter(path => {
2266
+ const value = this.$__getValue(path);
2267
+ if (value != null && value[arrayAtomicsSymbol] != null && value[arrayAtomicsSymbol].$set === undefined) {
2268
+ return false;
2269
+ }
2270
+ return true;
2271
+ });
2272
+ }
2259
2273
  return isModifiedChild || paths.some(function(path) {
2260
2274
  return directModifiedPaths.some(function(mod) {
2261
2275
  return mod === path || path.startsWith(mod + '.');
@@ -2677,7 +2691,7 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip) {
2677
2691
  paths.delete(fullPathToSubdoc + '.' + modifiedPath);
2678
2692
  }
2679
2693
 
2680
- if (doc.$isModified(fullPathToSubdoc, modifiedPaths) &&
2694
+ if (doc.$isModified(fullPathToSubdoc, null, modifiedPaths) &&
2681
2695
  !doc.isDirectModified(fullPathToSubdoc) &&
2682
2696
  !doc.$isDefault(fullPathToSubdoc)) {
2683
2697
  paths.add(fullPathToSubdoc);
@@ -3691,8 +3705,7 @@ Document.prototype.$toObject = function(options, json) {
3691
3705
  const schemaOptions = this.$__schema && this.$__schema.options || {};
3692
3706
  // merge base default options with Schema's set default options if available.
3693
3707
  // `clone` is necessary here because `utils.options` directly modifies the second input.
3694
- defaultOptions = utils.options(defaultOptions, clone(baseOptions));
3695
- defaultOptions = utils.options(defaultOptions, clone(schemaOptions[path] || {}));
3708
+ defaultOptions = { ...defaultOptions, ...baseOptions, ...schemaOptions[path] };
3696
3709
 
3697
3710
  // If options do not exist or is not an object, set it to empty object
3698
3711
  options = utils.isPOJO(options) ? { ...options } : {};
@@ -3754,7 +3767,7 @@ Document.prototype.$toObject = function(options, json) {
3754
3767
  }
3755
3768
 
3756
3769
  // merge default options with input options.
3757
- options = utils.options(defaultOptions, options);
3770
+ options = { ...defaultOptions, ...options };
3758
3771
  options._isNested = true;
3759
3772
  options.json = json;
3760
3773
  options.minimize = _minimize;
@@ -54,7 +54,7 @@ function clone(obj, options, isArrayChild) {
54
54
  ret = obj.toObject(options);
55
55
  }
56
56
 
57
- if (options && options.minimize && isSingleNested && Object.keys(ret).length === 0) {
57
+ if (options && options.minimize && !obj.constructor.$__required && isSingleNested && Object.keys(ret).length === 0) {
58
58
  return undefined;
59
59
  }
60
60
 
@@ -0,0 +1,30 @@
1
+ 'use strict';
2
+
3
+ module.exports = applyEmbeddedDiscriminators;
4
+
5
+ function applyEmbeddedDiscriminators(schema, seen = new WeakSet()) {
6
+ if (seen.has(schema)) {
7
+ return;
8
+ }
9
+ seen.add(schema);
10
+ for (const path of Object.keys(schema.paths)) {
11
+ const schemaType = schema.paths[path];
12
+ if (!schemaType.schema) {
13
+ continue;
14
+ }
15
+ applyEmbeddedDiscriminators(schemaType.schema, seen);
16
+ if (!schemaType.schema._applyDiscriminators) {
17
+ continue;
18
+ }
19
+ if (schemaType._appliedDiscriminators) {
20
+ continue;
21
+ }
22
+ for (const disc of schemaType.schema._applyDiscriminators.keys()) {
23
+ schemaType.discriminator(
24
+ disc,
25
+ schemaType.schema._applyDiscriminators.get(disc)
26
+ );
27
+ }
28
+ schemaType._appliedDiscriminators = true;
29
+ }
30
+ }
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ const isNestedProjection = require('../projection/isNestedProjection');
4
+
3
5
  module.exports = function applyDefaults(doc, fields, exclude, hasIncludedChildren, isBeforeSetters, pathsToSkip) {
4
6
  const paths = Object.keys(doc.$__schema.paths);
5
7
  const plen = paths.length;
@@ -32,7 +34,7 @@ module.exports = function applyDefaults(doc, fields, exclude, hasIncludedChildre
32
34
  }
33
35
  } else if (exclude === false && fields && !included) {
34
36
  const hasSubpaths = type.$isSingleNested || type.$isMongooseDocumentArray;
35
- if (curPath in fields || (j === len - 1 && hasSubpaths && hasIncludedChildren != null && hasIncludedChildren[curPath])) {
37
+ if ((curPath in fields && !isNestedProjection(fields[curPath])) || (j === len - 1 && hasSubpaths && hasIncludedChildren != null && hasIncludedChildren[curPath])) {
36
38
  included = true;
37
39
  } else if (hasIncludedChildren != null && !hasIncludedChildren[curPath]) {
38
40
  break;
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ const hasDollarKeys = require('../query/hasDollarKeys');
4
+
3
5
  function getRelatedSchemaIndexes(model, schemaIndexes) {
4
6
  return getRelatedIndexes({
5
7
  baseModelName: model.baseModelName,
@@ -46,7 +48,9 @@ function getRelatedIndexes({
46
48
 
47
49
  return indexes.filter(index => {
48
50
  const partialFilterExpression = getPartialFilterExpression(index, indexesType);
49
- return !partialFilterExpression || !partialFilterExpression[discriminatorKey];
51
+ return !partialFilterExpression
52
+ || !partialFilterExpression[discriminatorKey]
53
+ || (hasDollarKeys(partialFilterExpression[discriminatorKey]) && !('$eq' in partialFilterExpression[discriminatorKey]));
50
54
  });
51
55
  }
52
56
 
@@ -6,6 +6,7 @@ const applyTimestampsToChildren = require('../update/applyTimestampsToChildren')
6
6
  const applyTimestampsToUpdate = require('../update/applyTimestampsToUpdate');
7
7
  const cast = require('../../cast');
8
8
  const castUpdate = require('../query/castUpdate');
9
+ const clone = require('../clone');
9
10
  const decorateUpdateWithVersionKey = require('../update/decorateUpdateWithVersionKey');
10
11
  const { inspect } = require('util');
11
12
  const setDefaultsOnInsert = require('../setDefaultsOnInsert');
@@ -64,30 +65,32 @@ module.exports = function castBulkWrite(originalModel, op, options) {
64
65
  const schema = model.schema;
65
66
  const strict = options.strict != null ? options.strict : model.schema.options.strict;
66
67
 
68
+ const update = clone(op['updateOne']['update']);
69
+
67
70
  _addDiscriminatorToObject(schema, op['updateOne']['filter']);
68
71
 
69
72
  if (model.schema.$timestamps != null && op['updateOne'].timestamps !== false) {
70
73
  const createdAt = model.schema.$timestamps.createdAt;
71
74
  const updatedAt = model.schema.$timestamps.updatedAt;
72
- applyTimestampsToUpdate(now, createdAt, updatedAt, op['updateOne']['update'], {});
75
+ applyTimestampsToUpdate(now, createdAt, updatedAt, update, {});
73
76
  }
74
77
 
75
78
  if (op['updateOne'].timestamps !== false) {
76
- applyTimestampsToChildren(now, op['updateOne']['update'], model.schema);
79
+ applyTimestampsToChildren(now, update, model.schema);
77
80
  }
78
81
 
79
82
  const shouldSetDefaultsOnInsert = op['updateOne'].setDefaultsOnInsert == null ?
80
83
  globalSetDefaultsOnInsert :
81
84
  op['updateOne'].setDefaultsOnInsert;
82
85
  if (shouldSetDefaultsOnInsert !== false) {
83
- setDefaultsOnInsert(op['updateOne']['filter'], model.schema, op['updateOne']['update'], {
86
+ setDefaultsOnInsert(op['updateOne']['filter'], model.schema, update, {
84
87
  setDefaultsOnInsert: true,
85
88
  upsert: op['updateOne'].upsert
86
89
  });
87
90
  }
88
91
 
89
92
  decorateUpdateWithVersionKey(
90
- op['updateOne']['update'],
93
+ update,
91
94
  op['updateOne'],
92
95
  model.schema.options.versionKey
93
96
  );
@@ -96,8 +99,7 @@ module.exports = function castBulkWrite(originalModel, op, options) {
96
99
  strict: strict,
97
100
  upsert: op['updateOne'].upsert
98
101
  });
99
-
100
- op['updateOne']['update'] = castUpdate(model.schema, op['updateOne']['update'], {
102
+ op['updateOne']['update'] = castUpdate(model.schema, update, {
101
103
  strict: strict,
102
104
  upsert: op['updateOne'].upsert
103
105
  }, model, op['updateOne']['filter']);
@@ -39,8 +39,10 @@ module.exports = function assignVals(o) {
39
39
  const options = o.options;
40
40
  const count = o.count && o.isVirtual;
41
41
  let i;
42
+ let setValueIndex = 0;
42
43
 
43
44
  function setValue(val) {
45
+ ++setValueIndex;
44
46
  if (count) {
45
47
  return val;
46
48
  }
@@ -80,11 +82,14 @@ module.exports = function assignVals(o) {
80
82
  return valueFilter(val[0], options, populateOptions, _allIds);
81
83
  } else if (o.justOne === false && !Array.isArray(val)) {
82
84
  return valueFilter([val], options, populateOptions, _allIds);
85
+ } else if (o.justOne === true && !Array.isArray(val) && Array.isArray(_allIds)) {
86
+ return valueFilter(val, options, populateOptions, val == null ? val : _allIds[setValueIndex - 1]);
83
87
  }
84
88
  return valueFilter(val, options, populateOptions, _allIds);
85
89
  }
86
90
 
87
91
  for (i = 0; i < docs.length; ++i) {
92
+ setValueIndex = 0;
88
93
  const _path = o.path.endsWith('.$*') ? o.path.slice(0, -3) : o.path;
89
94
  const existingVal = mpath.get(_path, docs[i], lookupLocalFields);
90
95
  if (existingVal == null && !getVirtual(o.originalModel.schema, _path)) {
@@ -21,6 +21,7 @@ module.exports = function hasIncludedChildren(fields) {
21
21
  const keys = Object.keys(fields);
22
22
 
23
23
  for (const key of keys) {
24
+
24
25
  if (key.indexOf('.') === -1) {
25
26
  hasIncludedChildren[key] = 1;
26
27
  continue;
@@ -12,13 +12,12 @@ module.exports = function isExclusive(projection) {
12
12
  }
13
13
 
14
14
  const keys = Object.keys(projection);
15
- let ki = keys.length;
16
15
  let exclude = null;
17
16
 
18
- if (ki === 1 && keys[0] === '_id') {
17
+ if (keys.length === 1 && keys[0] === '_id') {
19
18
  exclude = !projection._id;
20
19
  } else {
21
- while (ki--) {
20
+ for (let ki = 0; ki < keys.length; ++ki) {
22
21
  // Does this projection explicitly define inclusion/exclusion?
23
22
  // Explicitly avoid `$meta` and `$slice`
24
23
  const key = keys[ki];
@@ -0,0 +1,8 @@
1
+ 'use strict';
2
+
3
+ module.exports = function isNestedProjection(val) {
4
+ if (val == null || typeof val !== 'object') {
5
+ return false;
6
+ }
7
+ return val.$slice == null && val.$elemMatch == null && val.$meta == null && val.$ == null;
8
+ };
@@ -13,6 +13,7 @@ const moveImmutableProperties = require('../update/moveImmutableProperties');
13
13
  const schemaMixedSymbol = require('../../schema/symbols').schemaMixedSymbol;
14
14
  const setDottedPath = require('../path/setDottedPath');
15
15
  const utils = require('../../utils');
16
+ const { internalToObjectOptions } = require('../../options');
16
17
 
17
18
  const mongodbUpdateOperators = new Set([
18
19
  '$currentDate',
@@ -99,7 +100,10 @@ module.exports = function castUpdate(schema, obj, options, context, filter) {
99
100
  const op = ops[i];
100
101
  val = ret[op];
101
102
  hasDollarKey = hasDollarKey || op.startsWith('$');
102
-
103
+ if (val != null && val.$__) {
104
+ val = val.toObject(internalToObjectOptions);
105
+ ret[op] = val;
106
+ }
103
107
  if (val &&
104
108
  typeof val === 'object' &&
105
109
  !Buffer.isBuffer(val) &&
package/lib/model.js CHANGED
@@ -4298,9 +4298,11 @@ function populate(model, docs, options, callback) {
4298
4298
  // _id back off before returning the result.
4299
4299
  if (typeof select === 'string') {
4300
4300
  select = select.replace(excludeIdRegGlobal, ' ');
4301
+ } else if (Array.isArray(select)) {
4302
+ select = select.filter(field => field !== '-_id');
4301
4303
  } else {
4302
4304
  // preserve original select conditions by copying
4303
- select = utils.object.shallowCopy(select);
4305
+ select = { ...select };
4304
4306
  delete select._id;
4305
4307
  }
4306
4308
  }
package/lib/mongoose.js CHANGED
@@ -30,6 +30,7 @@ const sanitizeFilter = require('./helpers/query/sanitizeFilter');
30
30
  const isBsonType = require('./helpers/isBsonType');
31
31
  const MongooseError = require('./error/mongooseError');
32
32
  const SetOptionError = require('./error/setOptionError');
33
+ const applyEmbeddedDiscriminators = require('./helpers/discriminator/applyEmbeddedDiscriminators');
33
34
 
34
35
  const defaultMongooseSymbol = Symbol.for('mongoose:default');
35
36
 
@@ -627,6 +628,8 @@ Mongoose.prototype._model = function(name, schema, collection, options) {
627
628
  }
628
629
  }
629
630
 
631
+ applyEmbeddedDiscriminators(schema);
632
+
630
633
  return model;
631
634
  };
632
635
 
package/lib/query.js CHANGED
@@ -2498,12 +2498,12 @@ Query.prototype._findOne = async function _findOne() {
2498
2498
  // don't pass in the conditions because we already merged them in
2499
2499
  const doc = await this.mongooseCollection.findOne(this._conditions, options);
2500
2500
  return new Promise((resolve, reject) => {
2501
- this._completeOne(doc, null, _wrapThunkCallback(this, (err, res) => {
2501
+ this._completeOne(doc, null, (err, res) => {
2502
2502
  if (err) {
2503
2503
  return reject(err);
2504
2504
  }
2505
2505
  resolve(res);
2506
- }));
2506
+ });
2507
2507
  });
2508
2508
  };
2509
2509
 
@@ -3303,12 +3303,12 @@ Query.prototype._findOneAndUpdate = async function _findOneAndUpdate() {
3303
3303
  const doc = !options.includeResultMetadata ? res : res.value;
3304
3304
 
3305
3305
  return new Promise((resolve, reject) => {
3306
- this._completeOne(doc, res, _wrapThunkCallback(this, (err, res) => {
3306
+ this._completeOne(doc, res, (err, res) => {
3307
3307
  if (err) {
3308
3308
  return reject(err);
3309
3309
  }
3310
3310
  resolve(res);
3311
- }));
3311
+ });
3312
3312
  });
3313
3313
  };
3314
3314
 
@@ -3399,12 +3399,12 @@ Query.prototype._findOneAndDelete = async function _findOneAndDelete() {
3399
3399
  const doc = !includeResultMetadata ? res : res.value;
3400
3400
 
3401
3401
  return new Promise((resolve, reject) => {
3402
- this._completeOne(doc, res, _wrapThunkCallback(this, (err, res) => {
3402
+ this._completeOne(doc, res, (err, res) => {
3403
3403
  if (err) {
3404
3404
  return reject(err);
3405
3405
  }
3406
3406
  resolve(res);
3407
- }));
3407
+ });
3408
3408
  });
3409
3409
  };
3410
3410
 
@@ -3553,12 +3553,12 @@ Query.prototype._findOneAndReplace = async function _findOneAndReplace() {
3553
3553
 
3554
3554
  const doc = !includeResultMetadata ? res : res.value;
3555
3555
  return new Promise((resolve, reject) => {
3556
- this._completeOne(doc, res, _wrapThunkCallback(this, (err, res) => {
3556
+ this._completeOne(doc, res, (err, res) => {
3557
3557
  if (err) {
3558
3558
  return reject(err);
3559
3559
  }
3560
3560
  resolve(res);
3561
- }));
3561
+ });
3562
3562
  });
3563
3563
  };
3564
3564
 
@@ -4382,28 +4382,6 @@ function _executePreHooks(query, op) {
4382
4382
  });
4383
4383
  }
4384
4384
 
4385
- /*!
4386
- * ignore
4387
- */
4388
-
4389
- function _wrapThunkCallback(query, cb) {
4390
- return function(error, res) {
4391
- if (error != null) {
4392
- return cb(error);
4393
- }
4394
-
4395
- for (const fn of query._transforms) {
4396
- try {
4397
- res = fn(res);
4398
- } catch (error) {
4399
- return cb(error);
4400
- }
4401
- }
4402
-
4403
- return cb(null, res);
4404
- };
4405
- }
4406
-
4407
4385
  /**
4408
4386
  * Executes the query returning a `Promise` which will be
4409
4387
  * resolved with either the doc(s) or rejected with the error.
@@ -4791,16 +4769,14 @@ Query.prototype._castFields = function _castFields(fields) {
4791
4769
  elemMatchKeys,
4792
4770
  keys,
4793
4771
  key,
4794
- out,
4795
- i;
4772
+ out;
4796
4773
 
4797
4774
  if (fields) {
4798
4775
  keys = Object.keys(fields);
4799
4776
  elemMatchKeys = [];
4800
- i = keys.length;
4801
4777
 
4802
4778
  // collect $elemMatch args
4803
- while (i--) {
4779
+ for (let i = 0; i < keys.length; ++i) {
4804
4780
  key = keys[i];
4805
4781
  if (fields[key].$elemMatch) {
4806
4782
  selected || (selected = {});
@@ -4819,8 +4795,7 @@ Query.prototype._castFields = function _castFields(fields) {
4819
4795
  }
4820
4796
 
4821
4797
  // apply the casted field args
4822
- i = elemMatchKeys.length;
4823
- while (i--) {
4798
+ for (let i = 0; i < elemMatchKeys.length; ++i) {
4824
4799
  key = elemMatchKeys[i];
4825
4800
  fields[key] = out[key];
4826
4801
  }
@@ -180,11 +180,12 @@ exports.applyPaths = function applyPaths(fields, schema) {
180
180
  if (!isDefiningProjection(field)) {
181
181
  continue;
182
182
  }
183
- // `_id: 1, name: 0` is a mixed inclusive/exclusive projection in
184
- // MongoDB 4.0 and earlier, but not in later versions.
185
183
  if (keys[keyIndex] === '_id' && keys.length > 1) {
186
184
  continue;
187
185
  }
186
+ if (keys[keyIndex] === schema.options.discriminatorKey && keys.length > 1 && field != null && !field) {
187
+ continue;
188
+ }
188
189
  exclude = !field;
189
190
  break;
190
191
  }
@@ -638,14 +638,14 @@ handle.$and = createLogicalQueryOperatorHandler('$and');
638
638
  handle.$nor = createLogicalQueryOperatorHandler('$nor');
639
639
 
640
640
  function createLogicalQueryOperatorHandler(op) {
641
- return function logicalQueryOperatorHandler(val) {
641
+ return function logicalQueryOperatorHandler(val, context) {
642
642
  if (!Array.isArray(val)) {
643
643
  throw new TypeError('conditional ' + op + ' requires an array');
644
644
  }
645
645
 
646
646
  const ret = [];
647
647
  for (const obj of val) {
648
- ret.push(cast(this.casterConstructor.schema, obj, null, this && this.$$context));
648
+ ret.push(cast(this.casterConstructor.schema ?? context.schema, obj, null, this && this.$$context));
649
649
  }
650
650
 
651
651
  return ret;
@@ -7,7 +7,6 @@
7
7
  const CastError = require('../error/cast');
8
8
  const SchemaType = require('../schemaType');
9
9
  const castBigInt = require('../cast/bigint');
10
- const utils = require('../utils');
11
10
 
12
11
  /**
13
12
  * BigInt SchemaType constructor.
@@ -177,12 +176,13 @@ SchemaBigInt.prototype.cast = function(value) {
177
176
  * ignore
178
177
  */
179
178
 
180
- SchemaBigInt.$conditionalHandlers = utils.options(SchemaType.prototype.$conditionalHandlers, {
179
+ SchemaBigInt.$conditionalHandlers = {
180
+ ...SchemaType.prototype.$conditionalHandlers,
181
181
  $gt: handleSingle,
182
182
  $gte: handleSingle,
183
183
  $lt: handleSingle,
184
184
  $lte: handleSingle
185
- });
185
+ };
186
186
 
187
187
  /*!
188
188
  * ignore
@@ -212,7 +212,14 @@ SchemaBigInt.prototype.castForQuery = function($conditional, val, context) {
212
212
  return this.applySetters(null, val, context);
213
213
  }
214
214
 
215
- return this.applySetters(val, context);
215
+ try {
216
+ return this.applySetters(val, context);
217
+ } catch (err) {
218
+ if (err instanceof CastError && err.path === this.path && this.$fullPath != null) {
219
+ err.path = this.$fullPath;
220
+ }
221
+ throw err;
222
+ }
216
223
  };
217
224
 
218
225
  /**
@@ -7,7 +7,6 @@
7
7
  const CastError = require('../error/cast');
8
8
  const SchemaType = require('../schemaType');
9
9
  const castBoolean = require('../cast/boolean');
10
- const utils = require('../utils');
11
10
 
12
11
  /**
13
12
  * Boolean SchemaType constructor.
@@ -235,8 +234,7 @@ SchemaBoolean.prototype.cast = function(value) {
235
234
  }
236
235
  };
237
236
 
238
- SchemaBoolean.$conditionalHandlers =
239
- utils.options(SchemaType.prototype.$conditionalHandlers, {});
237
+ SchemaBoolean.$conditionalHandlers = { ...SchemaType.prototype.$conditionalHandlers };
240
238
 
241
239
  /**
242
240
  * Casts contents for queries.
@@ -258,7 +256,14 @@ SchemaBoolean.prototype.castForQuery = function($conditional, val, context) {
258
256
  return this.applySetters(null, val, context);
259
257
  }
260
258
 
261
- return this.applySetters(val, context);
259
+ try {
260
+ return this.applySetters(val, context);
261
+ } catch (err) {
262
+ if (err instanceof CastError && err.path === this.path && this.$fullPath != null) {
263
+ err.path = this.$fullPath;
264
+ }
265
+ throw err;
266
+ }
262
267
  };
263
268
 
264
269
  /**
@@ -250,17 +250,17 @@ function handleSingle(val, context) {
250
250
  return this.castForQuery(null, val, context);
251
251
  }
252
252
 
253
- SchemaBuffer.prototype.$conditionalHandlers =
254
- utils.options(SchemaType.prototype.$conditionalHandlers, {
255
- $bitsAllClear: handleBitwiseOperator,
256
- $bitsAnyClear: handleBitwiseOperator,
257
- $bitsAllSet: handleBitwiseOperator,
258
- $bitsAnySet: handleBitwiseOperator,
259
- $gt: handleSingle,
260
- $gte: handleSingle,
261
- $lt: handleSingle,
262
- $lte: handleSingle
263
- });
253
+ SchemaBuffer.prototype.$conditionalHandlers = {
254
+ ...SchemaType.prototype.$conditionalHandlers,
255
+ $bitsAllClear: handleBitwiseOperator,
256
+ $bitsAnyClear: handleBitwiseOperator,
257
+ $bitsAllSet: handleBitwiseOperator,
258
+ $bitsAnySet: handleBitwiseOperator,
259
+ $gt: handleSingle,
260
+ $gte: handleSingle,
261
+ $lt: handleSingle,
262
+ $lte: handleSingle
263
+ };
264
264
 
265
265
  /**
266
266
  * Casts contents for queries.
@@ -279,7 +279,16 @@ SchemaBuffer.prototype.castForQuery = function($conditional, val, context) {
279
279
  }
280
280
  return handler.call(this, val);
281
281
  }
282
- const casted = this.applySetters(val, context);
282
+
283
+ let casted;
284
+ try {
285
+ casted = this.applySetters(val, context);
286
+ } catch (err) {
287
+ if (err instanceof CastError && err.path === this.path && this.$fullPath != null) {
288
+ err.path = this.$fullPath;
289
+ }
290
+ throw err;
291
+ }
283
292
  return casted ? casted.toObject({ transform: false, virtuals: false }) : casted;
284
293
  };
285
294
 
@@ -388,13 +388,13 @@ function handleSingle(val) {
388
388
  return this.cast(val);
389
389
  }
390
390
 
391
- SchemaDate.prototype.$conditionalHandlers =
392
- utils.options(SchemaType.prototype.$conditionalHandlers, {
393
- $gt: handleSingle,
394
- $gte: handleSingle,
395
- $lt: handleSingle,
396
- $lte: handleSingle
397
- });
391
+ SchemaDate.prototype.$conditionalHandlers = {
392
+ ...SchemaType.prototype.$conditionalHandlers,
393
+ $gt: handleSingle,
394
+ $gte: handleSingle,
395
+ $lt: handleSingle,
396
+ $lte: handleSingle
397
+ };
398
398
 
399
399
 
400
400
  /**
@@ -407,7 +407,14 @@ SchemaDate.prototype.$conditionalHandlers =
407
407
 
408
408
  SchemaDate.prototype.castForQuery = function($conditional, val, context) {
409
409
  if ($conditional == null) {
410
- return this.applySetters(val, context);
410
+ try {
411
+ return this.applySetters(val, context);
412
+ } catch (err) {
413
+ if (err instanceof CastError && err.path === this.path && this.$fullPath != null) {
414
+ err.path = this.$fullPath;
415
+ }
416
+ throw err;
417
+ }
411
418
  }
412
419
 
413
420
  const handler = this.$conditionalHandlers[$conditional];