mongoose 6.7.3 → 6.7.5

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/lib/cast.js CHANGED
@@ -264,7 +264,7 @@ module.exports = function cast(schema, obj, options, context) {
264
264
  }
265
265
 
266
266
  const strict = 'strict' in options ? options.strict : schema.options.strict;
267
- const strictQuery = getStrictQuery(options, schema._userProvidedOptions, schema.options);
267
+ const strictQuery = getStrictQuery(options, schema._userProvidedOptions, schema.options, context);
268
268
  if (options.upsert && strict) {
269
269
  if (strict === 'throw') {
270
270
  throw new StrictModeError(path);
@@ -374,7 +374,7 @@ function _cast(val, numbertype, context) {
374
374
  }
375
375
  }
376
376
 
377
- function getStrictQuery(queryOptions, schemaUserProvidedOptions, schemaOptions) {
377
+ function getStrictQuery(queryOptions, schemaUserProvidedOptions, schemaOptions, context) {
378
378
  if ('strictQuery' in queryOptions) {
379
379
  return queryOptions.strictQuery;
380
380
  }
@@ -387,5 +387,17 @@ function getStrictQuery(queryOptions, schemaUserProvidedOptions, schemaOptions)
387
387
  if ('strict' in schemaUserProvidedOptions) {
388
388
  return schemaUserProvidedOptions.strict;
389
389
  }
390
+ const mongooseOptions = context.mongooseCollection &&
391
+ context.mongooseCollection.conn &&
392
+ context.mongooseCollection.conn.base &&
393
+ context.mongooseCollection.conn.base.options;
394
+ if (mongooseOptions) {
395
+ if ('strictQuery' in mongooseOptions) {
396
+ return mongooseOptions.strictQuery;
397
+ }
398
+ if ('strict' in mongooseOptions) {
399
+ return mongooseOptions.strict;
400
+ }
401
+ }
390
402
  return schemaOptions.strictQuery;
391
403
  }
@@ -7,6 +7,8 @@
7
7
  const Binary = require('../driver').get().Binary;
8
8
  const isBsonType = require('./isBsonType');
9
9
  const isMongooseObject = require('./isMongooseObject');
10
+ const MongooseError = require('../error');
11
+ const util = require('util');
10
12
 
11
13
  exports.flatten = flatten;
12
14
  exports.modifiedPaths = modifiedPaths;
@@ -67,7 +69,25 @@ function flatten(update, path, options, schema) {
67
69
  * ignore
68
70
  */
69
71
 
70
- function modifiedPaths(update, path, result) {
72
+ function modifiedPaths(update, path, result, recursion = null) {
73
+ if (update == null || typeof update !== 'object') {
74
+ return;
75
+ }
76
+
77
+ if (recursion == null) {
78
+ recursion = {
79
+ raw: { update, path },
80
+ trace: new WeakSet()
81
+ };
82
+ }
83
+
84
+ if (recursion.trace.has(update)) {
85
+ throw new MongooseError(`a circular reference in the update value, updateValue:
86
+ ${util.inspect(recursion.raw.update, { showHidden: false, depth: 1 })}
87
+ updatePath: '${recursion.raw.path}'`);
88
+ }
89
+ recursion.trace.add(update);
90
+
71
91
  const keys = Object.keys(update || {});
72
92
  const numKeys = keys.length;
73
93
  result = result || {};
@@ -83,7 +103,7 @@ function modifiedPaths(update, path, result) {
83
103
  val = val.toObject({ transform: false, virtuals: false });
84
104
  }
85
105
  if (shouldFlatten(val)) {
86
- modifiedPaths(val, path + key, result);
106
+ modifiedPaths(val, path + key, result, recursion);
87
107
  }
88
108
  }
89
109
 
@@ -96,11 +116,11 @@ function modifiedPaths(update, path, result) {
96
116
 
97
117
  function shouldFlatten(val) {
98
118
  return val &&
99
- typeof val === 'object' &&
100
- !(val instanceof Date) &&
101
- !isBsonType(val, 'ObjectID') &&
102
- (!Array.isArray(val) || val.length !== 0) &&
103
- !(val instanceof Buffer) &&
104
- !isBsonType(val, 'Decimal128') &&
105
- !(val instanceof Binary);
119
+ typeof val === 'object' &&
120
+ !(val instanceof Date) &&
121
+ !isBsonType(val, 'ObjectID') &&
122
+ (!Array.isArray(val) || val.length !== 0) &&
123
+ !(val instanceof Buffer) &&
124
+ !isBsonType(val, 'Decimal128') &&
125
+ !(val instanceof Binary);
106
126
  }
@@ -33,7 +33,7 @@ module.exports = function eachAsync(next, fn, options, callback) {
33
33
  const aggregatedErrors = [];
34
34
  const enqueue = asyncQueue();
35
35
 
36
- let drained = false;
36
+ let aborted = false;
37
37
 
38
38
  return promiseOrCallback(callback, cb => {
39
39
  if (signal != null) {
@@ -42,7 +42,7 @@ module.exports = function eachAsync(next, fn, options, callback) {
42
42
  }
43
43
 
44
44
  signal.addEventListener('abort', () => {
45
- drained = true;
45
+ aborted = true;
46
46
  return cb(null);
47
47
  }, { once: true });
48
48
  }
@@ -63,90 +63,104 @@ module.exports = function eachAsync(next, fn, options, callback) {
63
63
  function iterate(finalCallback) {
64
64
  let handleResultsInProgress = 0;
65
65
  let currentDocumentIndex = 0;
66
- let documentsBatch = [];
67
66
 
68
67
  let error = null;
69
68
  for (let i = 0; i < parallel; ++i) {
70
- enqueue(fetch);
69
+ enqueue(createFetch());
71
70
  }
72
71
 
73
- function fetch(done) {
74
- if (drained || error) {
75
- return done();
76
- }
72
+ function createFetch() {
73
+ let documentsBatch = [];
74
+ let drained = false;
75
+
76
+ return fetch;
77
77
 
78
- next(function(err, doc) {
79
- if (drained || error != null) {
78
+ function fetch(done) {
79
+ if (drained || aborted) {
80
+ return done();
81
+ } else if (error) {
80
82
  return done();
81
83
  }
82
- if (err != null) {
83
- if (continueOnError) {
84
- aggregatedErrors.push(err);
85
- } else {
86
- error = err;
87
- finalCallback(err);
84
+
85
+ next(function(err, doc) {
86
+ if (error != null) {
88
87
  return done();
89
88
  }
90
- }
91
- if (doc == null) {
92
- drained = true;
93
- if (handleResultsInProgress <= 0) {
94
- const finalErr = continueOnError ?
95
- createEachAsyncMultiError(aggregatedErrors) :
96
- error;
97
-
98
- finalCallback(finalErr);
99
- } else if (batchSize && documentsBatch.length) {
100
- handleNextResult(documentsBatch, currentDocumentIndex++, handleNextResultCallBack);
89
+ if (err != null) {
90
+ if (err.name === 'MongoCursorExhaustedError') {
91
+ // We may end up calling `next()` multiple times on an exhausted
92
+ // cursor, which leads to an error. In case cursor is exhausted,
93
+ // just treat it as if the cursor returned no document, which is
94
+ // how a cursor indicates it is exhausted.
95
+ doc = null;
96
+ } else if (continueOnError) {
97
+ aggregatedErrors.push(err);
98
+ } else {
99
+ error = err;
100
+ finalCallback(err);
101
+ return done();
102
+ }
103
+ }
104
+ if (doc == null) {
105
+ drained = true;
106
+ if (handleResultsInProgress <= 0) {
107
+ const finalErr = continueOnError ?
108
+ createEachAsyncMultiError(aggregatedErrors) :
109
+ error;
110
+
111
+ finalCallback(finalErr);
112
+ } else if (batchSize && documentsBatch.length) {
113
+ handleNextResult(documentsBatch, currentDocumentIndex++, handleNextResultCallBack);
114
+ }
115
+ return done();
101
116
  }
102
- return done();
103
- }
104
117
 
105
- ++handleResultsInProgress;
118
+ ++handleResultsInProgress;
106
119
 
107
- // Kick off the subsequent `next()` before handling the result, but
108
- // make sure we know that we still have a result to handle re: #8422
109
- immediate(() => done());
120
+ // Kick off the subsequent `next()` before handling the result, but
121
+ // make sure we know that we still have a result to handle re: #8422
122
+ immediate(() => done());
110
123
 
111
- if (batchSize) {
112
- documentsBatch.push(doc);
113
- }
124
+ if (batchSize) {
125
+ documentsBatch.push(doc);
126
+ }
114
127
 
115
- // If the current documents size is less than the provided patch size don't process the documents yet
116
- if (batchSize && documentsBatch.length !== batchSize) {
117
- immediate(() => enqueue(fetch));
118
- return;
119
- }
128
+ // If the current documents size is less than the provided batch size don't process the documents yet
129
+ if (batchSize && documentsBatch.length !== batchSize) {
130
+ immediate(() => enqueue(fetch));
131
+ return;
132
+ }
120
133
 
121
- const docsToProcess = batchSize ? documentsBatch : doc;
134
+ const docsToProcess = batchSize ? documentsBatch : doc;
122
135
 
123
- function handleNextResultCallBack(err) {
124
- if (batchSize) {
125
- handleResultsInProgress -= documentsBatch.length;
126
- documentsBatch = [];
127
- } else {
128
- --handleResultsInProgress;
129
- }
130
- if (err != null) {
131
- if (continueOnError) {
132
- aggregatedErrors.push(err);
136
+ function handleNextResultCallBack(err) {
137
+ if (batchSize) {
138
+ handleResultsInProgress -= documentsBatch.length;
139
+ documentsBatch = [];
133
140
  } else {
134
- error = err;
135
- return finalCallback(err);
141
+ --handleResultsInProgress;
142
+ }
143
+ if (err != null) {
144
+ if (continueOnError) {
145
+ aggregatedErrors.push(err);
146
+ } else {
147
+ error = err;
148
+ return finalCallback(err);
149
+ }
150
+ }
151
+ if ((drained || aborted) && handleResultsInProgress <= 0) {
152
+ const finalErr = continueOnError ?
153
+ createEachAsyncMultiError(aggregatedErrors) :
154
+ error;
155
+ return finalCallback(finalErr);
136
156
  }
137
- }
138
- if (drained && handleResultsInProgress <= 0) {
139
- const finalErr = continueOnError ?
140
- createEachAsyncMultiError(aggregatedErrors) :
141
- error;
142
- return finalCallback(finalErr);
143
- }
144
157
 
145
- immediate(() => enqueue(fetch));
146
- }
158
+ immediate(() => enqueue(fetch));
159
+ }
147
160
 
148
- handleNextResult(docsToProcess, currentDocumentIndex++, handleNextResultCallBack);
149
- });
161
+ handleNextResult(docsToProcess, currentDocumentIndex++, handleNextResultCallBack);
162
+ });
163
+ }
150
164
  }
151
165
  }
152
166
 
@@ -23,5 +23,6 @@ module.exports = function merge(s1, s2, skipConflictingPaths) {
23
23
  s1.virtuals[virtual] = s2.virtuals[virtual].clone();
24
24
  }
25
25
 
26
+ s1._indexes = s1._indexes.concat(s2._indexes || []);
26
27
  s1.s.hooks.merge(s2.s.hooks, false);
27
28
  };
@@ -163,6 +163,11 @@ exports.applyPaths = function applyPaths(fields, schema) {
163
163
  if (!isDefiningProjection(field)) {
164
164
  continue;
165
165
  }
166
+ // `_id: 1, name: 0` is a mixed inclusive/exclusive projection in
167
+ // MongoDB 4.0 and earlier, but not in later versions.
168
+ if (keys[keyIndex] === '_id' && keys.length > 1) {
169
+ continue;
170
+ }
166
171
  exclude = !field;
167
172
  break;
168
173
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "6.7.3",
4
+ "version": "6.7.5",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
package/types/index.d.ts CHANGED
@@ -78,7 +78,13 @@ declare module 'mongoose' {
78
78
  schema?: TSchema,
79
79
  collection?: string,
80
80
  options?: CompileModelOptions
81
- ): Model<InferSchemaType<TSchema>, ObtainSchemaGeneric<TSchema, 'TQueryHelpers'>, ObtainSchemaGeneric<TSchema, 'TInstanceMethods'>, {}, TSchema> & ObtainSchemaGeneric<TSchema, 'TStaticMethods'>;
81
+ ): Model<
82
+ InferSchemaType<TSchema>,
83
+ ObtainSchemaGeneric<TSchema, 'TQueryHelpers'>,
84
+ ObtainSchemaGeneric<TSchema, 'TInstanceMethods'>,
85
+ ObtainSchemaGeneric<TSchema, 'TVirtuals'>,
86
+ TSchema
87
+ > & ObtainSchemaGeneric<TSchema, 'TStaticMethods'>;
82
88
 
83
89
  export function model<T>(name: string, schema?: Schema<T, any, any> | Schema<T & Document, any, any>, collection?: string, options?: CompileModelOptions): Model<T>;
84
90
 
@@ -490,7 +496,12 @@ declare module 'mongoose' {
490
496
  $pullAll?: AnyKeys<TSchema> & AnyObject;
491
497
 
492
498
  /** @see https://docs.mongodb.com/manual/reference/operator/update-bitwise/ */
493
- $bit?: Record<string, mongodb.NumericType>;
499
+ // Needs to be `AnyKeys` for now, because anything stricter makes us incompatible
500
+ // with the MongoDB Node driver's `UpdateFilter` interface (see gh-12595, gh-11911)
501
+ // and using the Node driver's `$bit` definition breaks because their `OnlyFieldsOfType`
502
+ // interface breaks on Mongoose Document class due to circular references.
503
+ // Re-evaluate this when we drop `extends Document` support in document interfaces.
504
+ $bit?: AnyKeys<TSchema>;
494
505
  };
495
506
 
496
507
  export type UpdateWithAggregationPipeline = UpdateAggregationStage[];
@@ -161,29 +161,30 @@ type PathEnumOrString<T extends SchemaTypeOptions<string>['enum']> = T extends (
161
161
  type ResolvePathType<PathValueType, Options extends SchemaTypeOptions<PathValueType> = {}, TypeKey extends TypeKeyBaseType = DefaultTypeKey> =
162
162
  PathValueType extends Schema ? InferSchemaType<PathValueType> :
163
163
  PathValueType extends (infer Item)[] ? IfEquals<Item, never, any[], Item extends Schema ? Types.DocumentArray<ObtainDocumentPathType<Item, TypeKey>> : ObtainDocumentPathType<Item, TypeKey>[]> :
164
- PathValueType extends StringSchemaDefinition ? PathEnumOrString<Options['enum']> :
165
- IfEquals<PathValueType, Schema.Types.String> extends true ? PathEnumOrString<Options['enum']> :
166
- IfEquals<PathValueType, String> extends true ? PathEnumOrString<Options['enum']> :
167
- PathValueType extends NumberSchemaDefinition ? Options['enum'] extends ReadonlyArray<any> ? Options['enum'][number] : number :
168
- IfEquals<PathValueType, Schema.Types.Number> extends true ? number :
169
- PathValueType extends DateSchemaDefinition ? Date :
170
- IfEquals<PathValueType, Schema.Types.Date> extends true ? Date :
171
- PathValueType extends typeof Buffer | 'buffer' | 'Buffer' | typeof Schema.Types.Buffer ? Buffer :
172
- PathValueType extends BooleanSchemaDefinition ? boolean :
173
- IfEquals<PathValueType, Schema.Types.Boolean> extends true ? boolean :
174
- PathValueType extends ObjectIdSchemaDefinition ? Types.ObjectId :
175
- IfEquals<PathValueType, Types.ObjectId> extends true ? Types.ObjectId :
176
- IfEquals<PathValueType, Schema.Types.ObjectId> extends true ? Types.ObjectId :
177
- PathValueType extends 'decimal128' | 'Decimal128' | typeof Schema.Types.Decimal128 ? Types.Decimal128 :
178
- IfEquals<PathValueType, Schema.Types.Decimal128> extends true ? Types.Decimal128 :
179
- IfEquals<PathValueType, Types.Decimal128> extends true ? Types.Decimal128 :
180
- PathValueType extends 'uuid' | 'UUID' | typeof Schema.Types.UUID ? Buffer :
181
- IfEquals<PathValueType, Schema.Types.UUID> extends true ? Buffer :
182
- PathValueType extends MapConstructor ? Map<string, ResolvePathType<Options['of']>> :
183
- PathValueType extends ArrayConstructor ? any[] :
184
- PathValueType extends typeof Schema.Types.Mixed ? any:
185
- IfEquals<PathValueType, ObjectConstructor> extends true ? any:
186
- IfEquals<PathValueType, {}> extends true ? any:
187
- PathValueType extends typeof SchemaType ? PathValueType['prototype'] :
188
- PathValueType extends Record<string, any> ? ObtainDocumentType<PathValueType, any, TypeKey> :
189
- unknown;
164
+ PathValueType extends ReadonlyArray<infer Item> ? IfEquals<Item, never, any[], Item extends Schema ? Types.DocumentArray<ObtainDocumentPathType<Item, TypeKey>> : ObtainDocumentPathType<Item, TypeKey>[]> :
165
+ PathValueType extends StringSchemaDefinition ? PathEnumOrString<Options['enum']> :
166
+ IfEquals<PathValueType, Schema.Types.String> extends true ? PathEnumOrString<Options['enum']> :
167
+ IfEquals<PathValueType, String> extends true ? PathEnumOrString<Options['enum']> :
168
+ PathValueType extends NumberSchemaDefinition ? Options['enum'] extends ReadonlyArray<any> ? Options['enum'][number] : number :
169
+ IfEquals<PathValueType, Schema.Types.Number> extends true ? number :
170
+ PathValueType extends DateSchemaDefinition ? Date :
171
+ IfEquals<PathValueType, Schema.Types.Date> extends true ? Date :
172
+ PathValueType extends typeof Buffer | 'buffer' | 'Buffer' | typeof Schema.Types.Buffer ? Buffer :
173
+ PathValueType extends BooleanSchemaDefinition ? boolean :
174
+ IfEquals<PathValueType, Schema.Types.Boolean> extends true ? boolean :
175
+ PathValueType extends ObjectIdSchemaDefinition ? Types.ObjectId :
176
+ IfEquals<PathValueType, Types.ObjectId> extends true ? Types.ObjectId :
177
+ IfEquals<PathValueType, Schema.Types.ObjectId> extends true ? Types.ObjectId :
178
+ PathValueType extends 'decimal128' | 'Decimal128' | typeof Schema.Types.Decimal128 ? Types.Decimal128 :
179
+ IfEquals<PathValueType, Schema.Types.Decimal128> extends true ? Types.Decimal128 :
180
+ IfEquals<PathValueType, Types.Decimal128> extends true ? Types.Decimal128 :
181
+ PathValueType extends 'uuid' | 'UUID' | typeof Schema.Types.UUID ? Buffer :
182
+ IfEquals<PathValueType, Schema.Types.UUID> extends true ? Buffer :
183
+ PathValueType extends MapConstructor ? Map<string, ResolvePathType<Options['of']>> :
184
+ PathValueType extends ArrayConstructor ? any[] :
185
+ PathValueType extends typeof Schema.Types.Mixed ? any:
186
+ IfEquals<PathValueType, ObjectConstructor> extends true ? any:
187
+ IfEquals<PathValueType, {}> extends true ? any:
188
+ PathValueType extends typeof SchemaType ? PathValueType['prototype'] :
189
+ PathValueType extends Record<string, any> ? ObtainDocumentType<PathValueType, any, TypeKey> :
190
+ unknown;
package/types/query.d.ts CHANGED
@@ -616,7 +616,7 @@ declare module 'mongoose' {
616
616
  then: Promise<ResultType>['then'];
617
617
 
618
618
  /** Converts this query to a customized, reusable query constructor with all arguments and options retained. */
619
- toConstructor(): typeof Query<ResultType, DocType, THelpers, RawDocType>;
619
+ toConstructor<RetType = typeof Query>(): RetType;
620
620
 
621
621
  /** Declare and/or execute this query as an update() operation. */
622
622
  update(filter?: FilterQuery<DocType>, update?: UpdateQuery<DocType> | UpdateWithAggregationPipeline, options?: QueryOptions<DocType> | null, callback?: Callback<UpdateWriteOpResult>): QueryWithHelpers<UpdateWriteOpResult, DocType, THelpers, RawDocType>;
Binary file