mongoose 5.4.3 → 5.4.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.
package/History.md CHANGED
@@ -1,3 +1,10 @@
1
+ 5.4.4 / 2019-01-14
2
+ ==================
3
+ * fix(query): run casting on arrayFilters option #7079
4
+ * fix(document): support skipping timestamps on save() with `save({ timestamps: false })` #7357
5
+ * fix(model): apply custom where on `Document#remove()` so we attach the shardKey #7393
6
+ * docs(mongoose): document `mongoose.connections` #7338
7
+
1
8
  5.4.3 / 2019-01-09
2
9
  ==================
3
10
  * fix(populate): handle `count` option when using `Document#populate()` on a virtual #7380
package/lib/cast.js CHANGED
@@ -337,4 +337,4 @@ function _cast(val, numbertype, context) {
337
337
  }
338
338
  }
339
339
  }
340
- }
340
+ }
@@ -0,0 +1,54 @@
1
+ 'use strict';
2
+
3
+ module.exports = function castFilterPath(query, schematype, val) {
4
+ const any$conditionals = Object.keys(val).some(function(k) {
5
+ return k.charAt(0) === '$' && k !== '$id' && k !== '$ref';
6
+ });
7
+
8
+ if (!any$conditionals) {
9
+ return schematype.castForQueryWrapper({
10
+ val: val,
11
+ context: query
12
+ });
13
+ }
14
+
15
+ const ks = Object.keys(val);
16
+
17
+ let k = ks.length;
18
+
19
+ while (k--) {
20
+ const $cond = ks[k];
21
+ const nested = val[$cond];
22
+
23
+ if ($cond === '$not') {
24
+ if (nested && schematype && !schematype.caster) {
25
+ const _keys = Object.keys(nested);
26
+ if (_keys.length && _keys[0].charAt(0) === '$') {
27
+ for (const key in nested) {
28
+ nested[key] = schematype.castForQueryWrapper({
29
+ $conditional: key,
30
+ val: nested[key],
31
+ context: context
32
+ });
33
+ }
34
+ } else {
35
+ val[$cond] = schematype.castForQueryWrapper({
36
+ $conditional: $cond,
37
+ val: nested,
38
+ context: context
39
+ });
40
+ }
41
+ continue;
42
+ }
43
+ // cast(schematype.caster ? schematype.caster.schema : schema, nested, options, context);
44
+ } else {
45
+ val[$cond] = schematype.castForQueryWrapper({
46
+ $conditional: $cond,
47
+ val: nested,
48
+ context: context
49
+ });
50
+ }
51
+ }
52
+
53
+ return val;
54
+ };
@@ -0,0 +1,62 @@
1
+ 'use strict';
2
+
3
+ const castFilterPath = require('../query/castFilterPath');
4
+ const modifiedPaths = require('./modifiedPaths');
5
+
6
+ module.exports = function castArrayFilters(query) {
7
+ const arrayFilters = query.options.arrayFilters;
8
+ if (!Array.isArray(arrayFilters)) {
9
+ return;
10
+ }
11
+
12
+ const update = query.getUpdate();
13
+ const schema = query.schema;
14
+
15
+ const updatedPaths = modifiedPaths(update);
16
+
17
+ const updatedPathsByFilter = Object.keys(updatedPaths).reduce((cur, path) => {
18
+ const matches = path.match(/\$\[[^\]]+\]/g);
19
+ if (matches == null) {
20
+ return cur;
21
+ }
22
+ for (const match of matches) {
23
+ const firstMatch = path.indexOf(match);
24
+ if (firstMatch !== path.lastIndexOf(match)) {
25
+ throw new Error(`Path '${path}' contains the same array filter multiple times`);
26
+ }
27
+ cur[match.substring(2, match.length - 1)] = path.substr(0, firstMatch - 1);
28
+ }
29
+ return cur;
30
+ }, {});
31
+
32
+ for (const filter of arrayFilters) {
33
+ if (filter == null) {
34
+ throw new Error(`Got null array filter in ${arrayFilters}`);
35
+ }
36
+ const firstKey = Object.keys(filter)[0];
37
+
38
+ if (filter[firstKey] == null) {
39
+ continue;
40
+ }
41
+
42
+ const dot = firstKey.indexOf('.');
43
+ let filterPath = dot === -1 ?
44
+ updatedPathsByFilter[firstKey] + '.0' :
45
+ updatedPathsByFilter[firstKey.substr(0, dot)] + '.0' + firstKey.substr(dot);
46
+
47
+ if (filterPath == null) {
48
+ throw new Error(`Filter path not found for ${firstKey}`);
49
+ }
50
+
51
+ // If there are multiple array filters in the path being updated, make sure
52
+ // to replace them so we can get the schema path.
53
+ filterPath = filterPath.replace(/\$\[[^\]]+\]/g, '0');
54
+
55
+ const schematype = schema.path(filterPath);
56
+ if (typeof filter[firstKey] === 'object') {
57
+ filter[firstKey] = castFilterPath(query, schematype, filter[firstKey]);
58
+ } else {
59
+ filter[firstKey] = schematype.castForQuery(filter[firstKey]);
60
+ }
61
+ }
62
+ };
package/lib/index.js CHANGED
@@ -586,7 +586,7 @@ Mongoose.prototype.plugin = function(fn, opts) {
586
586
  };
