Skip to content

Commit 62ab149

Browse files
committed
Merge branch 'master' into 8.10
2 parents 81e1bbb + ad10f48 commit 62ab149

File tree

8 files changed

+71
-32
lines changed

8 files changed

+71
-32
lines changed

lib/model.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3540,6 +3540,7 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
35403540
* @param {String|number} [options.w=1] The [write concern](https://www.mongodb.com/docs/manual/reference/write-concern/). See [`Query#w()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.w()) for more information.
35413541
* @param {number} [options.wtimeout=null] The [write concern timeout](https://www.mongodb.com/docs/manual/reference/write-concern/#wtimeout).
35423542
* @param {Boolean} [options.j=true] If false, disable [journal acknowledgement](https://www.mongodb.com/docs/manual/reference/write-concern/#j-option)
3543+
* @param {Boolean} [options.validateBeforeSave=true] set to `false` to skip Mongoose validation on all documents
35433544
* @return {BulkWriteResult} the return value from `bulkWrite()`
35443545
*/
35453546
Model.bulkSave = async function bulkSave(documents, options) {
@@ -3559,15 +3560,13 @@ Model.bulkSave = async function bulkSave(documents, options) {
35593560
}
35603561
}
35613562

3562-
await Promise.all(documents.map(buildPreSavePromise));
3563+
await Promise.all(documents.map(doc => buildPreSavePromise(doc, options)));
35633564

35643565
const writeOperations = this.buildBulkWriteOperations(documents, { skipValidation: true, timestamps: options.timestamps });
3565-
3566-
const { bulkWriteResult, bulkWriteError } = await this.bulkWrite(writeOperations, options).then(
3566+
const { bulkWriteResult, bulkWriteError } = await this.bulkWrite(writeOperations, { skipValidation: true, ...options }).then(
35673567
(res) => ({ bulkWriteResult: res, bulkWriteError: null }),
35683568
(err) => ({ bulkWriteResult: null, bulkWriteError: err })
35693569
);
3570-
35713570
// If not a MongoBulkWriteError, treat this as all documents failed to save.
35723571
if (bulkWriteError != null && !(bulkWriteError instanceof MongoBulkWriteError)) {
35733572
throw bulkWriteError;
@@ -3595,7 +3594,6 @@ Model.bulkSave = async function bulkSave(documents, options) {
35953594
successfulDocuments.push(document);
35963595
}
35973596
}
3598-
35993597
await Promise.all(successfulDocuments.map(document => handleSuccessfulWrite(document)));
36003598

36013599
if (bulkWriteError && bulkWriteError.writeErrors && bulkWriteError.writeErrors.length) {
@@ -3605,9 +3603,9 @@ Model.bulkSave = async function bulkSave(documents, options) {
36053603
return bulkWriteResult;
36063604
};
36073605

3608-
function buildPreSavePromise(document) {
3606+
function buildPreSavePromise(document, options) {
36093607
return new Promise((resolve, reject) => {
3610-
document.schema.s.hooks.execPre('save', document, (err) => {
3608+
document.schema.s.hooks.execPre('save', document, [options], (err) => {
36113609
if (err) {
36123610
reject(err);
36133611
return;

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@
3030
"devDependencies": {
3131
"@babel/core": "7.26.0",
3232
"@babel/preset-env": "7.26.0",
33-
"@typescript-eslint/eslint-plugin": "8.18.0",
34-
"@typescript-eslint/parser": "8.18.0",
33+
"@typescript-eslint/eslint-plugin": "^8.19.1",
34+
"@typescript-eslint/parser": "^8.19.1",
3535
"acquit": "1.3.0",
3636
"acquit-ignore": "0.2.1",
3737
"acquit-require": "0.1.1",
@@ -42,8 +42,8 @@
4242
"cheerio": "1.0.0",
4343
"crypto-browserify": "3.12.1",
4444
"dox": "1.0.0",
45-
"eslint": "8.57.0",
46-
"eslint-plugin-markdown": "^5.0.0",
45+
"eslint": "8.57.1",
46+
"eslint-plugin-markdown": "^5.1.0",
4747
"eslint-plugin-mocha-no-only": "1.2.0",
4848
"express": "^4.19.2",
4949
"fs-extra": "~11.2.0",

scripts/website.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -164,11 +164,11 @@ function moveDocsToTemp() {
164164
}
165165
}
166166

167-
/**
167+
/**
168168
* Array of array of semver numbers, sorted with highest number first
169169
* @example
170170
* [[1,2,3], [0,1,2]]
171-
* @type {number[][]}
171+
* @type {number[][]}
172172
*/
173173
let filteredTags = [];
174174

@@ -238,16 +238,16 @@ function getVersions() {
238238
* Stringify a semver number array
239239
* @param {number[]} arr The array to stringify
240240
* @param {boolean} dotX If "true", return "5.X" instead of "5.5.5"
241-
* @returns
241+
* @returns
242242
*/
243243
function stringifySemverNumber(arr, dotX) {
244244
if (dotX) {
245-
return `${arr[0]}.x`;
245+
return `${arr[0]}.x`;
246246
}
247247
return `${arr[0]}.${arr[1]}.${arr[2]}`;
248248
}
249249

250-
/**
250+
/**
251251
* Get the latest version available
252252
* @returns {Version}
253253
*/
@@ -422,7 +422,7 @@ function mapURLs(block, currentUrl) {
422422
* @param {String} filename The documentation file path to render
423423
* @param {import("../docs/source/index").DocsOptions} options The options to use to render the file (api may be overwritten at reload)
424424
* @param {Boolean} isReload Indicate this is a reload of the file
425-
* @returns
425+
* @returns
426426
*/
427427
async function pugify(filename, options, isReload = false) {
428428
/** Path for the output file */
@@ -502,7 +502,7 @@ async function pugify(filename, options, isReload = false) {
502502
}
503503

504504
str = mapURLs(str, '/' + path.relative(cwd, docsPath))
505-
505+
506506
await fs.promises.writeFile(newfile, str).catch((err) => {
507507
console.error('could not write', err.stack);
508508
}).then(() => {
@@ -624,5 +624,5 @@ function createSlug(value) {
624624
return '';
625625
}
626626
value = value.toLowerCase();
627-
return value.replace(/[^a-z0-9-_\s]/, '').replace(/ /g, '-');
628-
}
627+
return value.replace(/<\/?code>/g, '').replace(/[^a-z0-9-_\s]/g, '').replace(/ /g, '-');
628+
}

test/document.test.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -625,12 +625,12 @@ describe('document', function() {
625625
assert.equal(doc.val, 'test2');
626626
});
627627

628-
it('allows you to skip validation on save (gh-2981)', function() {
628+
it('allows you to skip validation on save (gh-2981)', async function() {
629629
const schema = new Schema({ name: { type: String, required: true } });
630630
const MyModel = db.model('Test', schema);
631631

632632
const doc = new MyModel();
633-
return doc.save({ validateBeforeSave: false });
633+
await doc.save({ validateBeforeSave: false });
634634
});
635635

636636
it('doesnt use custom toObject options on save', async function() {
@@ -12752,6 +12752,16 @@ describe('document', function() {
1275212752
assert.equal(updatedPerson?._age, 61);
1275312753
});
1275412754

12755+
it('bulkSave() allows skipping validation with validateBeforeSave (gh-15156)', async() => {
12756+
const schema = new Schema({ name: { type: String, required: true } });
12757+
const MyModel = db.model('Test', schema);
12758+
12759+
const doc = new MyModel();
12760+
await MyModel.bulkSave([doc], { validateBeforeSave: false });
12761+
12762+
assert.ok(await MyModel.exists({ _id: doc._id }));
12763+
});
12764+
1275512765
it('handles default embedded discriminator values (gh-13835)', async function() {
1275612766
const childAbstractSchema = new Schema(
1275712767
{ kind: { type: Schema.Types.String, enum: ['concreteKind'], required: true, default: 'concreteKind' } },

test/types/lean.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,3 +323,29 @@ async function gh15122() {
323323
testFn(parentDoc);
324324
}
325325
}
326+
327+
async function gh15158() {
328+
type FooBar = {
329+
value: string;
330+
};
331+
332+
const createSomeModelAndDoSomething = async <T extends FooBar>() => {
333+
const TestSchema = new Schema<T>({
334+
value: { type: String }
335+
});
336+
337+
const FooBarModel = model<T>('test', TestSchema);
338+
339+
const item = await FooBarModel.findOne().lean();
340+
341+
if (!item) return;
342+
343+
doSomeThing(item);
344+
};
345+
346+
const doSomeThing = <T extends FooBar>(item: T) => {
347+
console.log(item);
348+
};
349+
350+
createSomeModelAndDoSomething();
351+
}

types/index.d.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,14 @@ declare module 'mongoose' {
710710
[K in keyof T]: FlattenProperty<T[K]>;
711711
};
712712

713+
export type BufferToBinaryProperty<T> = T extends Buffer
714+
? mongodb.Binary
715+
: T extends Types.DocumentArray<infer ItemType>
716+
? Types.DocumentArray<BufferToBinary<ItemType>>
717+
: T extends Types.Subdocument<unknown, unknown, infer SubdocType>
718+
? HydratedSingleSubdocument<BufferToBinary<SubdocType>>
719+
: BufferToBinary<T>;
720+
713721
/**
714722
* Converts any Buffer properties into mongodb.Binary instances, which is what `lean()` returns
715723
*/
@@ -719,15 +727,11 @@ declare module 'mongoose' {
719727
? T
720728
: T extends TreatAsPrimitives
721729
? T
722-
: T extends Record<string, any> ? {
723-
[K in keyof T]: T[K] extends Buffer
724-
? mongodb.Binary
725-
: T[K] extends Types.DocumentArray<infer ItemType>
726-
? Types.DocumentArray<BufferToBinary<ItemType>>
727-
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
728-
? HydratedSingleSubdocument<BufferToBinary<SubdocType>>
729-
: BufferToBinary<T[K]>;
730-
} : T;
730+
: T extends Record<string, any>
731+
? {
732+
[K in keyof T]: BufferToBinaryProperty<T[K]>
733+
}
734+
: T;
731735

732736
/**
733737
* Converts any Buffer properties into { type: 'buffer', data: [1, 2, 3] } format for JSON serialization

types/models.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ declare module 'mongoose' {
3535
interface MongooseBulkSaveOptions extends mongodb.BulkWriteOptions {
3636
timestamps?: boolean;
3737
session?: ClientSession;
38+
validateBeforeSave?: boolean;
3839
}
3940

4041
/**

types/query.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ declare module 'mongoose' {
223223
type QueryOpThatReturnsDocument = 'find' | 'findOne' | 'findOneAndUpdate' | 'findOneAndReplace' | 'findOneAndDelete';
224224

225225
type GetLeanResultType<RawDocType, ResultType, QueryOp> = QueryOp extends QueryOpThatReturnsDocument
226-
? (ResultType extends any[] ? Default__v<Require_id<BufferToBinary<FlattenMaps<RawDocType>>>>[] : Default__v<Require_id<BufferToBinary<FlattenMaps<RawDocType>>>>)
226+
? (ResultType extends any[] ? Default__v<Require_id<FlattenMaps<BufferToBinary<RawDocType>>>>[] : Default__v<Require_id<FlattenMaps<BufferToBinary<RawDocType>>>>)
227227
: ResultType;
228228

229229
type MergePopulatePaths<RawDocType, ResultType, QueryOp, Paths, TQueryHelpers, TDocOverrides = Record<string, never>> = QueryOp extends QueryOpThatReturnsDocument

0 commit comments

Comments
 (0)