Skip to content

Commit

Permalink
Merge branch 'master' into 8.0
Browse files Browse the repository at this point in the history
  • Loading branch information
vkarpov15 committed Sep 26, 2023
2 parents d5e9176 + 2acc3f5 commit 11ae61f
Show file tree
Hide file tree
Showing 21 changed files with 268 additions and 34 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ module.exports = {
'*.min.js',
'**/docs/js/native.js',
'!.*',
'node_modules'
'node_modules',
'.git'
],
overrides: [
{
Expand Down
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
7.5.3 / 2023-09-25
==================
* fix(document): handle MongoDB Long when casting BigInts #13869 #13791
* fix(model): make bulkSave() persist changes that happen in pre('save') middleware #13885 #13799
* fix: handle casting $elemMatch underneath $not underneath another $elemMatch #13893 #13880
* fix(model): make bulkWrite casting respect global setDefaultsOnInsert #13870 #13823
* fix(document): handle default values for discriminator key with embedded discriminators #13891 #13835
* fix: account for null values when assigning isNew property within document array #13883
* types: avoid "interface can only extend object types with statically known members" error in TypeScript 4 #13871
* docs(deprecations): fix typo in includeResultMetadata deprecation docs #13884 #13844
* docs: fix pre element overflow in home page #13868 [ghoshRitesh12](https://github.com/ghoshRitesh12)

7.5.2 / 2023-09-15
==================
* fix(schema): handle number discriminator keys when using Schema.prototype.discriminator() #13858 #13788
* fix: ignore `id` property when calling `set()` with both `id` and `_id` specified to avoid `id` setter overwriting #13762
* types: pass correct document type to required and default function #13851 #13797
* docs(model): add examples of using diffIndexes() to syncIndexes()and diffIndexes() api docs #13850 #13771

7.5.1 / 2023-09-11
==================
* fix: set default value for _update when no update object is provided and versionKey is set to false #13795 #13783 [MohOraby](https://github.com/MohOraby)
Expand Down
1 change: 1 addition & 0 deletions docs/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pre {
background: #eee;
padding: 5px;
border-radius: 3px;
overflow-x: auto;
}
code {
color: #333;
Expand Down
2 changes: 1 addition & 1 deletion docs/deprecations.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ cause any problems for your application. Please [report any issues on GitHub](ht

To fix all deprecation warnings, follow the below steps:

* Replace `rawResult: true` with `includeResultMetadata: false` in `findOneAndUpdate()`, `findOneAndReplace()`, `findOneAndDelete()` calls.
* Replace `rawResult: true` with `includeResultMetadata: true` in `findOneAndUpdate()`, `findOneAndReplace()`, `findOneAndDelete()` calls.

Read below for more a more detailed description of each deprecation warning.

Expand Down
18 changes: 16 additions & 2 deletions lib/cast.js
Original file line number Diff line number Diff line change
Expand Up @@ -309,8 +309,21 @@ module.exports = function cast(schema, obj, options, context) {
while (k--) {
$cond = ks[k];
nested = val[$cond];

if ($cond === '$not') {
if ($cond === '$elemMatch') {
if (nested && schematype != null && schematype.schema != null) {
cast(schematype.schema, nested, options, context);
} else if (nested && schematype != null && schematype.$isMongooseArray) {
if (utils.isPOJO(nested) && nested.$not != null) {
cast(schema, nested, options, context);
} else {
val[$cond] = schematype.castForQuery(
$cond,
nested,
context
);
}
}
} else if ($cond === '$not') {
if (nested && schematype) {
_keys = Object.keys(nested);
if (_keys.length && isOperator(_keys[0])) {
Expand All @@ -337,6 +350,7 @@ module.exports = function cast(schema, obj, options, context) {
context
);
}

}
}
} else if (Array.isArray(val) && ['Buffer', 'Array'].indexOf(schematype.instance) === -1) {
Expand Down
5 changes: 5 additions & 0 deletions lib/cast/bigint.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

const assert = require('assert');
const { Long } = require('bson');

/**
* Given a value, cast it to a BigInt, or throw an `Error` if the value
Expand All @@ -23,6 +24,10 @@ module.exports = function castBigInt(val) {
return val;
}

if (val instanceof Long) {
return val.toBigInt();
}

if (typeof val === 'string' || typeof val === 'number') {
return BigInt(val);
}
Expand Down
6 changes: 5 additions & 1 deletion lib/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -1667,7 +1667,11 @@ Document.prototype.$__set = function(pathToMark, path, options, constructing, pa
val[arrayAtomicsSymbol] = priorVal[arrayAtomicsSymbol];
val[arrayAtomicsBackupSymbol] = priorVal[arrayAtomicsBackupSymbol];
if (utils.isMongooseDocumentArray(val)) {
val.forEach(doc => { doc.isNew = false; });
val.forEach(doc => {
if (doc != null) {
doc.$isNew = false;
}
});
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/drivers/node-mongodb-native/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ function _setClient(conn, client, options, dbName) {
client.s.options.hosts &&
client.s.options.hosts[0] &&
client.s.options.hosts[0].port || void 0;
conn.name = dbName != null ? dbName : client && client.s && client.s.options && client.s.options.dbName || void 0;
conn.name = dbName != null ? dbName : db.databaseName;
conn._closeCalled = client._closeCalled;

const _handleReconnect = () => {
Expand Down
17 changes: 10 additions & 7 deletions lib/helpers/discriminator/getConstructor.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@ const getDiscriminatorByValue = require('./getDiscriminatorByValue');
* @api private
*/

module.exports = function getConstructor(Constructor, value) {
module.exports = function getConstructor(Constructor, value, defaultDiscriminatorValue) {
const discriminatorKey = Constructor.schema.options.discriminatorKey;
if (value != null &&
Constructor.discriminators &&
value[discriminatorKey] != null) {
if (Constructor.discriminators[value[discriminatorKey]]) {
Constructor = Constructor.discriminators[value[discriminatorKey]];
let discriminatorValue = (value != null && value[discriminatorKey]);
if (discriminatorValue == null) {
discriminatorValue = defaultDiscriminatorValue;
}
if (Constructor.discriminators &&
discriminatorValue != null) {
if (Constructor.discriminators[discriminatorValue]) {
Constructor = Constructor.discriminators[discriminatorValue];
} else {
const constructorByValue = getDiscriminatorByValue(Constructor.discriminators, value[discriminatorKey]);
const constructorByValue = getDiscriminatorByValue(Constructor.discriminators, discriminatorValue);
if (constructorByValue) {
Constructor = constructorByValue;
}
Expand Down
13 changes: 11 additions & 2 deletions lib/helpers/model/castBulkWrite.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ const setDefaultsOnInsert = require('../setDefaultsOnInsert');

module.exports = function castBulkWrite(originalModel, op, options) {
const now = originalModel.base.now();

const globalSetDefaultsOnInsert = originalModel.base.options.setDefaultsOnInsert;
if (op['insertOne']) {
return (callback) => {
const model = decideModelByObject(originalModel, op['insertOne']['document']);
Expand Down Expand Up @@ -69,7 +71,10 @@ module.exports = function castBulkWrite(originalModel, op, options) {
applyTimestampsToChildren(now, op['updateOne']['update'], model.schema);
}

if (op['updateOne'].setDefaultsOnInsert !== false) {
const shouldSetDefaultsOnInsert = op['updateOne'].setDefaultsOnInsert == null ?
globalSetDefaultsOnInsert :
op['updateOne'].setDefaultsOnInsert;
if (shouldSetDefaultsOnInsert !== false) {
setDefaultsOnInsert(op['updateOne']['filter'], model.schema, op['updateOne']['update'], {
setDefaultsOnInsert: true,
upsert: op['updateOne'].upsert
Expand Down Expand Up @@ -106,7 +111,11 @@ module.exports = function castBulkWrite(originalModel, op, options) {
const schema = model.schema;
const strict = options.strict != null ? options.strict : model.schema.options.strict;

if (op['updateMany'].setDefaultsOnInsert !== false) {
const shouldSetDefaultsOnInsert = op['updateMany'].setDefaultsOnInsert == null ?
globalSetDefaultsOnInsert :
op['updateMany'].setDefaultsOnInsert;

if (shouldSetDefaultsOnInsert !== false) {
setDefaultsOnInsert(op['updateMany']['filter'], model.schema, op['updateMany']['update'], {
setDefaultsOnInsert: true,
upsert: op['updateMany'].upsert
Expand Down
4 changes: 2 additions & 2 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -624,8 +624,8 @@ Mongoose.prototype._model = function(name, schema, collection, options) {
connection.emit('model', model);

if (schema._applyDiscriminators != null) {
for (const disc of Object.keys(schema._applyDiscriminators)) {
model.discriminator(disc, schema._applyDiscriminators[disc]);
for (const disc of schema._applyDiscriminators.keys()) {
model.discriminator(disc, schema._applyDiscriminators.get(disc));
}
}

Expand Down
6 changes: 3 additions & 3 deletions lib/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -3464,11 +3464,9 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
* @param {Boolean} [options.j=true] If false, disable [journal acknowledgement](https://www.mongodb.com/docs/manual/reference/write-concern/#j-option)
*
*/
Model.bulkSave = async function(documents, options) {
Model.bulkSave = async function bulkSave(documents, options) {
options = options || {};

const writeOperations = this.buildBulkWriteOperations(documents, { skipValidation: true, timestamps: options.timestamps });

if (options.timestamps != null) {
for (const document of documents) {
document.$__.saveOptions = document.$__.saveOptions || {};
Expand All @@ -3485,6 +3483,8 @@ Model.bulkSave = async function(documents, options) {

await Promise.all(documents.map(buildPreSavePromise));

const writeOperations = this.buildBulkWriteOperations(documents, { skipValidation: true, timestamps: options.timestamps });

const { bulkWriteResult, bulkWriteError } = await this.bulkWrite(writeOperations, options).then(
(res) => ({ bulkWriteResult: res, bulkWriteError: null }),
(err) => ({ bulkWriteResult: null, bulkWriteError: err })
Expand Down
21 changes: 11 additions & 10 deletions lib/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ Schema.prototype._clone = function _clone(Constructor) {
s.discriminators = Object.assign({}, this.discriminators);
}
if (this._applyDiscriminators != null) {
s._applyDiscriminators = Object.assign({}, this._applyDiscriminators);
s._applyDiscriminators = new Map(this._applyDiscriminators);
}

s.aliases = Object.assign({}, this.aliases);
Expand Down Expand Up @@ -621,7 +621,8 @@ Schema.prototype.defaultOptions = function(options) {
* @api public
*/
Schema.prototype.discriminator = function(name, schema) {
this._applyDiscriminators = Object.assign(this._applyDiscriminators || {}, { [name]: schema });
this._applyDiscriminators = this._applyDiscriminators || new Map();
this._applyDiscriminators.set(name, schema);

return this;
};
Expand Down Expand Up @@ -722,18 +723,18 @@ Schema.prototype.add = function add(obj, prefix) {
for (const key in val[0].discriminators) {
schemaType.discriminator(key, val[0].discriminators[key]);
}
} else if (val[0] != null && val[0].instanceOfSchema && utils.isPOJO(val[0]._applyDiscriminators)) {
const applyDiscriminators = val[0]._applyDiscriminators || [];
} else if (val[0] != null && val[0].instanceOfSchema && val[0]._applyDiscriminators instanceof Map) {
const applyDiscriminators = val[0]._applyDiscriminators;
const schemaType = this.path(prefix + key);
for (const disc in applyDiscriminators) {
schemaType.discriminator(disc, applyDiscriminators[disc]);
for (const disc of applyDiscriminators.keys()) {
schemaType.discriminator(disc, applyDiscriminators.get(disc));
}
}
else if (val != null && val.instanceOfSchema && utils.isPOJO(val._applyDiscriminators)) {
const applyDiscriminators = val._applyDiscriminators || [];
else if (val != null && val.instanceOfSchema && val._applyDiscriminators instanceof Map) {
const applyDiscriminators = val._applyDiscriminators;
const schemaType = this.path(prefix + key);
for (const disc in applyDiscriminators) {
schemaType.discriminator(disc, applyDiscriminators[disc]);
for (const disc of applyDiscriminators.keys()) {
schemaType.discriminator(disc, applyDiscriminators.get(disc));
}
}
} else if (Object.keys(val).length < 1) {
Expand Down
4 changes: 3 additions & 1 deletion lib/schema/subdocument.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,9 @@ SchemaSubdocument.prototype.cast = function(val, doc, init, priorVal, options) {
throw new ObjectExpectedError(this.path, val);
}

const Constructor = getConstructor(this.caster, val);
const discriminatorKeyPath = this.schema.path(this.schema.options.discriminatorKey);
const defaultDiscriminatorValue = discriminatorKeyPath == null ? null : discriminatorKeyPath.getDefault(doc);
const Constructor = getConstructor(this.caster, val, defaultDiscriminatorValue);

let subdoc;

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "mongoose",
"description": "Mongoose MongoDB ODM",
"version": "7.5.1",
"version": "7.5.3",
"author": "Guillermo Rauch <[email protected]>",
"keywords": [
"mongodb",
Expand Down
2 changes: 2 additions & 0 deletions scripts/generateSearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ async function run() {
await Content.init();

await Content.deleteMany({ version });
let count = 0;
for (const content of contents) {
if (version === '7.x') {
let url = content.url.startsWith('/') ? content.url : `/${content.url}`;
Expand All @@ -143,6 +144,7 @@ async function run() {
const url = content.url.startsWith('/') ? content.url : `/${content.url}`;
content.url = `/docs/${version}/docs${url}`;
}
console.log(`${++count} / ${contents.length}`);
await content.save();
}

Expand Down
91 changes: 91 additions & 0 deletions test/document.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12402,6 +12402,97 @@ describe('document', function() {
const fromDb = await Test.findById(x._id).lean();
assert.equal(fromDb._id, 1);
});
it('handles bigint (gh-13791)', async function() {
const testSchema = new mongoose.Schema({
n: Number,
reward: BigInt
});
const Test = db.model('Test', testSchema);

const a = await Test.create({ n: 1, reward: 14055648105137340n });
const b = await Test.findOne({ n: 1 });
assert.equal(a.reward, 14055648105137340n);
assert.equal(b.reward, 14055648105137340n);
});
it('should allow null values in list in self assignment (gh-13859)', async function() {
const objSchema = new Schema({
date: Date,
value: Number
});

const testSchema = new Schema({
intArray: [Number],
strArray: [String],
objArray: [objSchema]
});
const Test = db.model('Test', testSchema);

const doc = new Test({
intArray: [1, 2, 3, null],
strArray: ['b', null, 'c'],
objArray: [
{ date: new Date(1000), value: 1 },
null,
{ date: new Date(3000), value: 3 }
]
});
await doc.save();
doc.intArray = doc.intArray;
doc.strArray = doc.strArray;
doc.objArray = doc.objArray; // this is the trigger for the error
assert.ok(doc);
await doc.save();
assert.ok(doc);
});

it('bulkSave() picks up changes in pre("save") middleware (gh-13799)', async() => {
const schema = new Schema({ name: String, _age: { type: Number, min: 0, default: 0 } });
schema.pre('save', function() {
this._age = this._age + 1;
});

const Person = db.model('Person', schema, 'Persons');
const person = new Person({ name: 'Jean-Luc Picard', _age: 59 });

await Person.bulkSave([person]);

let updatedPerson = await Person.findById(person._id);

assert.equal(updatedPerson?._age, 60);

await Person.bulkSave([updatedPerson]);

updatedPerson = await Person.findById(person._id);

assert.equal(updatedPerson?._age, 61);
});

it('handles default embedded discriminator values (gh-13835)', async function() {
const childAbstractSchema = new Schema(
{ kind: { type: Schema.Types.String, enum: ['concreteKind'], required: true, default: 'concreteKind' } },
{ discriminatorKey: 'kind', _id: false }
);
const childConcreteSchema = new Schema({ concreteProp: { type: Number, required: true } });

const parentSchema = new Schema(
{
child: {
type: childAbstractSchema,
required: true
}
},
{ _id: false }
);

parentSchema.path('child').discriminator('concreteKind', childConcreteSchema);

const ParentModel = db.model('Test', parentSchema);

const parent = new ParentModel({ child: { concreteProp: 123 } });
assert.strictEqual(parent.child.concreteProp, 123);
assert.strictEqual(parent.get('child.concreteProp'), 123);
assert.strictEqual(parent.toObject().child.concreteProp, 123);
});
});

describe('Check if instance function that is supplied in schema option is availabe', function() {
Expand Down
Loading

0 comments on commit 11ae61f

Please sign in to comment.