587
587
 
588
588
  /**
589
- * The default connection of the mongoose module.
589
+ * The Mongoose module's default connection. Equivalent to `mongoose.connections][0]`, see [`connections`](#mongoose_Mongoose-connections).
590
590
  *
591
591
  * ####Example:
592
592
  *
@@ -596,10 +596,11 @@ Mongoose.prototype.plugin = function(fn, opts) {
596
596
  *
597
597
  * This is the connection used by default for every model created using [mongoose.model](#index_Mongoose-model).
598
598
  *
599
+ * To create a new connection, use [`createConnection()`](#mongoose_Mongoose-createConnection).
600
+ *
599
601
  * @memberOf Mongoose
600
602
  * @instance
601
- * @property connection
602
- * @return {Connection}
603
+ * @property {Connection} connection
603
604
  * @api public
604
605
  */
605
606
 
@@ -614,6 +615,29 @@ Mongoose.prototype.__defineSetter__('connection', function(v) {
614
615
  }
615
616
  });
616
617
 
618
+ /**
619
+ * An array containing all [connections](connections.html) associated with this
620
+ * Mongoose instance. By default, there is 1 connection. Calling
621
+ * [`createConnection()`](#mongoose_Mongoose-createConnection) adds a connection
622
+ * to this array.
623
+ *
624
+ * ####Example:
625
+ *
626
+ * const mongoose = require('mongoose');
627
+ * mongoose.connections.length; // 1, just the default connection
628
+ * mongoose.connections[0] === mongoose.connection; // true
629
+ *
630
+ * mongoose.createConnection('mongodb://localhost:27017/test');
631
+ * mongoose.connections.length; // 2
632
+ *
633
+ * @memberOf Mongoose
634
+ * @instance
635
+ * @property {Array} connections
636
+ * @api public
637
+ */
638
+
639
+ Mongoose.prototype.connections;
640
+
617
641
  /*!
618
642
  * Driver dependent APIs
619
643
  */
package/lib/model.js CHANGED
@@ -171,13 +171,12 @@ Model.prototype.baseModelName;
171
171
  * MyModel.events.on('error', err => console.log(err.message));
172
172
  *
173
173
  * // Prints a 'CastError' because of the above handler
174
- * await MyModel.findOne({ _id: 'notanid' }).catch({} => {});
174
+ * await MyModel.findOne({ _id: 'notanid' }).catch(noop);
175
175
  *
176
176
  * @api public
177
177
  * @fires error whenever any query or model function errors
178
- * @property events
179
178
  * @memberOf Model
180
- * @static
179
+ * @static events
181
180
  */
182
181
 
183
182
  Model.events;
@@ -193,15 +192,28 @@ Model.events;
193
192
 
194
193
  Model._middleware;
195
194
 
195
+ /*!
196
+ * ignore
197
+ */
198
+
199
+ function _applyCustomWhere(doc, where) {
200
+ if (doc.$where == null) {
201
+ return;
202
+ }
203
+
204
+ const keys = Object.keys(doc.$where);
205
+ const len = keys.length;
206
+ for (let i = 0; i < len; ++i) {
207
+ where[keys[i]] = doc.$where[keys[i]];
208
+ }
209
+ }
210
+
196
211
  /*!
197
212
  * ignore
198
213
  */
199
214
 
