mongoose 5.13.2 → 5.13.6

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.
@@ -188,13 +188,7 @@ function getOwnPropertyDescriptors(object) {
188
188
  const result = {};
189
189
 
190
190
  Object.getOwnPropertyNames(object).forEach(function(key) {
191
- result[key] = Object.getOwnPropertyDescriptor(object, key);
192
- // Assume these are schema paths, ignore them re: #5470
193
- if (result[key].get) {
194
- delete result[key];
195
- return;
196
- }
197
- result[key].enumerable = [
191
+ const skip = [
198
192
  'isNew',
199
193
  '$__',
200
194
  'errors',
@@ -205,6 +199,12 @@ function getOwnPropertyDescriptors(object) {
205
199
  '__index',
206
200
  '$isDocumentArrayElement'
207
201
  ].indexOf(key) === -1;
202
+ if (skip) {
203
+ return;
204
+ }
205
+
206
+ result[key] = Object.getOwnPropertyDescriptor(object, key);
207
+ result[key].enumerable = false;
208
208
  });
209
209
 
210
210
  return result;
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ /*!
4
+ * If `val` is an object, returns constructor name, if possible. Otherwise returns undefined.
5
+ */
6
+
7
+ module.exports = function getConstructorName(val) {
8
+ if (val == null) {
9
+ return void 0;
10
+ }
11
+ if (typeof val.constructor !== 'function') {
12
+ return void 0;
13
+ }
14
+ return val.constructor.name;
15
+ };
@@ -5,6 +5,7 @@ const SkipPopulateValue = require('./SkipPopulateValue');
5
5
  const get = require('../get');
6
6
  const getDiscriminatorByValue = require('../discriminator/getDiscriminatorByValue');
7
7
  const isPathExcluded = require('../projection/isPathExcluded');
8
+ const getConstructorName = require('../getConstructorName');
8
9
  const getSchemaTypes = require('./getSchemaTypes');
9
10
  const getVirtual = require('./getVirtual');
10
11
  const lookupLocalFields = require('./lookupLocalFields');
@@ -520,8 +521,7 @@ function convertTo_id(val, schema) {
520
521
 
521
522
  // `populate('map')` may be an object if populating on a doc that hasn't
522
523
  // been hydrated yet
523
- if (val != null &&
524
- val.constructor.name === 'Object' &&
524
+ if (getConstructorName(val) === 'Object' &&
525
525
  // The intent here is we should only flatten the object if we expect
526
526
  // to get a Map in the end. Avoid doing this for mixed types.
527
527
  (schema == null || schema[schemaMixedSymbol] == null)) {
@@ -6,6 +6,7 @@ const StrictModeError = require('../../error/strict');
6
6
  const ValidationError = require('../../error/validation');
7
7
  const castNumber = require('../../cast/number');
8
8
  const cast = require('../../cast');
9
+ const getConstructorName = require('../getConstructorName');
9
10
  const getEmbeddedDiscriminatorPath = require('./getEmbeddedDiscriminatorPath');
10
11
  const handleImmutable = require('./handleImmutable');
11
12
  const moveImmutableProperties = require('../update/moveImmutableProperties');
@@ -200,7 +201,7 @@ function walkUpdatePath(schema, obj, op, options, context, filter, pref) {
200
201
  }
201
202
  }
202
203
 
203
- if (val && val.constructor.name === 'Object') {
204
+ if (getConstructorName(val) === 'Object') {
204
205
  // watch for embedded doc schemas
205
206
  schematype = schema._getSchema(prefix + key);
206
207
 
@@ -1,8 +1,9 @@
1
1
  'use strict';
2
2
 
3
+ const getConstructorName = require('../getConstructorName');
4
+
3
5
  module.exports = function allServersUnknown(topologyDescription) {
4
- if (topologyDescription == null ||
5
- topologyDescription.constructor.name !== 'TopologyDescription') {
6
+ if (getConstructorName(topologyDescription) !== 'TopologyDescription') {
6
7
  return false;
7
8
  }
8
9
 
@@ -1,8 +1,9 @@
1
1
  'use strict';
2
2
 
3
+ const getConstructorName = require('../getConstructorName');
4
+
3
5
  module.exports = function isAtlas(topologyDescription) {
4
- if (topologyDescription == null ||
5
- topologyDescription.constructor.name !== 'TopologyDescription') {
6
+ if (getConstructorName(topologyDescription) !== 'TopologyDescription') {
6
7
  return false;
7
8
  }
8
9
 
@@ -1,11 +1,12 @@
1
1
  'use strict';
2
2
 
3
+ const getConstructorName = require('../getConstructorName');
4
+
3
5
  const nonSSLMessage = 'Client network socket disconnected before secure TLS ' +
4
6
  'connection was established';
5
7
 
6
8
  module.exports = function isSSLError(topologyDescription) {
7
- if (topologyDescription == null ||
8
- topologyDescription.constructor.name !== 'TopologyDescription') {
9
+ if (getConstructorName(topologyDescription) !== 'TopologyDescription') {
9
10
  return false;
10
11
  }
11
12
 
@@ -19,34 +19,10 @@ function applyTimestampsToChildren(now, update, schema) {
19
19
 
20
20
  if (hasDollarKey) {
21
21
  if (update.$push) {
22
- for (const key of Object.keys(update.$push)) {
23
- const $path = schema.path(key);
24
- if (update.$push[key] &&
25
- $path &&
26
- $path.$isMongooseDocumentArray &&
27
- $path.schema.options.timestamps) {
28
- const timestamps = $path.schema.options.timestamps;
29
- const createdAt = handleTimestampOption(timestamps, 'createdAt');
30
- const updatedAt = handleTimestampOption(timestamps, 'updatedAt');
31
- if (update.$push[key].$each) {
32
- update.$push[key].$each.forEach(function(subdoc) {
33
- if (updatedAt != null) {
34
- subdoc[updatedAt] = now;
35
- }
36
- if (createdAt != null) {
37
- subdoc[createdAt] = now;
38
- }
39
- });
40
- } else {
41
- if (updatedAt != null) {
42
- update.$push[key][updatedAt] = now;
43
- }
44
- if (createdAt != null) {
45
- update.$push[key][createdAt] = now;
46
- }
47
- }
48
- }
49
- }
22
+ _applyTimestampToUpdateOperator(update.$push);
23
+ }
24
+ if (update.$addToSet) {
25
+ _applyTimestampToUpdateOperator(update.$addToSet);
50
26
  }
51
27
  if (update.$set != null) {
52
28
  const keys = Object.keys(update.$set);
@@ -54,12 +30,49 @@ function applyTimestampsToChildren(now, update, schema) {
54
30
  applyTimestampsToUpdateKey(schema, key, update.$set, now);
55
31
  }
56
32
  }
33
+ if (update.$setOnInsert != null) {
34
+ const keys = Object.keys(update.$setOnInsert);
35
+ for (const key of keys) {
36
+ applyTimestampsToUpdateKey(schema, key, update.$setOnInsert, now);
37
+ }
38
+ }
57
39
  }
58
40
 
59
41
  const updateKeys = Object.keys(update).filter(key => !key.startsWith('$'));
60
42
  for (const key of updateKeys) {
61
43
  applyTimestampsToUpdateKey(schema, key, update, now);
62
44
  }
45
+
46
+ function _applyTimestampToUpdateOperator(op) {
47
+ for (const key of Object.keys(op)) {
48
+ const $path = schema.path(key.replace(/\.\$\./i, '.').replace(/.\$$/, ''));
49
+ if (op[key] &&
50
+ $path &&
51
+ $path.$isMongooseDocumentArray &&
52
+ $path.schema.options.timestamps) {
53
+ const timestamps = $path.schema.options.timestamps;
54
+ const createdAt = handleTimestampOption(timestamps, 'createdAt');
55
+ const updatedAt = handleTimestampOption(timestamps, 'updatedAt');
56
+ if (op[key].$each) {
57
+ op[key].$each.forEach(function(subdoc) {
58
+ if (updatedAt != null) {
59
+ subdoc[updatedAt] = now;
60
+ }
61
+ if (createdAt != null) {
62
+ subdoc[createdAt] = now;
63
+ }
64
+ });
65
+ } else {
66
+ if (updatedAt != null) {
67
+ op[key][updatedAt] = now;
68
+ }
69
+ if (createdAt != null) {
70
+ op[key][createdAt] = now;
71
+ }
72
+ }
73
+ }
74
+ }
75
+ }
63
76
  }
64
77
 
65
78
  function applyTimestampsToDocumentArray(arr, schematype, now) {
package/lib/index.js CHANGED
@@ -317,7 +317,7 @@ Mongoose.prototype.createConnection = function(uri, options, callback) {
317
317
  * @param {String} uri(s)
318
318
  * @param {Object} [options] passed down to the [MongoDB driver's `connect()` function](http://mongodb.github.io/node-mongodb-native/3.0/api/MongoClient.html), except for 4 mongoose-specific options explained below.
319
319
  * @param {Boolean} [options.bufferCommands=true] Mongoose specific option. Set to false to [disable buffering](http://mongoosejs.com/docs/faq.html#callback_never_executes) on all models associated with this connection.
320
- * @param {Number} [options.bufferTimeoutMS=true] Mongoose specific option. If `bufferCommands` is true, Mongoose will throw an error after `bufferTimeoutMS` if the operation is still buffered.
320
+ * @param {Number} [options.bufferTimeoutMS=10000] Mongoose specific option. If `bufferCommands` is true, Mongoose will throw an error after `bufferTimeoutMS` if the operation is still buffered.
321
321
  * @param {String} [options.dbName] The name of the database we want to use. If not provided, use database name from connection string.
322
322
  * @param {String} [options.user] username for authentication, equivalent to `options.auth.user`. Maintained for backwards compatibility.
323
323
  * @param {String} [options.pass] password for authentication, equivalent to `options.auth.password`. Maintained for backwards compatibility.
package/lib/model.js CHANGED
@@ -35,6 +35,7 @@ const getDefaultBulkwriteResult = require('./helpers/getDefaultBulkwriteResult')
35
35
  const discriminator = require('./helpers/model/discriminator');
36
36
  const each = require('./helpers/each');
37
37
  const get = require('./helpers/get');
38
+ const getConstructorName = require('./helpers/getConstructorName');
38
39
  const getDiscriminatorByValue = require('./helpers/discriminator/getDiscriminatorByValue');
39
40
  const getModelsMapForPopulate = require('./helpers/populate/getModelsMapForPopulate');
40
41
  const immediate = require('./helpers/immediate');
@@ -3113,8 +3114,7 @@ Model.create = function create(doc, options, callback) {
3113
3114
  args[0] != null &&
3114
3115
  args[1] != null &&
3115
3116
  args[0].session == null &&
3116
- last.session != null &&
3117
- last.session.constructor.name === 'ClientSession' &&
3117
+ getConstructorName(last.session) === 'ClientSession' &&
3118
3118
  !this.schema.path('session')) {
3119
3119
  // Probably means the user is running into the common mistake of trying
3120
3120
  // to use a spread to specify options, see gh-7535
@@ -3728,25 +3728,34 @@ Model.buildBulkWriteOperations = function buildBulkWriteOperations(documents, op
3728
3728
  }
3729
3729
  }
3730
3730
 
3731
+ const isANewDocument = document.isNew;
3732
+ if (isANewDocument) {
3733
+ accumulator.push({
3734
+ insertOne: { document }
3735
+ });
3736
+
3737
+ return accumulator;
3738
+ }
3739
+
3731
3740
  const delta = document.$__delta();
3732
- const where = document.$__where(delta[0]);
3733
- const changes = delta[1];
3741
+ const isDocumentWithChanges = delta != null && !utils.isEmptyObject(delta[0]);
3734
3742
 
3735
- _applyCustomWhere(document, where);
3743
+ if (isDocumentWithChanges) {
3744
+ const where = document.$__where(delta[0]);
3745
+ const changes = delta[1];
3736
3746
 
3737
- document.$__version(where, delta);
3747
+ _applyCustomWhere(document, where);
3748
+
3749
+ document.$__version(where, delta);
3738
3750
 
3739
- if (document.isNew) {
3740
- accumulator.push({
3741
- insertOne: { document }
3742
- });
3743
- } else if (!utils.isEmptyObject(changes)) {
3744
3751
  accumulator.push({
3745
3752
  updateOne: {
3746
3753
  filter: where,
3747
3754
  update: changes
3748
3755
  }
3749
3756
  });
3757
+
3758
+ return accumulator;
3750
3759
  }
3751
3760
 
3752
3761
  return accumulator;
package/lib/query.js CHANGED
@@ -5128,7 +5128,7 @@ Query.prototype.maxscan = Query.base.maxScan;
5128
5128
  Query.prototype.tailable = function(val, opts) {
5129
5129
  // we need to support the tailable({ awaitdata : true }) as well as the
5130
5130
  // tailable(true, {awaitdata :true}) syntax that mquery does not support
5131
- if (val && val.constructor.name === 'Object') {
5131
+ if (val != null && typeof val.constructor === 'function' && val.constructor.name === 'Object') {
5132
5132
  opts = val;
5133
5133
  val = true;
5134
5134
  }
@@ -5485,11 +5485,11 @@ Query.prototype.center = Query.base.circle;
5485
5485
  */
5486
5486
 
5487
5487
  Query.prototype.centerSphere = function() {
5488
- if (arguments[0] && arguments[0].constructor.name === 'Object') {
5488
+ if (arguments[0] != null && typeof arguments[0].constructor === 'function' && arguments[0].constructor.name === 'Object') {
5489
5489
  arguments[0].spherical = true;
5490
5490
  }
5491
5491
 
5492
- if (arguments[1] && arguments[1].constructor.name === 'Object') {
5492
+ if (arguments[1] != null && typeof arguments[1].constructor === 'function' && arguments[1].constructor.name === 'Object') {
5493
5493
  arguments[1].spherical = true;
5494
5494
  }
5495
5495
 
@@ -451,7 +451,7 @@ SchemaArray.prototype._castForPopulate = function _castForPopulate(value, doc) {
451
451
  */
452
452
 
453
453
  SchemaArray.prototype.discriminator = function(name, schema) {
454
- let arr = this; // eslint-disable-line consistent-this
454
+ let arr = this;
455
455
  while (arr.$isMongooseArray && !arr.$isMongooseDocumentArray) {
456
456
  arr = arr.casterConstructor;
457
457
  if (arr == null || typeof arr === 'function') {
@@ -8,6 +8,7 @@ const MongooseError = require('../error/index');
8
8
  const SchemaDateOptions = require('../options/SchemaDateOptions');
9
9
  const SchemaType = require('../schematype');
10
10
  const castDate = require('../cast/date');
11
+ const getConstructorName = require('../helpers/getConstructorName');
11
12
  const utils = require('../utils');
12
13
 
13
14
  const CastError = SchemaType.CastError;
@@ -147,7 +148,7 @@ SchemaDate._defaultCaster = v => {
147
148
  */
148
149
 
149
150
  SchemaDate.prototype.expires = function(when) {
150
- if (!this._index || this._index.constructor.name !== 'Object') {
151
+ if (getConstructorName(this._index) !== 'Object') {
151
152
  this._index = {};
152
153
  }
153
154
 
@@ -7,6 +7,7 @@
7
7
  const SchemaObjectIdOptions = require('../options/SchemaObjectIdOptions');
8
8
  const SchemaType = require('../schematype');
9
9
  const castObjectId = require('../cast/objectid');
10
+ const getConstructorName = require('../helpers/getConstructorName');
10
11
  const oid = require('../types/objectid');
11
12
  const utils = require('../utils');
12
13
 
@@ -225,7 +226,7 @@ ObjectId.prototype.cast = function(value, doc, init) {
225
226
  // wait! we may need to cast this to a document
226
227
  if (value instanceof oid) {
227
228
  return value;
228
- } else if (value != null && (value.constructor.name || '').toLowerCase() === 'objectid') {
229
+ } else if ((getConstructorName(value) || '').toLowerCase() === 'objectid') {
229
230
  return new oid(value.toHexString());
230
231
  }
231
232
 
package/lib/schema.js CHANGED
@@ -14,6 +14,7 @@ const VirtualType = require('./virtualtype');
14
14
  const addAutoId = require('./helpers/schema/addAutoId');
15
15
  const arrayParentSymbol = require('./helpers/symbols').arrayParentSymbol;
16
16
  const get = require('./helpers/get');
17
+ const getConstructorName = require('./helpers/getConstructorName');
17
18
  const getIndexes = require('./helpers/schema/getIndexes');
18
19
  const merge = require('./helpers/schema/merge');
19
20
  const mpath = require('mpath');
@@ -932,11 +933,21 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
932
933
  : type[0];
933
934
 
934
935
  if (cast && cast.instanceOfSchema) {
936
+ if (!(cast instanceof Schema)) {
937
+ throw new TypeError('Schema for array path `' + path +
938
+ '` is from a different copy of the Mongoose module. Please make sure you\'re using the same version ' +
939
+ 'of Mongoose everywhere with `npm list mongoose`.');
940
+ }
935
941
  return new MongooseTypes.DocumentArray(path, cast, obj);
936
942
  }
937
943
  if (cast &&
938
944
  cast[options.typeKey] &&
939
945
  cast[options.typeKey].instanceOfSchema) {
946
+ if (!(cast[options.typeKey] instanceof Schema)) {
947
+ throw new TypeError('Schema for array path `' + path +
948
+ '` is from a different copy of the Mongoose module. Please make sure you\'re using the same version ' +
949
+ 'of Mongoose everywhere with `npm list mongoose`.');
950
+ }
940
951
  return new MongooseTypes.DocumentArray(path, cast[options.typeKey], obj, cast);
941
952
  }
942
953
 
@@ -1665,8 +1676,8 @@ Object.defineProperty(Schema, 'indexTypes', {
1665
1676
  });
1666
1677
 
1667
1678
  /**
1668
- * Returns a list of indexes that this schema declares, via `schema.index()`
1669
- * or by `index: true` in a path's options.
1679
+ * Returns a list of indexes that this schema declares, via `schema.index()` or by `index: true` in a path's options.
1680
+ * Indexes are expressed as an array `[spec, options]`.
1670
1681
  *
1671
1682
  * ####Example:
1672
1683
  *
@@ -1679,6 +1690,17 @@ Object.defineProperty(Schema, 'indexTypes', {
1679
1690
  * // [ { registeredAt: 1 }, { background: true } ] ]
1680
1691
  * userSchema.indexes();
1681
1692
  *
1693
+ * [Plugins](/docs/plugins.html) can use the return value of this function to modify a schema's indexes.
1694
+ * For example, the below plugin makes every index unique by default.
1695
+ *
1696
+ * function myPlugin(schema) {
1697
+ * for (const index of schema.indexes()) {
1698
+ * if (index[1].unique === undefined) {
1699
+ * index[1].unique = true;
1700
+ * }
1701
+ * }
1702
+ * }
1703
+ *
1682
1704
  * @api public
1683
1705
  * @return {Array} list of indexes defined in the schema
1684
1706
  */
@@ -1702,7 +1724,7 @@ Schema.prototype.indexes = function() {
1702
1724
  */
1703
1725
 
1704
1726
  Schema.prototype.virtual = function(name, options) {
1705
- if (name instanceof VirtualType || (name != null && name.constructor.name === 'VirtualType')) {
1727
+ if (name instanceof VirtualType || getConstructorName(name) === 'VirtualType') {
1706
1728
  return this.virtual(name.path, name.options);
1707
1729
  }
1708
1730
 
@@ -1937,7 +1959,9 @@ Schema.prototype.loadClass = function(model, virtualsOnly) {
1937
1959
  return;
1938
1960
  }
1939
1961
  const prop = Object.getOwnPropertyDescriptor(model, name);
1940
- this.static(name, prop.value);
1962
+ if (prop.hasOwnProperty('value')) {
1963
+ this.static(name, prop.value);
1964
+ }
1941
1965
  }, this);
1942
1966
  }
1943
1967
 
@@ -2034,7 +2058,7 @@ Schema.prototype._getSchema = function(path) {
2034
2058
  }
2035
2059
  } else if (foundschema.$isSchemaMap) {
2036
2060
  if (p + 1 >= parts.length) {
2037
- return foundschema.$__schemaType;
2061
+ return foundschema;
2038
2062
  }
2039
2063
  const ret = search(parts.slice(p + 1), foundschema.$__schemaType.schema);
2040
2064
  return ret;
@@ -397,7 +397,7 @@ EmbeddedDocument.prototype.ownerDocument = function() {
397
397
 
398
398
  EmbeddedDocument.prototype.$__fullPath = function(path) {
399
399
  if (!this.$__.fullPath) {
400
- let parent = this; // eslint-disable-line consistent-this
400
+ let parent = this;
401
401
  if (!parent[documentArrayParent]) {
402
402
  return path;
403
403
  }
package/lib/types/map.js CHANGED
@@ -2,8 +2,10 @@
2
2
 
3
3
  const Mixed = require('../schema/mixed');
4
4
  const ObjectId = require('./objectid');
5
+ const clone = require('../helpers/clone');
5
6
  const deepEqual = require('../utils').deepEqual;
6
7
  const get = require('../helpers/get');
8
+ const getConstructorName = require('../helpers/getConstructorName');
7
9
  const handleSpreadDoc = require('../helpers/document/handleSpreadDoc');
8
10
  const util = require('util');
9
11
  const specialProperties = require('../helpers/specialProperties');
@@ -16,7 +18,7 @@ const populateModelSymbol = require('../helpers/symbols').populateModelSymbol;
16
18
 
17
19
  class MongooseMap extends Map {
18
20
  constructor(v, path, doc, schemaType) {
19
- if (v != null && v.constructor.name === 'Object') {
21
+ if (getConstructorName(v) === 'Object') {
20
22
  v = Object.keys(v).reduce((arr, key) => arr.concat([[key, v[key]]]), []);
21
23
  }
22
24
  super(v);
@@ -133,7 +135,7 @@ class MongooseMap extends Map {
133
135
  const ret = {};
134
136
  const keys = this.keys();
135
137
  for (const key of keys) {
136
- ret[key] = this.get(key);
138
+ ret[key] = clone(this.get(key));
137
139
  }
138
140
  return ret;
139
141
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "5.13.2",
4
+ "version": "5.13.6",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -20,14 +20,14 @@
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
22
  "@types/mongodb": "^3.5.27",
23
- "@types/node": "14.x || 15.x",
24
23
  "bson": "^1.1.4",
25
24
  "kareem": "2.3.2",
26
- "mongodb": "3.6.8",
25
+ "mongodb": "3.6.11",
27
26
  "mongoose-legacy-pluralize": "1.0.2",
28
27
  "mpath": "0.8.3",
29
28
  "mquery": "3.2.5",
30
29
  "ms": "2.1.2",
30
+ "optional-require": "1.0.x",
31
31
  "regexp-clone": "1.0.0",
32
32
  "safe-buffer": "5.2.1",
33
33
  "sift": "13.5.2",
@@ -84,6 +84,7 @@
84
84
  "test-cov": "nyc --reporter=html --reporter=text npm test"
85
85
  },
86
86
  "main": "./index.js",
87
+ "types": "./index.d.ts",
87
88
  "engines": {
88
89
  "node": ">=4.0.0"
89
90
  },