mongoose 8.20.0 → 8.20.2

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/document.js CHANGED
@@ -5422,6 +5422,38 @@ Document.prototype.$__hasOnlyPrimitiveValues = function $__hasOnlyPrimitiveValue
5422
5422
  }));
5423
5423
  };
5424
5424
 
5425
+ /*!
5426
+ * Increment this document's version if necessary.
5427
+ */
5428
+
5429
+ Document.prototype._applyVersionIncrement = function _applyVersionIncrement() {
5430
+ if (!this.$__.version) return;
5431
+ const doIncrement = VERSION_INC === (VERSION_INC & this.$__.version);
5432
+
5433
+ this.$__.version = undefined;
5434
+ if (doIncrement) {
5435
+ const key = this.$__schema.options.versionKey;
5436
+ const version = this.$__getValue(key) || 0;
5437
+ this.$__setValue(key, version + 1); // increment version if was successful
5438
+ }
5439
+ };
5440
+
5441
+ /*!
5442
+ * Increment this document's version if necessary.
5443
+ */
5444
+
5445
+ Document.prototype._applyVersionIncrement = function _applyVersionIncrement() {
5446
+ if (!this.$__.version) return;
5447
+ const doIncrement = VERSION_INC === (VERSION_INC & this.$__.version);
5448
+
5449
+ this.$__.version = undefined;
5450
+ if (doIncrement) {
5451
+ const key = this.$__schema.options.versionKey;
5452
+ const version = this.$__getValue(key) || 0;
5453
+ this.$__setValue(key, version + 1); // increment version if was successful
5454
+ }
5455
+ };
5456
+
5425
5457
  /*!
5426
5458
  * Module exports.
5427
5459
  */
