mongoose 6.1.10 → 6.2.3

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 (81) hide show
  1. package/.eslintrc.json +154 -0
  2. package/CHANGELOG.md +73 -0
  3. package/dist/browser.umd.js +233 -222
  4. package/index.js +5 -1
  5. package/lib/aggregate.js +23 -28
  6. package/lib/browserDocument.js +1 -1
  7. package/lib/cast/number.js +2 -3
  8. package/lib/cast.js +9 -7
  9. package/lib/connection.js +76 -24
  10. package/lib/cursor/AggregationCursor.js +12 -7
  11. package/lib/cursor/QueryCursor.js +11 -6
  12. package/lib/document.js +131 -122
  13. package/lib/drivers/node-mongodb-native/collection.js +12 -4
  14. package/lib/drivers/node-mongodb-native/connection.js +11 -0
  15. package/lib/error/cast.js +3 -2
  16. package/lib/error/index.js +11 -0
  17. package/lib/error/syncIndexes.js +30 -0
  18. package/lib/helpers/clone.js +51 -29
  19. package/lib/helpers/common.js +2 -2
  20. package/lib/helpers/cursor/eachAsync.js +18 -15
  21. package/lib/helpers/document/compile.js +7 -4
  22. package/lib/helpers/getFunctionName.js +6 -4
  23. package/lib/helpers/indexes/decorateDiscriminatorIndexOptions.js +14 -0
  24. package/lib/helpers/indexes/getRelatedIndexes.js +59 -0
  25. package/lib/helpers/isMongooseObject.js +9 -8
  26. package/lib/helpers/isObject.js +4 -4
  27. package/lib/helpers/model/discriminator.js +2 -1
  28. package/lib/helpers/path/parentPaths.js +10 -5
  29. package/lib/helpers/populate/assignRawDocsToIdStructure.js +4 -2
  30. package/lib/helpers/populate/assignVals.js +12 -4
  31. package/lib/helpers/populate/getModelsMapForPopulate.js +4 -4
  32. package/lib/helpers/populate/markArraySubdocsPopulated.js +3 -1
  33. package/lib/helpers/populate/modelNamesFromRefPath.js +4 -3
  34. package/lib/helpers/printJestWarning.js +2 -2
  35. package/lib/helpers/projection/applyProjection.js +77 -0
  36. package/lib/helpers/projection/hasIncludedChildren.js +36 -0
  37. package/lib/helpers/projection/isExclusive.js +5 -2
  38. package/lib/helpers/projection/isInclusive.js +5 -1
  39. package/lib/helpers/query/cast$expr.js +279 -0
  40. package/lib/helpers/query/castUpdate.js +6 -2
  41. package/lib/helpers/query/hasDollarKeys.js +7 -3
  42. package/lib/helpers/query/isOperator.js +5 -2
  43. package/lib/helpers/schema/applyPlugins.js +11 -0
  44. package/lib/helpers/schema/getIndexes.js +6 -2
  45. package/lib/helpers/schema/getPath.js +4 -2
  46. package/lib/helpers/timestamps/setupTimestamps.js +3 -8
  47. package/lib/index.js +26 -19
  48. package/lib/internal.js +10 -2
  49. package/lib/model.js +196 -171
  50. package/lib/options/SchemaTypeOptions.js +1 -1
  51. package/lib/plugins/trackTransaction.js +5 -4
  52. package/lib/query.js +159 -146
  53. package/lib/queryhelpers.js +10 -10
  54. package/lib/schema/SubdocumentPath.js +4 -3
  55. package/lib/schema/array.js +30 -21
  56. package/lib/schema/buffer.js +1 -1
  57. package/lib/schema/date.js +1 -1
  58. package/lib/schema/decimal128.js +1 -1
  59. package/lib/schema/documentarray.js +9 -11
  60. package/lib/schema/number.js +1 -1
  61. package/lib/schema/objectid.js +2 -2
  62. package/lib/schema/string.js +4 -4
  63. package/lib/schema.js +13 -8
  64. package/lib/schematype.js +86 -40
  65. package/lib/types/ArraySubdocument.js +2 -1
  66. package/lib/types/DocumentArray/index.js +10 -27
  67. package/lib/types/DocumentArray/isMongooseDocumentArray.js +5 -0
  68. package/lib/types/DocumentArray/methods/index.js +15 -3
  69. package/lib/types/array/index.js +22 -21
  70. package/lib/types/array/isMongooseArray.js +5 -0
  71. package/lib/types/array/methods/index.js +22 -23
  72. package/lib/types/buffer.js +3 -3
  73. package/lib/types/map.js +3 -4
  74. package/lib/utils.js +19 -10
  75. package/package.json +34 -168
  76. package/tools/repl.js +1 -1
  77. package/tsconfig.json +8 -0
  78. package/types/Error.d.ts +129 -0
  79. package/types/PipelineStage.d.ts +272 -0
  80. package/{index.d.ts → types/index.d.ts} +169 -481
  81. package/lib/types/array/ArrayWrapper.js +0 -981
