Skip to content

Commit

Permalink
Merge branch '8.0' into vkarpov15/gh-13772
Browse files Browse the repository at this point in the history
  • Loading branch information
vkarpov15 committed Sep 28, 2023
2 parents cb6d61f + 11ae61f commit 092e2c5
Show file tree
Hide file tree
Showing 22 changed files with 338 additions and 81 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
43 changes: 6 additions & 37 deletions lib/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const isExclusive = require('./helpers/projection/isExclusive');
const inspect = require('util').inspect;
const internalToObjectOptions = require('./options').internalToObjectOptions;
const markArraySubdocsPopulated = require('./helpers/populate/markArraySubdocsPopulated');
const minimize = require('./helpers/minimize');
const mpath = require('mpath');
const queryhelpers = require('./queryHelpers');
const utils = require('./utils');
Expand Down Expand Up @@ -1666,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 Expand Up @@ -3938,42 +3943,6 @@ Document.prototype.toObject = function(options) {
return this.$toObject(options);
};

/**
* Minimizes an object, removing undefined values and empty objects
*
* @param {Object} object to minimize
* @return {Object}
* @api private
*/

function minimize(obj) {
const keys = Object.keys(obj);
let i = keys.length;
let hasKeys;
let key;
let val;

while (i--) {
key = keys[i];
val = obj[key];

if (utils.isPOJO(val)) {
obj[key] = minimize(val);
}

if (undefined === obj[key]) {
delete obj[key];
continue;
}

hasKeys = true;
}

return hasKeys
? obj
: undefined;
}

/*!
* Applies virtuals properties to `json`.
*/
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
41 changes: 41 additions & 0 deletions lib/helpers/minimize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use strict';

const { isPOJO } = require('../utils');

module.exports = minimize;

/**
* Minimizes an object, removing undefined values and empty objects
*
* @param {Object} object to minimize
* @return {Object|undefined}
* @api private
*/

function minimize(obj) {
const keys = Object.keys(obj);
let i = keys.length;
let hasKeys;
let key;
let val;

while (i--) {
key = keys[i];
val = obj[key];

if (isPOJO(val)) {
obj[key] = minimize(val);
}

if (undefined === obj[key]) {
delete obj[key];
continue;
}

hasKeys = true;
}

return hasKeys
? obj
: undefined;
}
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
39 changes: 28 additions & 11 deletions lib/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ const STATES = require('./connectionState');
const util = require('util');
const utils = require('./utils');
const MongooseBulkWriteError = require('./error/bulkWriteError');
const minimize = require('./helpers/minimize');

const VERSION_WHERE = 1;
const VERSION_INC = 2;
Expand Down Expand Up @@ -342,7 +343,19 @@ Model.prototype.$__handleSave = function(options, callback) {
}

_applyCustomWhere(this, where);
this[modelCollectionSymbol].updateOne(where, delta[1], saveOptions).then(

const update = delta[1];
if (this.$__schema.options.minimize) {
minimize(update);
// minimize might leave us with an empty object, which would
// lead to MongoDB throwing a "Update document requires atomic operators" error
if (Object.keys(update).length === 0) {
handleEmptyUpdate.call(this);
return;
}
}

this[modelCollectionSymbol].updateOne(where, update, saveOptions).then(
ret => {
ret.$where = where;
callback(null, ret);
Expand All @@ -354,6 +367,17 @@ Model.prototype.$__handleSave = function(options, callback) {
}
);
} else {
handleEmptyUpdate.call(this);
return;
}

// store the modified paths before the document is reset
this.$__.modifiedPaths = this.modifiedPaths();
this.$__reset();

_setIsNew(this, false);

function handleEmptyUpdate() {
const optionsWithCustomValues = Object.assign({}, options, saveOptions);
const where = this.$__where();
const optimisticConcurrency = this.$__schema.options.optimisticConcurrency;
Expand All @@ -370,14 +394,7 @@ Model.prototype.$__handleSave = function(options, callback) {
callback(null, { $where: where, matchedCount });
})
.catch(callback);
return;
}

// store the modified paths before the document is reset
this.$__.modifiedPaths = this.modifiedPaths();
this.$__reset();

_setIsNew(this, false);
};

/*!
Expand Down Expand Up @@ -3447,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 @@ -3468,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
Loading

0 comments on commit 092e2c5

Please sign in to comment.