200
215
  Model.prototype.$__handleSave = function(options, callback) {
201
216
  const _this = this;
202
- let i;
203
- let keys;
204
- let len;
205
217
  let saveOptions = {};
206
218
 
207
219
  if ('safe' in options) {
@@ -285,13 +297,7 @@ Model.prototype.$__handleSave = function(options, callback) {
285
297
  return;
286
298
  }
287
299
 
288
- if (this.$where) {
289
- keys = Object.keys(this.$where);
290
- len = keys.length;
291
- for (i = 0; i < len; ++i) {
292
- where[keys[i]] = this.$where[keys[i]];
293
- }
294
- }
300
+ _applyCustomWhere(this, where);
295
301
 
296
302
  this[modelCollectionSymbol].updateOne(where, delta[1], saveOptions, function(err, ret) {
297
303
  if (err) {
@@ -420,6 +426,7 @@ function generateVersionError(doc, modifiedPaths) {
420
426
  * @param {Boolean} [options.j] set to true for MongoDB to wait until this `save()` has been [journaled before resolving the returned promise](https://docs.mongodb.com/manual/reference/write-concern/#j-option). Overrides the [schema-level `writeConcern` option](/docs/guide.html#writeConcern)
421
427
  * @param {Number} [options.wtimeout] sets a [timeout for the write concern](https://docs.mongodb.com/manual/reference/write-concern/#wtimeout). Overrides the [schema-level `writeConcern` option](/docs/guide.html#writeConcern).
422
428
  * @param {Boolean} [options.checkKeys=true] the MongoDB driver prevents you from saving keys that start with '$' or contain '.' by default. Set this option to `false` to skip that check. See [restrictions on field names](https://docs.mongodb.com/manual/reference/limits/#Restrictions-on-Field-Names)
429
+ * @param {Boolean} [options.timestamps=true] if `false` and [timestamps](./guide.html#timestamps) are enabled, skip timestamps for this `save()`.
423
430
  * @param {Function} [fn] optional callback
424
431
  * @return {Promise|undefined} Returns undefined if used with callback or a Promise otherwise.
425
432
  * @api public
@@ -458,8 +465,11 @@ Model.prototype.save = function(options, fn) {
458
465
  return cb(parallelSave);
459
466
  }
460
467
 
468
+ this.$__.saveOptions = options;
469
+
461
470
  this.$__save(options, error => {
462
471
  this.$__.saving = undefined;
472
+ delete this.$__.saveOptions;
463
473
 
464
474
  if (error) {
465
475
  this.$__handleReject(error);
@@ -915,6 +925,8 @@ Model.prototype.$__remove = function $__remove(options, cb) {
915
925
  return cb(where);
916
926
  }
917
927
 
928
+ _applyCustomWhere(this, where);
929
+
918
930
  this[modelCollectionSymbol].deleteOne(where, options, err => {
919
931
  if (!err) {
920
932
  this.$__.isDeleted = true;
@@ -16,6 +16,10 @@ module.exports = function shardingPlugin(schema) {
16
16
  applyWhere.call(this);
17
17
  next();
18
18
  });
19
+ schema.pre('remove', function(next) {
20
+ applyWhere.call(this);
21
+ next();
22
+ });
19
23
  schema.post('save', function() {
20
24
  storeShard.call(this);
21
25
  });
package/lib/query.js CHANGED
@@ -11,6 +11,7 @@ const QueryCursor = require('./cursor/QueryCursor');
11
11
  const ReadPreference = require('./driver').get().ReadPreference;
12
12
  const applyWriteConcern = require('./helpers/schema/applyWriteConcern');
13
13
  const cast = require('./cast');
14
+ const castArrayFilters = require('./helpers/update/castArrayFilters');
14
15
  const castUpdate = require('./helpers/query/castUpdate');
15
16
  const completeMany = require('./helpers/query/completeMany');
16
17
  const get = require('./helpers/get');
@@ -1728,6 +1729,18 @@ Query.prototype._castConditions = function() {
1728
1729
  }
1729
1730
  };
1730
1731
 
1732
+ /*!
1733
+ * ignore
1734
+ */
1735
+
1736
+ function _castArrayFilters(query) {
1737
+ try {
1738
+ castArrayFilters(query);
1739
+ } catch (err) {
1740
+ query.error(err);
1741
+ }
1742
+ }
1743
+
1731
1744
  /**
1732
1745
  * Thunk around find()
1733
1746
  *
@@ -3147,6 +3160,8 @@ Query.prototype._findAndModify = function(type, callback) {
3147
3160
  return callback(castedQuery);
3148
3161
  }
3149
3162
 
3163
+ _castArrayFilters(this);
3164
+
3150
3165
  const opts = this._optionsForExec(model);
3151
3166
 
3152
3167
  if ('strict' in opts) {
@@ -3385,6 +3400,8 @@ function _updateThunk(op, callback) {
3385
3400
 
3386
3401
  this._castConditions();
3387
3402
 
3403
+ _castArrayFilters(this);
3404
+
3388
3405
  if (this.error() != null) {
3389
3406
  callback(this.error());
3390
3407
  return null;
package/lib/schema.js CHANGED
@@ -918,6 +918,10 @@ Schema.prototype.setupTimestamp = function(timestamps) {
918
918
  this.add(schemaAdditions);
919
919
 
920
920
  this.pre('save', function(next) {
921
+ if (get(this, '$__.saveOptions.timestamps') === false) {
922
+ return next();
923
+ }
924
+
921
925
  const defaultTimestamp = (this.ownerDocument ? this.ownerDocument() : this).
922
926
  constructor.base.now();
923
927
  const auto_id = this._id && this._id.auto;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "5.4.3",
4
+ "version": "5.4.4",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",