@@ -118,7 +118,10 @@ module.exports.castUpdateOne = function castUpdateOne(originalModel, updateOne,
118
118
  if (model.schema.$timestamps != null && doInitTimestamps) {
119
119
  const createdAt = model.schema.$timestamps.createdAt;
120
120
  const updatedAt = model.schema.$timestamps.updatedAt;
121
- applyTimestampsToUpdate(now, createdAt, updatedAt, update, {});
121
+ applyTimestampsToUpdate(now, createdAt, updatedAt, update, {
122
+ timestamps: updateOne.timestamps,
123
+ overwriteImmutable: updateOne.overwriteImmutable
124
+ });
122
125
  }
123
126
 
124
127
  if (doInitTimestamps) {
@@ -150,7 +153,8 @@ module.exports.castUpdateOne = function castUpdateOne(originalModel, updateOne,
150
153
  strict: strict,
151
154
  upsert: updateOne.upsert,
152
155
  arrayFilters: updateOne.arrayFilters,
153
- overwriteDiscriminatorKey: updateOne.overwriteDiscriminatorKey
156
+ overwriteDiscriminatorKey: updateOne.overwriteDiscriminatorKey,
157
+ overwriteImmutable: updateOne.overwriteImmutable
154
158
  }, model, updateOne['filter']);
155
159
 
156
160
  return updateOne;
@@ -185,7 +189,10 @@ module.exports.castUpdateMany = function castUpdateMany(originalModel, updateMan
185
189
  if (model.schema.$timestamps != null && doInitTimestamps) {
186
190
  const createdAt = model.schema.$timestamps.createdAt;
187
191
  const updatedAt = model.schema.$timestamps.updatedAt;
188
- applyTimestampsToUpdate(now, createdAt, updatedAt, updateMany['update'], {});
192
+ applyTimestampsToUpdate(now, createdAt, updatedAt, updateMany['update'], {
193
+ timestamps: updateMany.timestamps,
194
+ overwriteImmutable: updateMany.overwriteImmutable
195
+ });
189
196
  }
190
197
  if (doInitTimestamps) {
191
198
  applyTimestampsToChildren(now, updateMany['update'], model.schema);
@@ -208,7 +215,8 @@ module.exports.castUpdateMany = function castUpdateMany(originalModel, updateMan
208
215
  strict: strict,
209
216
  upsert: updateMany.upsert,
210
217
  arrayFilters: updateMany.arrayFilters,
211
- overwriteDiscriminatorKey: updateMany.overwriteDiscriminatorKey
218
+ overwriteDiscriminatorKey: updateMany.overwriteDiscriminatorKey,
219
+ overwriteImmutable: updateMany.overwriteImmutable
212
220
  }, model, updateMany['filter']);
213
221
  };
214
222
 
@@ -295,7 +303,6 @@ function decideModelByObject(model, object) {
295
303
  return model;
296
304
  }
297
305
 
298
-
299
306
  /**
300
307
  * gets timestamps option for a given operation. If the option is set within an individual operation, use it. Otherwise, use the global timestamps option configured in the `bulkWrite` options. Overall default is `true`.
301
308
  * @api private
@@ -80,33 +80,46 @@ function applyTimestampsToUpdate(now, createdAt, updatedAt, currentUpdate, optio
80
80
  }
81
81
 
82
82
  if (!skipCreatedAt && createdAt) {
83
- if (currentUpdate[createdAt]) {
84
- delete currentUpdate[createdAt];
85
- }
86
- if (currentUpdate.$set && currentUpdate.$set[createdAt]) {
87
- delete currentUpdate.$set[createdAt];
88
- }
89
- let timestampSet = false;
90
- if (createdAt.indexOf('.') !== -1) {
91
- const pieces = createdAt.split('.');
92
- for (let i = 1; i < pieces.length; ++i) {
93
- const remnant = pieces.slice(-i).join('.');
94
- const start = pieces.slice(0, -i).join('.');
95
- if (currentUpdate[start] != null) {
96
- currentUpdate[start][remnant] = now;
97
- timestampSet = true;
98
- break;
99
- } else if (currentUpdate.$set && currentUpdate.$set[start]) {
100
- currentUpdate.$set[start][remnant] = now;
101
- timestampSet = true;
102
- break;
83
+ const overwriteImmutable = get(options, 'overwriteImmutable', false);
84
+ const hasUserCreatedAt = currentUpdate[createdAt] != null || currentUpdate?.$set[createdAt] != null;
85
+
86
+ // If overwriteImmutable is true and user provided createdAt, keep their value
87
+ if (overwriteImmutable && hasUserCreatedAt) {
88
+ // Move createdAt from top-level to $set if needed
89
+ if (currentUpdate[createdAt] != null) {
90
+ updates.$set[createdAt] = currentUpdate[createdAt];
91
+ delete currentUpdate[createdAt];
92
+ }
93
+ // User's value is already in $set, nothing more to do
94
+ } else {
95
+ if (currentUpdate[createdAt]) {
96
+ delete currentUpdate[createdAt];
97
+ }
98
+ if (currentUpdate.$set && currentUpdate.$set[createdAt]) {
99
+ delete currentUpdate.$set[createdAt];
100
+ }
101
+ let timestampSet = false;
102
+ if (createdAt.indexOf('.') !== -1) {
103
+ const pieces = createdAt.split('.');
104
+ for (let i = 1; i < pieces.length; ++i) {
105
+ const remnant = pieces.slice(-i).join('.');
106
+ const start = pieces.slice(0, -i).join('.');
107
+ if (currentUpdate[start] != null) {
108
+ currentUpdate[start][remnant] = now;
109
+ timestampSet = true;
110
+ break;
111
+ } else if (currentUpdate.$set && currentUpdate.$set[start]) {
112
+ currentUpdate.$set[start][remnant] = now;
113
+ timestampSet = true;
114
+ break;
115
+ }
103
116
  }
104
117
  }
105
- }
106
118
 
107
- if (!timestampSet) {
108
- updates.$setOnInsert = updates.$setOnInsert || {};
109
- updates.$setOnInsert[createdAt] = now;
119
+ if (!timestampSet) {
120
+ updates.$setOnInsert = updates.$setOnInsert || {};
121
+ updates.$setOnInsert[createdAt] = now;
122
+ }
110
123
  }
111
124
  }
112
125
 
package/lib/model.js CHANGED
@@ -523,11 +523,9 @@ Model.prototype.$__save = function(options, callback) {
523
523
  const versionBump = this.$__.version;
524
524
  // was this an update that required a version bump?
525
525
  if (versionBump && !this.$__.inserting) {
526
- const doIncrement = VERSION_INC === (VERSION_INC & this.$__.version);
527
- this.$__.version = undefined;
528
- const key = this.$__schema.options.versionKey;
529
- const version = this.$__getValue(key) || 0;
530
526
  if (numAffected <= 0) {
527
+ const key = this.$__schema.options.versionKey;
528
+ const version = this.$__getValue(key) || 0;
531
529
  // the update failed. pass an error back
532
530
  this.$__undoReset();
533
531
  const err = this.$__.$versionError ||
@@ -535,10 +533,7 @@ Model.prototype.$__save = function(options, callback) {
535
533
  return callback(err, this);
536
534
  }
537
535
 
538
- // increment version if was successful
539
- if (doIncrement) {
540
- this.$__setValue(key, version + 1);
541
- }
536
+ this._applyVersionIncrement();
542
537
  }
543
538
  if (result != null && numAffected <= 0) {
544
539
  this.$__undoReset();
@@ -3666,6 +3661,8 @@ function handleSuccessfulWrite(document) {
3666
3661
  }
3667
3662
 
3668
3663
  document.$__reset();
3664
+ document._applyVersionIncrement();
3665
+
3669
3666
  document.schema.s.hooks.execPost('save', document, [document], {}, (err) => {
3670
3667
  if (err) {
3671
3668
  reject(err);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "8.20.0",
4
+ "version": "8.20.2",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -55,7 +55,7 @@
55
55
  "lodash.isequal": "4.5.0",
56
56
  "lodash.isequalwith": "4.4.0",
57
57
  "markdownlint-cli2": "^0.18.1",
58
- "marked": "16.4.1",
58
+ "marked": "15.x",
59
59
  "mkdirp": "^3.0.1",
60
60
  "mocha": "11.7.4",
61
61
  "moment": "2.30.1",
@@ -91,6 +91,7 @@
91
91
  "docs:prepare:publish:5x": "git checkout 5.x && git merge 5.x && npm run docs:clean:stable && npm run docs:generate && npm run docs:copy:tmp && git checkout gh-pages && npm run docs:copy:tmp:5x",
92
92
  "docs:prepare:publish:6x": "git checkout 6.x && git merge 6.x && npm run docs:clean:stable && env DOCS_DEPLOY=true npm run docs:generate && mv ./docs/6.x ./tmp && git checkout gh-pages && npm run docs:copy:tmp:6x",
93
93
  "docs:prepare:publish:7x": "env DOCS_DEPLOY=true npm run docs:generate && git checkout gh-pages && rimraf ./docs/7.x && mv ./tmp ./docs/7.x",
94
+ "docs:prepare:publish:8x": "env DOCS_DEPLOY=true npm run docs:generate && git checkout gh-pages && rimraf ./docs/8.x && mv ./tmp ./docs/8.x",
94
95
  "docs:check-links": "blc http://127.0.0.1:8089 -ro",
95
96
  "lint": "eslint .",
96
97
  "lint-js": "eslint . --ext .js --ext .cjs",
package/types/index.d.ts CHANGED
@@ -542,6 +542,7 @@ declare module 'mongoose' {
542
542
 
543
543
  /** Adds static "class" methods to Models compiled from this schema. */
544
544
  static<K extends keyof TStaticMethods>(name: K, fn: TStaticMethods[K]): this;
545
+ static(obj: { [F in keyof TStaticMethods]: TStaticMethods[F] }): this;
545
546
  static(obj: { [F in keyof TStaticMethods]: TStaticMethods[F] } & { [name: string]: (this: TModelType, ...args: any[]) => any }): this;
546
547
  static(name: string, fn: (this: TModelType, ...args: any[]) => any): this;
547
548
 
package/types/models.d.ts CHANGED
@@ -172,94 +172,47 @@ declare module 'mongoose' {
172
172
 
173
173
  interface RemoveOptions extends SessionOption, Omit<mongodb.DeleteOptions, 'session'> {}
174
174
 
175
- const Model: Model<any>;
176
-
177
- export type AnyBulkWriteOperation<TSchema = AnyObject> = {
178
- insertOne: InsertOneModel<TSchema>;
179
- } | {
180
- replaceOne: ReplaceOneModel<TSchema>;
181
- } | {
182
- updateOne: UpdateOneModel<TSchema>;
183
- } | {
184
- updateMany: UpdateManyModel<TSchema>;
185
- } | {
186
- deleteOne: DeleteOneModel<TSchema>;
187
- } | {
188
- deleteMany: DeleteManyModel<TSchema>;
189
- };
190
-
191
- export interface InsertOneModel<TSchema> {
192
- document: mongodb.OptionalId<TSchema>;
175
+ interface MongooseBulkWritePerOperationOptions {
176
+ /** Skip validation for this operation. */
177
+ skipValidation?: boolean;
193
178
  /** When false, do not add timestamps. When true, overrides the `timestamps` option set in the `bulkWrite` options. */
194
179
  timestamps?: boolean;
195
180
  }
196
181
 
197
- export interface ReplaceOneModel<TSchema = AnyObject> {
198
- /** The filter to limit the replaced document. */
199
- filter: RootFilterQuery<TSchema>;
200
- /** The document with which to replace the matched document. */
201
- replacement: mongodb.WithoutId<TSchema>;
202
- /** Specifies a collation. */
203
- collation?: mongodb.CollationOptions;
204
- /** The index to use. If specified, then the query system will only consider plans using the hinted index. */
205
- hint?: mongodb.Hint;
206
- /** When true, creates a new document if no document matches the query. */
207
- upsert?: boolean;
208
- /** When false, do not add timestamps. When true, overrides the `timestamps` option set in the `bulkWrite` options. */
209
- timestamps?: boolean;
182
+ interface MongooseBulkUpdatePerOperationOptions extends MongooseBulkWritePerOperationOptions {
183
+ /** When true, allows updating fields that are marked as `immutable` in the schema. */
184
+ overwriteImmutable?: boolean;
185
+ /** When false, do not set default values on insert. */
186
+ setDefaultsOnInsert?: boolean;
210
187
  }
211
188
 
212
- export interface UpdateOneModel<TSchema = AnyObject> {
213
- /** The filter to limit the updated documents. */
214
- filter: RootFilterQuery<TSchema>;
215
- /** A document or pipeline containing update operators. */
216
- update: UpdateQuery<TSchema>;
217
- /** A set of filters specifying to which array elements an update should apply. */
218
- arrayFilters?: AnyObject[];
219
- /** Specifies a collation. */
220
- collation?: mongodb.CollationOptions;
221
- /** The index to use. If specified, then the query system will only consider plans using the hinted index. */
222
- hint?: mongodb.Hint;
223
- /** When true, creates a new document if no document matches the query. */
224
- upsert?: boolean;
225
- /** When false, do not add timestamps. When true, overrides the `timestamps` option set in the `bulkWrite` options. */
226
- timestamps?: boolean;
227
- }
189
+ export type InsertOneModel<TSchema extends mongodb.Document = mongodb.Document> =
190
+ mongodb.InsertOneModel<TSchema> & MongooseBulkWritePerOperationOptions;
228
191
 
229
- export interface UpdateManyModel<TSchema = AnyObject> {
230
- /** The filter to limit the updated documents. */
231
- filter: RootFilterQuery<TSchema>;
232
- /** A document or pipeline containing update operators. */
233
- update: UpdateQuery<TSchema>;
234
- /** A set of filters specifying to which array elements an update should apply. */
235
- arrayFilters?: AnyObject[];
236
- /** Specifies a collation. */
237
- collation?: mongodb.CollationOptions;
238
- /** The index to use. If specified, then the query system will only consider plans using the hinted index. */
239
- hint?: mongodb.Hint;
240
- /** When true, creates a new document if no document matches the query. */
241
- upsert?: boolean;
242
- /** When false, do not add timestamps. When true, overrides the `timestamps` option set in the `bulkWrite` options. */
243
- timestamps?: boolean;
244
- }
192
+ export type ReplaceOneModel<TSchema extends mongodb.Document = mongodb.Document> =
193
+ mongodb.ReplaceOneModel<TSchema> & MongooseBulkWritePerOperationOptions;
245
194
 
246
- export interface DeleteOneModel<TSchema = AnyObject> {
247
- /** The filter to limit the deleted documents. */
248
- filter: RootFilterQuery<TSchema>;
249
- /** Specifies a collation. */
250
- collation?: mongodb.CollationOptions;
251
- /** The index to use. If specified, then the query system will only consider plans using the hinted index. */
252
- hint?: mongodb.Hint;
253
- }
195
+ export type UpdateOneModel<TSchema extends mongodb.Document = mongodb.Document> =
196
+ mongodb.UpdateOneModel<TSchema> & MongooseBulkUpdatePerOperationOptions;
254
197
 
255
- export interface DeleteManyModel<TSchema = AnyObject> {
256
- /** The filter to limit the deleted documents. */
257
- filter: RootFilterQuery<TSchema>;
258
- /** Specifies a collation. */
259
- collation?: mongodb.CollationOptions;
260
- /** The index to use. If specified, then the query system will only consider plans using the hinted index. */
261
- hint?: mongodb.Hint;
262
- }
198
+ export type UpdateManyModel<TSchema extends mongodb.Document = mongodb.Document> =
199
+ mongodb.UpdateManyModel<TSchema> & MongooseBulkUpdatePerOperationOptions;
200
+
201
+ export type DeleteOneModel<TSchema extends mongodb.Document = mongodb.Document> =
202
+ mongodb.DeleteOneModel<TSchema>;
203
+
204
+ export type DeleteManyModel<TSchema extends mongodb.Document = mongodb.Document> =
205
+ mongodb.DeleteManyModel<TSchema>;
206
+
207
+ export type AnyBulkWriteOperation<TSchema extends mongodb.Document = mongodb.Document> =
208
+ | { insertOne: InsertOneModel<TSchema> }
209
+ | { replaceOne: ReplaceOneModel<TSchema> }
210
+ | { updateOne: UpdateOneModel<TSchema> }
211
+ | { updateMany: UpdateManyModel<TSchema> }
212
+ | { deleteOne: DeleteOneModel<TSchema> }
213
+ | { deleteMany: DeleteManyModel<TSchema> };
214
+
215
+ const Model: Model<any>;
263
216
 
264
217
  type HasLeanOption<TSchema> = 'lean' extends keyof ObtainSchemaGeneric<TSchema, 'TSchemaOptions'> ?
265
218
  ObtainSchemaGeneric<TSchema, 'TSchemaOptions'>['lean'] extends Record<string, any> ?
@@ -319,13 +272,13 @@ declare module 'mongoose' {
319
272
  * round trip to the MongoDB server.
320
273
  */
321
274
  bulkWrite<DocContents = TRawDocType>(
322
- writes: Array<AnyBulkWriteOperation<DocContents>>,
323
- options: MongooseBulkWriteOptions & { ordered: false }
324
- ): Promise<MongooseBulkWriteResult>;
275
+ writes: Array<AnyBulkWriteOperation<DocContents extends mongodb.Document ? DocContents : any>>,
276
+ options: mongodb.BulkWriteOptions & MongooseBulkWriteOptions & { ordered: false }
277
+ ): Promise<mongodb.BulkWriteResult & { mongoose?: { validationErrors: Error[] } }>;
325
278
  bulkWrite<DocContents = TRawDocType>(
326
- writes: Array<AnyBulkWriteOperation<DocContents>>,
327
- options?: MongooseBulkWriteOptions
328
- ): Promise<MongooseBulkWriteResult>;
279
+ writes: Array<AnyBulkWriteOperation<DocContents extends mongodb.Document ? DocContents : any>>,
280
+ options?: mongodb.BulkWriteOptions & MongooseBulkWriteOptions
281
+ ): Promise<mongodb.BulkWriteResult>;
329
282
 
330
283
  /**
331
284
  * Sends multiple `save()` calls in a single `bulkWrite()`. This is faster than