@@ -8,7 +8,6 @@ const MongooseCollection = require('../../collection');
8
8
  const MongooseError = require('../../error/mongooseError');
9
9
  const Collection = require('mongodb').Collection;
10
10
  const ObjectId = require('./objectid');
11
- const get = require('../../helpers/get');
12
11
  const getConstructorName = require('../../helpers/getConstructorName');
13
12
  const stream = require('stream');
14
13
  const util = require('util');
@@ -76,7 +75,11 @@ function iter(i) {
76
75
  const collection = this.collection;
77
76
  const args = Array.from(arguments);
78
77
  const _this = this;
79
- const debug = get(_this, 'conn.base.options.debug');
78
+ const debug = _this &&
79
+ _this.conn &&
80
+ _this.conn.base &&
81
+ _this.conn.base.options &&
82
+ _this.conn.base.options.debug;
80
83
  const lastArg = arguments[arguments.length - 1];
81
84
  const opId = new ObjectId();
82
85
 
@@ -84,7 +87,7 @@ function iter(i) {
84
87
  if (this.conn.$wasForceClosed) {
85
88
  const error = new MongooseError('Connection was force closed');
86
89
  if (args.length > 0 &&
87
- typeof args[args.length - 1] === 'function') {
90
+ typeof args[args.length - 1] === 'function') {
88
91
  args[args.length - 1](error);
89
92
  return;
90
93
  } else {
@@ -368,7 +371,12 @@ function format(obj, sub, color, shell) {
368
371
  formatDate(x, key, shell);
369
372
  } else if (_constructorName === 'ClientSession') {
370
373
  x[key] = inspectable('ClientSession("' +
371
- get(x[key], 'id.id.buffer', '').toString('hex') + '")');
374
+ (
375
+ x[key] &&
376
+ x[key].id &&
377
+ x[key].id.id &&
378
+ x[key].id.id.buffer || ''
379
+ ).toString('hex') + '")');
372
380
  } else if (Array.isArray(x[key])) {
373
381
  x[key] = x[key].map(map);
374
382
  } else if (error != null) {
@@ -137,6 +137,17 @@ NativeConnection.prototype.doClose = function(force, fn) {
137
137
  return this;
138
138
  }
139
139
 
140
+ let skipCloseClient = false;
141
+ if (force != null && typeof force === 'object') {
142
+ skipCloseClient = force.skipCloseClient;
143
+ force = force.force;
144
+ }
145
+
146
+ if (skipCloseClient) {
147
+ immediate(() => fn());
148
+ return this;
149
+ }
150
+
140
151
  this.client.close(force, (err, res) => {
141
152
  // Defer because the driver will wait at least 1ms before finishing closing
142
153
  // the pool, see https://github.com/mongodb-js/mongodb-core/blob/a8f8e4ce41936babc3b9112bf42d609779f03b39/lib/connection/pool.js#L1026-L1030.
package/lib/error/cast.js CHANGED
@@ -5,7 +5,6 @@
5
5
  */
6
6
 
7
7
  const MongooseError = require('./mongooseError');
8
- const get = require('../helpers/get');
9
8
  const util = require('util');
10
9
 
11
10
  /**
@@ -111,7 +110,9 @@ function getValueType(value) {
111
110
  }
112
111
 
113
112
  function getMessageFormat(schemaType) {
114
- const messageFormat = get(schemaType, 'options.cast', null);
113
+ const messageFormat = schemaType &&
114
+ schemaType.options &&
115
+ schemaType.options.cast || null;
115
116
  if (typeof messageFormat === 'string') {
116
117
  return messageFormat;
117
118
  }
@@ -181,6 +181,17 @@ MongooseError.OverwriteModelError = require('./overwriteModel');
181
181
 
182
182
  MongooseError.MissingSchemaError = require('./missingSchema');
183
183
 
184
+ /**
185
+ * Thrown when the MongoDB Node driver can't connect to a valid server
186
+ * to send an operation to.
187
+ *
188
+ * @api public
189
+ * @memberOf Error
190
+ * @static MongooseServerSelectionError
191
+ */
192
+
193
+ MongooseError.MongooseServerSelectionError = require('./serverSelection');
194
+
184
195
  /**
185
196
  * An instance of this error will be returned if you used an array projection
186
197
  * and then modified the array in an unsafe way.
@@ -0,0 +1,30 @@
1
+ 'use strict';
2
+
3
+ /*!
4
+ * Module dependencies.
5
+ */
6
+
7
+ const MongooseError = require('./mongooseError');
8
+
9
+ /**
10
+ * SyncIndexes Error constructor.
11
+ *
12
+ * @param {String} message
13
+ * @param {String} errorsMap
14
+ * @inherits MongooseError
15
+ * @api private
16
+ */
17
+
18
+ class SyncIndexesError extends MongooseError {
19
+ constructor(message, errorsMap) {
20
+ super(message);
21
+ this.errors = errorsMap;
22
+ }
23
+ }
24
+
25
+ Object.defineProperty(SyncIndexesError.prototype, 'name', {
26
+ value: 'SyncIndexesError'
27
+ });
28
+
29
+
30
+ module.exports = SyncIndexesError;
@@ -1,7 +1,5 @@
1
1
  'use strict';
2
2
 
3
-
4
- const cloneRegExp = require('regexp-clone');
5
3
  const Decimal = require('../types/decimal128');
6
4
  const ObjectId = require('../types/objectid');
7
5
  const specialProperties = require('./specialProperties');
@@ -34,7 +32,7 @@ function clone(obj, options, isArrayChild) {
34
32
  }
35
33
 
36
34
  if (Array.isArray(obj)) {
37
- return cloneArray(obj, options);
35
+ return cloneArray(utils.isMongooseArray(obj) ? obj.__array : obj, options);
38
36
  }
39
37
 
40
38
  if (isMongooseObject(obj)) {
@@ -43,23 +41,34 @@ function clone(obj, options, isArrayChild) {
43
41
  if (options && options._skipSingleNestedGetters && obj.$isSingleNested) {
44
42
  options = Object.assign({}, options, { getters: false });
45
43
  }
44
+ const isSingleNested = obj.$isSingleNested;
46
45
 
47
46
  if (utils.isPOJO(obj) && obj.$__ != null && obj._doc != null) {
48
47
  return obj._doc;
49
48
  }
50
49
 
50
+ let ret;
51
51
  if (options && options.json && typeof obj.toJSON === 'function') {
52
- return obj.toJSON(options);
52
+ ret = obj.toJSON(options);
53
+ } else {
54
+ ret = obj.toObject(options);
55
+ }
56
+
57
+ if (options && options.minimize && isSingleNested && Object.keys(ret).length === 0) {
58
+ return undefined;
53
59
  }
54
- return obj.toObject(options);
60
+
61
+ return ret;
55
62
  }
56
63
 
57
- if (obj.constructor) {
58
- switch (getFunctionName(obj.constructor)) {
64
+ const objConstructor = obj.constructor;
65
+
66
+ if (objConstructor) {
67
+ switch (getFunctionName(objConstructor)) {
59
68
  case 'Object':
60
69
  return cloneObject(obj, options, isArrayChild);
61
70
  case 'Date':
62
- return new obj.constructor(+obj);
71
+ return new objConstructor(+obj);
63
72
  case 'RegExp':
64
73
  return cloneRegExp(obj);
65
74
  default:
@@ -79,12 +88,12 @@ function clone(obj, options, isArrayChild) {
79
88
  return Decimal.fromString(obj.toString());
80
89
  }
81
90
 
82
- if (!obj.constructor && isObject(obj)) {
83
- // object created with Object.create(null)
91
+ // object created with Object.create(null)
92
+ if (!objConstructor && isObject(obj)) {
84
93
  return cloneObject(obj, options, isArrayChild);
85
94
  }
86
95
 
87
- if (obj[symbols.schemaTypeSymbol]) {
96
+ if (typeof obj === 'object' && obj[symbols.schemaTypeSymbol]) {
88
97
  return obj.clone();
89
98
  }
90
99
 
@@ -95,7 +104,7 @@ function clone(obj, options, isArrayChild) {
95
104
  return obj;
96
105
  }
97
106
 
98
- if (obj.valueOf != null) {
107
+ if (typeof obj.valueOf === 'function') {
99
108
  return obj.valueOf();
100
109
  }
101
110
 
@@ -112,25 +121,28 @@ function cloneObject(obj, options, isArrayChild) {
112
121
  const ret = {};
113
122
  let hasKeys;
114
123
 
115
- if (obj[trustedSymbol]) {
124
+ if (trustedSymbol in obj) {
116
125
  ret[trustedSymbol] = obj[trustedSymbol];
117
126
  }
118
127
 
119
- for (const k of Object.keys(obj)) {
120
- if (specialProperties.has(k)) {
128
+ let i = 0;
129
+ let key = '';
130
+ const keys = Object.keys(obj);
131
+ const len = keys.length;
132
+
133
+ for (i = 0; i < len; ++i) {
134
+ if (specialProperties.has(key = keys[i])) {
121
135
  continue;
122
136
  }
123
137
 
124
138
  // Don't pass `isArrayChild` down
125
- const val = clone(obj[k], options);
126
-
127
- if (!minimize || (typeof val !== 'undefined')) {
128
- if (minimize === false && typeof val === 'undefined') {
129
- delete ret[k];
130
- } else {
131
- hasKeys || (hasKeys = true);
132
- ret[k] = val;
133
- }
139
+ const val = clone(obj[key], options, false);
140
+
141
+ if (minimize === false && typeof val === 'undefined') {
142
+ delete ret[key];
143
+ } else if (minimize !== true || (typeof val !== 'undefined')) {
144
+ hasKeys || (hasKeys = true);
145
+ ret[key] = val;
134
146
  }
135
147
  }
136
148
 
@@ -138,11 +150,21 @@ function cloneObject(obj, options, isArrayChild) {
138
150
  }
139
151
 
140
152
  function cloneArray(arr, options) {
141
- const ret = [];
142
-
143
- for (const item of arr) {
144
- ret.push(clone(item, options, true));
153
+ let i = 0;
154
+ const len = arr.length;
155
+ const ret = new Array(len);
156
+ for (i = 0; i < len; ++i) {
157
+ ret[i] = clone(arr[i], options, true);
145
158
  }
146
159
 
147
160
  return ret;
148
- }
161
+ }
162
+
163
+ function cloneRegExp(regexp) {
164
+ const ret = new RegExp(regexp.source, regexp.flags);
165
+
166
+ if (ret.lastIndex !== regexp.lastIndex) {
167
+ ret.lastIndex = regexp.lastIndex;
168
+ }
169
+ return ret;
170
+ }
@@ -88,7 +88,7 @@ function modifiedPaths(update, path, result) {
88
88
  cur += '.' + sp[i];
89
89
  }
90
90
  }
91
- if (isMongooseObject(val) && !Buffer.isBuffer(val)) {
91
+ if (!Buffer.isBuffer(val) && isMongooseObject(val)) {
92
92
  val = val.toObject({ transform: false, virtuals: false });
93
93
  }
94
94
  if (shouldFlatten(val)) {
@@ -108,7 +108,7 @@ function shouldFlatten(val) {
108
108
  typeof val === 'object' &&
109
109
  !(val instanceof Date) &&
110
110
  !(val instanceof ObjectId) &&
111
- (!Array.isArray(val) || val.length > 0) &&
111
+ (!Array.isArray(val) || val.length !== 0) &&
112
112
  !(val instanceof Buffer) &&
113
113
  !(val instanceof Decimal128) &&
114
114
  !(val instanceof Binary);
@@ -27,16 +27,15 @@ module.exports = function eachAsync(next, fn, options, callback) {
27
27
  const enqueue = asyncQueue();
28
28
 
29
29
  return promiseOrCallback(callback, cb => {
30
+
30
31
  if (batchSize != null) {
31
32
  if (typeof batchSize !== 'number') {
32
33
  throw new TypeError('batchSize must be a number');
33
- }
34
- if (batchSize < 1) {
34
+ } else if (!Number.isInteger(batchSize)) {
35
+ throw new TypeError('batchSize must be an integer');
36
+ } else if (batchSize < 1) {
35
37
  throw new TypeError('batchSize must be at least 1');
36
38
  }
37
- if (batchSize !== Math.floor(batchSize)) {
38
- throw new TypeError('batchSize must be a positive integer');
39
- }
40
39
  }
41
40
 
42
41
  iterate(cb);
@@ -71,7 +70,7 @@ module.exports = function eachAsync(next, fn, options, callback) {
71
70
  drained = true;
72
71
  if (handleResultsInProgress <= 0) {
73
72
  finalCallback(null);
74
- } else if (batchSize != null && documentsBatch.length) {
73
+ } else if (batchSize && documentsBatch.length) {
75
74
  handleNextResult(documentsBatch, currentDocumentIndex++, handleNextResultCallBack);
76
75
  }
77
76
  return done();
@@ -83,20 +82,20 @@ module.exports = function eachAsync(next, fn, options, callback) {
83
82
  // make sure we know that we still have a result to handle re: #8422
84
83
  immediate(() => done());
85
84
 
86
- if (batchSize != null) {
85
+ if (batchSize) {
87
86
  documentsBatch.push(doc);
88
87
  }
89
88
 
90
89
  // If the current documents size is less than the provided patch size don't process the documents yet
91
- if (batchSize != null && documentsBatch.length !== batchSize) {
92
- setTimeout(() => enqueue(fetch), 0);
90
+ if (batchSize && documentsBatch.length !== batchSize) {
91
+ immediate(() => enqueue(fetch));
93
92
  return;
94
93
  }
95
94
 
96
- const docsToProcess = batchSize != null ? documentsBatch : doc;
95
+ const docsToProcess = batchSize ? documentsBatch : doc;
97
96
 
98
97
  function handleNextResultCallBack(err) {
99
- if (batchSize != null) {
98
+ if (batchSize) {
100
99
  handleResultsInProgress -= documentsBatch.length;
101
100
  documentsBatch = [];
102
101
  } else {
@@ -110,7 +109,7 @@ module.exports = function eachAsync(next, fn, options, callback) {
110
109
  return finalCallback(null);
111
110
  }
112
111
 
113
- setTimeout(() => enqueue(fetch), 0);
112
+ immediate(() => enqueue(fetch));
114
113
  }
115
114
 
116
115
  handleNextResult(docsToProcess, currentDocumentIndex++, handleNextResultCallBack);
@@ -139,7 +138,10 @@ function asyncQueue() {
139
138
  let id = 0;
140
139
 
141
140
  return function enqueue(fn) {
142
- if (_queue.length === 0 && inProgress == null) {
141
+ if (
142
+ inProgress === null &&
143
+ _queue.length === 0
144
+ ) {
143
145
  inProgress = id++;
144
146
  return fn(_step);
145
147
  }
@@ -147,11 +149,12 @@ function asyncQueue() {
147
149
  };
148
150
 
149
151
  function _step() {
150
- inProgress = null;
151
- if (_queue.length > 0) {
152
+ if (_queue.length !== 0) {
152
153
  inProgress = id++;
153
154
  const fn = _queue.shift();
154
155
  fn(_step);
156
+ } else {
157
+ inProgress = null;
155
158
  }
156
159
  }
157
160
  }
@@ -1,7 +1,6 @@
1
1
  'use strict';
2
2
 
3
3
  const documentSchemaSymbol = require('../../helpers/symbols').documentSchemaSymbol;
4
- const get = require('../../helpers/get');
5
4
  const internalToObjectOptions = require('../../options').internalToObjectOptions;
6
5
  const utils = require('../../utils');
7
6
 
@@ -93,7 +92,11 @@ function defineKey({ prop, subprops, prototype, prefix, options }) {
93
92
  writable: false,
94
93
  value: function() {
95
94
  return utils.clone(_this.get(path, null, {
96
- virtuals: get(this, 'schema.options.toObject.virtuals', null)
95
+ virtuals: this &&
96
+ this.schema &&
97
+ this.schema.options &&
98
+ this.schema.options.toObject &&
99
+ this.schema.options.toObject.virtuals || null
97
100
  }));
98
101
  }
99
102
  });
@@ -104,7 +107,7 @@ function defineKey({ prop, subprops, prototype, prefix, options }) {
104
107
  writable: false,
105
108
  value: function() {
106
109
  return _this.get(path, null, {
107
- virtuals: get(this, 'schema.options.toObject.virtuals', null)
110
+ virtuals: this && this.schema && this.schema.options && this.schema.options.toObject && this.schema.options.toObject.virtuals || null
108
111
  });
109
112
  }
110
113
  });
@@ -115,7 +118,7 @@ function defineKey({ prop, subprops, prototype, prefix, options }) {
115
118
  writable: false,
116
119
  value: function() {
117
120
  return _this.get(path, null, {
118
- virtuals: get(_this, 'schema.options.toJSON.virtuals', null)
121
+ virtuals: this && this.schema && this.schema.options && this.schema.options.toJSON && this.schema.options.toJSON.virtuals || null
119
122
  });
120
123
  }
121
124
  });
@@ -1,8 +1,10 @@
1
1
  'use strict';
2
2
 
3
+ const functionNameRE = /^function\s*([^\s(]+)/;
4
+
3
5
  module.exports = function(fn) {
4
- if (fn.name) {
5
- return fn.name;
6
- }
7
- return (fn.toString().trim().match(/^function\s*([^\s(]+)/) || [])[1];
6
+ return (
7
+ fn.name ||
8
+ (fn.toString().trim().match(functionNameRE) || [])[1]
9
+ );
8
10
  };
@@ -0,0 +1,14 @@
1
+ 'use strict';
2
+
3
+ module.exports = function decorateDiscriminatorIndexOptions(schema, indexOptions) {
4
+ // If the model is a discriminator and has an index, add a
5
+ // partialFilterExpression by default so the index will only apply
6
+ // to that discriminator.
7
+ const discriminatorName = schema.discriminatorMapping && schema.discriminatorMapping.value;
8
+ if (discriminatorName && !('sparse' in indexOptions)) {
9
+ const discriminatorKey = schema.options.discriminatorKey;
10
+ indexOptions.partialFilterExpression = indexOptions.partialFilterExpression || {};
11
+ indexOptions.partialFilterExpression[discriminatorKey] = discriminatorName;
12
+ }
13
+ return indexOptions;
14
+ };
@@ -0,0 +1,59 @@
1
+ 'use strict';
2
+
3
+ function getRelatedSchemaIndexes(model, schemaIndexes) {
4
+ return getRelatedIndexes({
5
+ baseModelName: model.baseModelName,
6
+ discriminatorMapping: model.schema.discriminatorMapping,
7
+ indexes: schemaIndexes,
8
+ indexesType: 'schema'
9
+ });
10
+ }
11
+
12
+ function getRelatedDBIndexes(model, dbIndexes) {
13
+ return getRelatedIndexes({
14
+ baseModelName: model.baseModelName,
15
+ discriminatorMapping: model.schema.discriminatorMapping,
16
+ indexes: dbIndexes,
17
+ indexesType: 'db'
18
+ });
19
+ }
20
+
21
+ module.exports = {
22
+ getRelatedSchemaIndexes,
23
+ getRelatedDBIndexes
24
+ };
25
+
26
+ function getRelatedIndexes({
27
+ baseModelName,
28
+ discriminatorMapping,
29
+ indexes,
30
+ indexesType
31
+ }) {
32
+ const discriminatorKey = discriminatorMapping && discriminatorMapping.key;
33
+ const discriminatorValue = discriminatorMapping && discriminatorMapping.value;
34
+
35
+ if (!discriminatorKey) {
36
+ return indexes;
37
+ }
38
+
39
+ const isChildDiscriminatorModel = Boolean(baseModelName);
40
+ if (isChildDiscriminatorModel) {
41
+ return indexes.filter(index => {
42
+ const partialFilterExpression = getPartialFilterExpression(index, indexesType);
43
+ return partialFilterExpression && partialFilterExpression[discriminatorKey] === discriminatorValue;
44
+ });
45
+ }
46
+
47
+ return indexes.filter(index => {
48
+ const partialFilterExpression = getPartialFilterExpression(index, indexesType);
49
+ return !partialFilterExpression || !partialFilterExpression[discriminatorKey];
50
+ });
51
+ }
52
+
53
+ function getPartialFilterExpression(index, indexesType) {
54
+ if (indexesType === 'schema') {
55
+ const options = index[1];
56
+ return options && options.partialFilterExpression;
57
+ }
58
+ return index.partialFilterExpression;
59
+ }
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ const isMongooseArray = require('../types/array/isMongooseArray').isMongooseArray;
3
4
  /*!
4
5
  * Returns if `v` is a mongoose object that has a `toObject()` method we can use.
5
6
  *
@@ -10,12 +11,12 @@
10
11
  */
11
12
 
12
13
  module.exports = function(v) {
13
- if (v == null) {
14
- return false;
15
- }
16
-
17
- return v.$__ != null || // Document
18
- v.isMongooseArray || // Array or Document Array
19
- v.isMongooseBuffer || // Buffer
20
- v.$isMongooseMap; // Map
14
+ return (
15
+ v != null && (
16
+ isMongooseArray(v) || // Array or Document Array
17
+ v.$__ != null || // Document
18
+ v.isMongooseBuffer || // Buffer
19
+ v.$isMongooseMap // Map
20
+ )
21
+ );
21
22
  };
@@ -9,8 +9,8 @@
9
9
  */
10
10
 
11
11
  module.exports = function(arg) {
12
- if (Buffer.isBuffer(arg)) {
13
- return true;
14
- }
15
- return Object.prototype.toString.call(arg) === '[object Object]';
12
+ return (
13
+ Buffer.isBuffer(arg) ||
14
+ Object.prototype.toString.call(arg) === '[object Object]'
15
+ );
16
16
  };
@@ -17,6 +17,7 @@ const CUSTOMIZABLE_DISCRIMINATOR_OPTIONS = {
17
17
  */
18
18
 
19
19
  module.exports = function discriminator(model, name, schema, tiedValue, applyPlugins) {
20
+
20
21
  if (!(schema && schema.instanceOfSchema)) {
21
22
  throw new Error('You must pass a valid discriminator Schema');
22
23
  }
@@ -201,7 +202,7 @@ module.exports = function discriminator(model, name, schema, tiedValue, applyPlu
201
202
 
202
203
  model.schema.discriminators[name] = schema;
203
204
 
204
- if (model.discriminators[name]) {
205
+ if (model.discriminators[name] && !schema.options.overwriteModels) {
205
206
  throw new Error('Discriminator with name "' + name + '" already exists');
206
207
  }
207
208
 
@@ -1,12 +1,17 @@
1
1
  'use strict';
2
2
 
3
+ const dotRE = /\./g;
3
4
  module.exports = function parentPaths(path) {
4
- const pieces = path.split('.');
5
+ if (path.indexOf('.') === -1) {
6
+ return [path];
7
+ }
8
+ const pieces = path.split(dotRE);
9
+ const len = pieces.length;
10
+ const ret = new Array(len);
5
11
  let cur = '';
6
- const ret = [];
7
- for (let i = 0; i < pieces.length; ++i) {
8
- cur += (cur.length > 0 ? '.' : '') + pieces[i];
9
- ret.push(cur);
12
+ for (let i = 0; i < len; ++i) {
13
+ cur += (cur.length !== 0) ? '.' + pieces[i] : pieces[i];
14
+ ret[i] = cur;
10
15
  }
11
16
 
12
17
  return ret;
@@ -35,11 +35,13 @@ function assignRawDocsToIdStructure(rawIds, resultDocs, resultOrder, options, re
35
35
  let sid;
36
36
  let id;
37
37
 
38
- if (rawIds.isMongooseArrayProxy) {
38
+ if (utils.isMongooseArray(rawIds)) {
39
39
  rawIds = rawIds.__array;
40
40
  }
41
41
 
42
- for (let i = 0; i < rawIds.length; ++i) {
42
+ let i = 0;
43
+ const len = rawIds.length;
44
+ for (i = 0; i < len; ++i) {
43
45
  id = rawIds[i];
44
46
 
45
47
  if (Array.isArray(id)) {
@@ -172,6 +172,10 @@ module.exports = function assignVals(o) {
172
172
  o.allOptions.options[populateModelSymbol] = o.allOptions.model;
173
173
  docs[i].$populated(_path, o.unpopulatedValues[i], o.allOptions.options);
174
174
 
175
+ if (valueToSet != null && valueToSet.$__ != null) {
176
+ valueToSet.$__.wasPopulated = { value: o.unpopulatedValues[i] };
177
+ }
178
+
175
179
  if (valueToSet instanceof Map && !valueToSet.$isMongooseMap) {
176
180
  valueToSet = new MongooseMap(valueToSet, _path, docs[i], docs[i].schema.path(_path).$__schemaType);
177
181
  }
@@ -241,15 +245,19 @@ function valueFilter(val, assignmentOpts, populateOptions, allIds) {
241
245
  }
242
246
  }
243
247
 
248
+ const rLen = ret.length;
244
249
  // Since we don't want to have to create a new mongoosearray, make sure to
245
250
  // modify the array in place
246
- while (val.length > ret.length) {
251
+ while (val.length > rLen) {
247
252
  Array.prototype.pop.apply(val, []);
248
253
  }
249
- for (let i = 0; i < ret.length; ++i) {
250
- if (val.isMongooseArrayProxy) {
254
+ let i = 0;
255
+ if (utils.isMongooseArray(val)) {
256
+ for (i = 0; i < rLen; ++i) {
251
257
  val.set(i, ret[i], true);
252
- } else {
258
+ }
259
+ } else {
260
+ for (i = 0; i < rLen; ++i) {
253
261
  val[i] = ret[i];
254
262
  }
255
263
  }