mongoose 8.8.4 → 8.9.0

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.
@@ -23,234 +23,47 @@ const setDefaultsOnInsert = require('../setDefaultsOnInsert');
23
23
  module.exports = function castBulkWrite(originalModel, op, options) {
24
24
  const now = originalModel.base.now();
25
25
 
26
- const globalSetDefaultsOnInsert = originalModel.base.options.setDefaultsOnInsert;
27
26
  if (op['insertOne']) {
28
- return (callback) => {
29
- const model = decideModelByObject(originalModel, op['insertOne']['document']);
30
-
31
- const doc = new model(op['insertOne']['document']);
32
- if (model.schema.options.timestamps && getTimestampsOpt(op['insertOne'], options)) {
33
- doc.initializeTimestamps();
34
- }
35
- if (options.session != null) {
36
- doc.$session(options.session);
37
- }
38
- const versionKey = model?.schema?.options?.versionKey;
39
- if (versionKey && doc[versionKey] == null) {
40
- doc[versionKey] = 0;
41
- }
42
- op['insertOne']['document'] = doc;
43
-
44
- if (options.skipValidation || op['insertOne'].skipValidation) {
45
- callback(null);
46
- return;
47
- }
48
-
49
- op['insertOne']['document'].$validate().then(
50
- () => { callback(null); },
51
- err => { callback(err, null); }
52
- );
53
- };
27
+ return callback => module.exports.castInsertOne(originalModel, op['insertOne'], options).then(() => callback(null), err => callback(err));
54
28
  } else if (op['updateOne']) {
55
29
  return (callback) => {
56
30
  try {
57
- if (!op['updateOne']['filter']) {
58
- throw new Error('Must provide a filter object.');
59
- }
60
- if (!op['updateOne']['update']) {
61
- throw new Error('Must provide an update object.');
62
- }
63
-
64
- const model = decideModelByObject(originalModel, op['updateOne']['filter']);
65
- const schema = model.schema;
66
- const strict = options.strict != null ? options.strict : model.schema.options.strict;
67
-
68
- const update = clone(op['updateOne']['update']);
69
-
70
- _addDiscriminatorToObject(schema, op['updateOne']['filter']);
71
-
72
- const doInitTimestamps = getTimestampsOpt(op['updateOne'], options);
73
-
74
- if (model.schema.$timestamps != null && doInitTimestamps) {
75
- const createdAt = model.schema.$timestamps.createdAt;
76
- const updatedAt = model.schema.$timestamps.updatedAt;
77
- applyTimestampsToUpdate(now, createdAt, updatedAt, update, {});
78
- }
79
-
80
- if (doInitTimestamps) {
81
- applyTimestampsToChildren(now, update, model.schema);
82
- }
83
-
84
- const shouldSetDefaultsOnInsert = op['updateOne'].setDefaultsOnInsert == null ?
85
- globalSetDefaultsOnInsert :
86
- op['updateOne'].setDefaultsOnInsert;
87
- if (shouldSetDefaultsOnInsert !== false) {
88
- setDefaultsOnInsert(op['updateOne']['filter'], model.schema, update, {
89
- setDefaultsOnInsert: true,
90
- upsert: op['updateOne'].upsert
91
- });
92
- }
93
-
94
- decorateUpdateWithVersionKey(
95
- update,
96
- op['updateOne'],
97
- model.schema.options.versionKey
98
- );
99
-
100
- op['updateOne']['filter'] = cast(model.schema, op['updateOne']['filter'], {
101
- strict: strict,
102
- upsert: op['updateOne'].upsert
103
- });
104
- op['updateOne']['update'] = castUpdate(model.schema, update, {
105
- strict: strict,
106
- upsert: op['updateOne'].upsert,
107
- arrayFilters: op['updateOne'].arrayFilters,
108
- overwriteDiscriminatorKey: op['updateOne'].overwriteDiscriminatorKey
109
- }, model, op['updateOne']['filter']);
110
- } catch (error) {
111
- return callback(error, null);
31
+ module.exports.castUpdateOne(originalModel, op['updateOne'], options, now);
32
+ callback(null);
33
+ } catch (err) {
34
+ callback(err);
112
35
  }
113
-
114
- callback(null);
115
36
  };
116
37
  } else if (op['updateMany']) {
117
38
  return (callback) => {
118
39
  try {
119
- if (!op['updateMany']['filter']) {
120
- throw new Error('Must provide a filter object.');
121
- }
122
- if (!op['updateMany']['update']) {
123
- throw new Error('Must provide an update object.');
124
- }
125
-
126
- const model = decideModelByObject(originalModel, op['updateMany']['filter']);
127
- const schema = model.schema;
128
- const strict = options.strict != null ? options.strict : model.schema.options.strict;
129
-
130
- const shouldSetDefaultsOnInsert = op['updateMany'].setDefaultsOnInsert == null ?
131
- globalSetDefaultsOnInsert :
132
- op['updateMany'].setDefaultsOnInsert;
133
-
134
- if (shouldSetDefaultsOnInsert !== false) {
135
- setDefaultsOnInsert(op['updateMany']['filter'], model.schema, op['updateMany']['update'], {
136
- setDefaultsOnInsert: true,
137
- upsert: op['updateMany'].upsert
138
- });
139
- }
140
-
141
- const doInitTimestamps = getTimestampsOpt(op['updateMany'], options);
142
-
143
- if (model.schema.$timestamps != null && doInitTimestamps) {
144
- const createdAt = model.schema.$timestamps.createdAt;
145
- const updatedAt = model.schema.$timestamps.updatedAt;
146
- applyTimestampsToUpdate(now, createdAt, updatedAt, op['updateMany']['update'], {});
147
- }
148
- if (doInitTimestamps) {
149
- applyTimestampsToChildren(now, op['updateMany']['update'], model.schema);
150
- }
151
-
152
- _addDiscriminatorToObject(schema, op['updateMany']['filter']);
153
-
154
- decorateUpdateWithVersionKey(
155
- op['updateMany']['update'],
156
- op['updateMany'],
157
- model.schema.options.versionKey
158
- );
159
-
160
- op['updateMany']['filter'] = cast(model.schema, op['updateMany']['filter'], {
161
- strict: strict,
162
- upsert: op['updateMany'].upsert
163
- });
164
-
165
- op['updateMany']['update'] = castUpdate(model.schema, op['updateMany']['update'], {
166
- strict: strict,
167
- upsert: op['updateMany'].upsert,
168
- arrayFilters: op['updateMany'].arrayFilters,
169
- overwriteDiscriminatorKey: op['updateMany'].overwriteDiscriminatorKey
170
- }, model, op['updateMany']['filter']);
171
- } catch (error) {
172
- return callback(error, null);
40
+ module.exports.castUpdateMany(originalModel, op['updateMany'], options, now);
41
+ callback(null);
42
+ } catch (err) {
43
+ callback(err);
173
44
  }
174
-
175
- callback(null);
176
45
  };
177
46
  } else if (op['replaceOne']) {
178
47
  return (callback) => {
179
- const model = decideModelByObject(originalModel, op['replaceOne']['filter']);
180
- const schema = model.schema;
181
- const strict = options.strict != null ? options.strict : model.schema.options.strict;
182
-
183
- _addDiscriminatorToObject(schema, op['replaceOne']['filter']);
184
- try {
185
- op['replaceOne']['filter'] = cast(model.schema, op['replaceOne']['filter'], {
186
- strict: strict,
187
- upsert: op['replaceOne'].upsert
188
- });
189
- } catch (error) {
190
- return callback(error, null);
191
- }
192
-
193
- // set `skipId`, otherwise we get "_id field cannot be changed"
194
- const doc = new model(op['replaceOne']['replacement'], strict, true);
195
- if (model.schema.options.timestamps && getTimestampsOpt(op['replaceOne'], options)) {
196
- doc.initializeTimestamps();
197
- }
198
- if (options.session != null) {
199
- doc.$session(options.session);
200
- }
201
- const versionKey = model?.schema?.options?.versionKey;
202
- if (versionKey && doc[versionKey] == null) {
203
- doc[versionKey] = 0;
204
- }
205
- op['replaceOne']['replacement'] = doc;
206
-
207
- if (options.skipValidation || op['replaceOne'].skipValidation) {
208
- op['replaceOne']['replacement'] = op['replaceOne']['replacement'].toBSON();
209
- callback(null);
210
- return;
211
- }
212
-
213
- op['replaceOne']['replacement'].$validate().then(
214
- () => {
215
- op['replaceOne']['replacement'] = op['replaceOne']['replacement'].toBSON();
216
- callback(null);
217
- },
218
- error => {
219
- callback(error, null);
220
- }
221
- );
48
+ module.exports.castReplaceOne(originalModel, op['replaceOne'], options).then(() => callback(null), err => callback(err));
222
49
  };
223
50
  } else if (op['deleteOne']) {
224
51
  return (callback) => {
225
- const model = decideModelByObject(originalModel, op['deleteOne']['filter']);
226
- const schema = model.schema;
227
-
228
- _addDiscriminatorToObject(schema, op['deleteOne']['filter']);
229
-
230
52
  try {
231
- op['deleteOne']['filter'] = cast(model.schema,
232
- op['deleteOne']['filter']);
233
- } catch (error) {
234
- return callback(error, null);
53
+ module.exports.castDeleteOne(originalModel, op['deleteOne']);
54
+ callback(null);
55
+ } catch (err) {
56
+ callback(err);
235
57
  }
236
-
237
- callback(null);
238
58
  };
239
59
  } else if (op['deleteMany']) {
240
60
  return (callback) => {
241
- const model = decideModelByObject(originalModel, op['deleteMany']['filter']);
242
- const schema = model.schema;
243
-
244
- _addDiscriminatorToObject(schema, op['deleteMany']['filter']);
245
-
246
61
  try {
247
- op['deleteMany']['filter'] = cast(model.schema,
248
- op['deleteMany']['filter']);
249
- } catch (error) {
250
- return callback(error, null);
62
+ module.exports.castDeleteMany(originalModel, op['deleteMany']);
63
+ callback(null);
64
+ } catch (err) {
65
+ callback(err);
251
66
  }
252
-
253
- callback(null);
254
67
  };
255
68
  } else {
256
69
  return (callback) => {
@@ -260,6 +73,206 @@ module.exports = function castBulkWrite(originalModel, op, options) {
260
73
  }
261
74
  };
262
75
 
76
+ module.exports.castInsertOne = async function castInsertOne(originalModel, insertOne, options) {
77
+ const model = decideModelByObject(originalModel, insertOne['document']);
78
+
79
+ const doc = new model(insertOne['document']);
80
+ if (model.schema.options.timestamps && getTimestampsOpt(insertOne, options)) {
81
+ doc.initializeTimestamps();
82
+ }
83
+ if (options.session != null) {
84
+ doc.$session(options.session);
85
+ }
86
+ const versionKey = model?.schema?.options?.versionKey;
87
+ if (versionKey && doc[versionKey] == null) {
88
+ doc[versionKey] = 0;
89
+ }
90
+ insertOne['document'] = doc;
91
+
92
+ if (options.skipValidation || insertOne.skipValidation) {
93
+ return insertOne;
94
+ }
95
+
96
+ await insertOne['document'].$validate();
97
+ return insertOne;
98
+ };
99
+
100
+ module.exports.castUpdateOne = function castUpdateOne(originalModel, updateOne, options, now) {
101
+ if (!updateOne['filter']) {
102
+ throw new Error('Must provide a filter object.');
103
+ }
104
+ if (!updateOne['update']) {
105
+ throw new Error('Must provide an update object.');
106
+ }
107
+
108
+ const model = decideModelByObject(originalModel, updateOne['filter']);
109
+ const schema = model.schema;
110
+ const strict = options.strict != null ? options.strict : model.schema.options.strict;
111
+
112
+ const update = clone(updateOne['update']);
113
+
114
+ _addDiscriminatorToObject(schema, updateOne['filter']);
115
+
116
+ const doInitTimestamps = getTimestampsOpt(updateOne, options);
117
+
118
+ if (model.schema.$timestamps != null && doInitTimestamps) {
119
+ const createdAt = model.schema.$timestamps.createdAt;
120
+ const updatedAt = model.schema.$timestamps.updatedAt;
121
+ applyTimestampsToUpdate(now, createdAt, updatedAt, update, {});
122
+ }
123
+
124
+ if (doInitTimestamps) {
125
+ applyTimestampsToChildren(now, update, model.schema);
126
+ }
127
+
128
+ const globalSetDefaultsOnInsert = originalModel.base.options.setDefaultsOnInsert;
129
+ const shouldSetDefaultsOnInsert = updateOne.setDefaultsOnInsert == null ?
130
+ globalSetDefaultsOnInsert :
131
+ updateOne.setDefaultsOnInsert;
132
+ if (shouldSetDefaultsOnInsert !== false) {
133
+ setDefaultsOnInsert(updateOne['filter'], model.schema, update, {
134
+ setDefaultsOnInsert: true,
135
+ upsert: updateOne.upsert
136
+ });
137
+ }
138
+
139
+ decorateUpdateWithVersionKey(
140
+ update,
141
+ updateOne,
142
+ model.schema.options.versionKey
143
+ );
144
+
145
+ updateOne['filter'] = cast(model.schema, updateOne['filter'], {
146
+ strict: strict,
147
+ upsert: updateOne.upsert
148
+ });
149
+ updateOne['update'] = castUpdate(model.schema, update, {
150
+ strict: strict,
151
+ upsert: updateOne.upsert,
152
+ arrayFilters: updateOne.arrayFilters,
153
+ overwriteDiscriminatorKey: updateOne.overwriteDiscriminatorKey
154
+ }, model, updateOne['filter']);
155
+
156
+ return updateOne;
157
+ };
158
+
159
+ module.exports.castUpdateMany = function castUpdateMany(originalModel, updateMany, options, now) {
160
+ if (!updateMany['filter']) {
161
+ throw new Error('Must provide a filter object.');
162
+ }
163
+ if (!updateMany['update']) {
164
+ throw new Error('Must provide an update object.');
165
+ }
166
+
167
+ const model = decideModelByObject(originalModel, updateMany['filter']);
168
+ const schema = model.schema;
169
+ const strict = options.strict != null ? options.strict : model.schema.options.strict;
170
+
171
+ const globalSetDefaultsOnInsert = originalModel.base.options.setDefaultsOnInsert;
172
+ const shouldSetDefaultsOnInsert = updateMany.setDefaultsOnInsert == null ?
173
+ globalSetDefaultsOnInsert :
174
+ updateMany.setDefaultsOnInsert;
175
+
176
+ if (shouldSetDefaultsOnInsert !== false) {
177
+ setDefaultsOnInsert(updateMany['filter'], model.schema, updateMany['update'], {
178
+ setDefaultsOnInsert: true,
179
+ upsert: updateMany.upsert
180
+ });
181
+ }
182
+
183
+ const doInitTimestamps = getTimestampsOpt(updateMany, options);
184
+
185
+ if (model.schema.$timestamps != null && doInitTimestamps) {
186
+ const createdAt = model.schema.$timestamps.createdAt;
187
+ const updatedAt = model.schema.$timestamps.updatedAt;
188
+ applyTimestampsToUpdate(now, createdAt, updatedAt, updateMany['update'], {});
189
+ }
190
+ if (doInitTimestamps) {
191
+ applyTimestampsToChildren(now, updateMany['update'], model.schema);
192
+ }
193
+
194
+ _addDiscriminatorToObject(schema, updateMany['filter']);
195
+
196
+ decorateUpdateWithVersionKey(
197
+ updateMany['update'],
198
+ updateMany,
199
+ model.schema.options.versionKey
200
+ );
201
+
202
+ updateMany['filter'] = cast(model.schema, updateMany['filter'], {
203
+ strict: strict,
204
+ upsert: updateMany.upsert
205
+ });
206
+
207
+ updateMany['update'] = castUpdate(model.schema, updateMany['update'], {
208
+ strict: strict,
209
+ upsert: updateMany.upsert,
210
+ arrayFilters: updateMany.arrayFilters,
211
+ overwriteDiscriminatorKey: updateMany.overwriteDiscriminatorKey
212
+ }, model, updateMany['filter']);
213
+ };
214
+
215
+ module.exports.castReplaceOne = async function castReplaceOne(originalModel, replaceOne, options) {
216
+ const model = decideModelByObject(originalModel, replaceOne['filter']);
217
+ const schema = model.schema;
218
+ const strict = options.strict != null ? options.strict : model.schema.options.strict;
219
+
220
+ _addDiscriminatorToObject(schema, replaceOne['filter']);
221
+ replaceOne['filter'] = cast(model.schema, replaceOne['filter'], {
222
+ strict: strict,
223
+ upsert: replaceOne.upsert
224
+ });
225
+
226
+ // set `skipId`, otherwise we get "_id field cannot be changed"
227
+ const doc = new model(replaceOne['replacement'], strict, true);
228
+ if (model.schema.options.timestamps && getTimestampsOpt(replaceOne, options)) {
229
+ doc.initializeTimestamps();
230
+ }
231
+ if (options.session != null) {
232
+ doc.$session(options.session);
233
+ }
234
+ const versionKey = model?.schema?.options?.versionKey;
235
+ if (versionKey && doc[versionKey] == null) {
236
+ doc[versionKey] = 0;
237
+ }
238
+ replaceOne['replacement'] = doc;
239
+
240
+ if (options.skipValidation || replaceOne.skipValidation) {
241
+ replaceOne['replacement'] = replaceOne['replacement'].toBSON();
242
+ return;
243
+ }
244
+
245
+ await replaceOne['replacement'].$validate();
246
+ replaceOne['replacement'] = replaceOne['replacement'].toBSON();
247
+ };
248
+
249
+ module.exports.castDeleteOne = function castDeleteOne(originalModel, deleteOne) {
250
+ const model = decideModelByObject(originalModel, deleteOne['filter']);
251
+ const schema = model.schema;
252
+
253
+ _addDiscriminatorToObject(schema, deleteOne['filter']);
254
+
255
+ deleteOne['filter'] = cast(model.schema, deleteOne['filter']);
256
+ };
257
+
258
+ module.exports.castDeleteMany = function castDeleteMany(originalModel, deleteMany) {
259
+ const model = decideModelByObject(originalModel, deleteMany['filter']);
260
+ const schema = model.schema;
261
+
262
+ _addDiscriminatorToObject(schema, deleteMany['filter']);
263
+
264
+ deleteMany['filter'] = cast(model.schema, deleteMany['filter']);
265
+ };
266
+
267
+ module.exports.cast = {
268
+ insertOne: module.exports.castInsertOne,
269
+ updateOne: module.exports.castUpdateOne,
270
+ updateMany: module.exports.castUpdateMany,
271
+ replaceOne: module.exports.castReplaceOne,
272
+ deleteOne: module.exports.castDeleteOne,
273
+ deleteMany: module.exports.castDeleteMany
274
+ };
275
+
263
276
  function _addDiscriminatorToObject(schema, obj) {
264
277
  if (schema == null) {
265
278
  return;
@@ -54,6 +54,13 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
54
54
  doc = docs[i];
55
55
  let justOne = null;
56
56
 
57
+ if (doc.$__ != null && doc.populated(options.path)) {
58
+ const forceRepopulate = options.forceRepopulate != null ? options.forceRepopulate : doc.constructor.base.options.forceRepopulate;
59
+ if (forceRepopulate === false) {
60
+ continue;
61
+ }
62
+ }
63
+
57
64
  const docSchema = doc != null && doc.$__ != null ? doc.$__schema : modelSchema;
58
65
  schema = getSchemaTypes(model, docSchema, doc, options.path);
59
66
 
@@ -39,6 +39,11 @@ module.exports = function getIndexes(schema) {
39
39
  continue;
40
40
  }
41
41
 
42
+ if (path._duplicateKeyErrorMessage != null) {
43
+ schema._duplicateKeyErrorMessagesByPath = schema._duplicateKeyErrorMessagesByPath || {};
44
+ schema._duplicateKeyErrorMessagesByPath[key] = path._duplicateKeyErrorMessage;
45
+ }
46
+
42
47
  if (path.$isMongooseDocumentArray || path.$isSingleNested) {
43
48
  if (get(path, 'options.excludeIndexes') !== true &&
44
49
  get(path, 'schemaOptions.excludeIndexes') !== true &&