Skip to content

Commit

Permalink
Merge branch 'master' into 5.12
Browse files Browse the repository at this point in the history
  • Loading branch information
vkarpov15 committed Mar 11, 2021
2 parents 6c55b69 + ff289ec commit 2170a8b
Show file tree
Hide file tree
Showing 11 changed files with 156 additions and 125 deletions.
18 changes: 18 additions & 0 deletions History.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
5.11.20 / 2021-03-11
====================
* fix(query+populate): avoid unnecessarily projecting in subpath when populating a path that uses an elemMatch projection #9973
* fix(connection): avoid `db` events deprecation warning with 'close' events #10004 #9930
* fix(index.d.ts): make `$pull` more permissive to allow dotted paths #9993

5.11.19 / 2021-03-05
====================
* fix(document): skip validating array elements that aren't modified when `validateModifiedOnly` is set #9963
* fix(timestamps): apply timestamps on `findOneAndReplace()` #9951
* fix(schema): correctly handle trailing array filters when looking up schema paths #9977
* fix(schema): load child class getter for virtuals instead of base class when using `loadClass()` #9975
* fix(index.d.ts): allow creating statics without passing generics to `Schema` constructor #9969
* fix(index.d.ts): add QueryHelpers generic to schema and model, make all query methods instead return QueryWithHelpers #9850
* fix(index.d.ts): support setting `type` to an array of schemas when using SchemaDefinitionType #9962
* fix(index.d.ts): add generic to plugin schema definition #9968 [emiljanitzek](https://github.com/emiljanitzek)
* docs: small typo fix #9964 [KrishnaMoorthy12](https://github.com/KrishnaMoorthy12)

5.11.18 / 2021-02-23
====================
* fix(connection): set connection state to `disconnected` if connecting string failed to parse #9921
Expand Down
47 changes: 45 additions & 2 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1129,7 +1129,7 @@ declare module 'mongoose' {
pathType(path: string): string;

/** Registers a plugin for this schema. */
plugin(fn: (schema: Schema, opts?: any) => void, opts?: any): this;
plugin(fn: (schema: Schema<DocType, Model<DocType>, SchemaDefinitionType>, opts?: any) => void, opts?: any): this;

/** Defines a post hook for the model. */
post<T extends Document = DocType>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, fn: (this: T, res: any, next: (err?: CallbackError) => void) => void): this;
Expand Down Expand Up @@ -2240,7 +2240,50 @@ declare module 'mongoose' {

export type FilterQuery<T> = _FilterQuery<DocumentDefinition<T>>;

export type UpdateQuery<T> = mongodb.UpdateQuery<DocumentDefinition<T>> & mongodb.MatchKeysAndValues<DocumentDefinition<T>>;
type NumericTypes = number | mongodb.Decimal128 | mongodb.Double | mongodb.Int32 | mongodb.Long;

type KeysOfAType<TSchema, Type> = {
[key in keyof TSchema]: NonNullable<TSchema[key]> extends Type ? key : never;
}[keyof TSchema];

type PullOperator<TSchema> = {
[key in KeysOfAType<TSchema, ReadonlyArray<any>>]?:
| Partial<Unpacked<TSchema[key]>>
| mongodb.ObjectQuerySelector<Unpacked<TSchema[key]>>
// Doesn't look like TypeScript has good support for creating an
// object containing dotted keys:
// https://stackoverflow.com/questions/58434389/typescript-deep-keyof-of-a-nested-object
| mongodb.QuerySelector<any>
| any;
};

/** @see https://docs.mongodb.com/manual/reference/operator/update */
type _UpdateQuery<TSchema> = {
/** @see https://docs.mongodb.com/manual/reference/operator/update-field/ */
$currentDate?: mongodb.OnlyFieldsOfType<TSchema, Date | mongodb.Timestamp, true | { $type: 'date' | 'timestamp' }>;
$inc?: mongodb.OnlyFieldsOfType<TSchema, NumericTypes | undefined>;
$min?: mongodb.MatchKeysAndValues<TSchema>;
$max?: mongodb.MatchKeysAndValues<TSchema>;
$mul?: mongodb.OnlyFieldsOfType<TSchema, NumericTypes | undefined>;
$rename?: { [key: string]: string };
$set?: mongodb.MatchKeysAndValues<TSchema>;
$setOnInsert?: mongodb.MatchKeysAndValues<TSchema>;
$unset?: mongodb.OnlyFieldsOfType<TSchema, any, '' | 1 | true>;

/** @see https://docs.mongodb.com/manual/reference/operator/update-array/ */
$addToSet?: mongodb.SetFields<TSchema>;
$pop?: mongodb.OnlyFieldsOfType<TSchema, ReadonlyArray<any>, 1 | -1>;
$pull?: PullOperator<TSchema>;
$push?: mongodb.PushOperator<TSchema>;
$pullAll?: mongodb.PullAllOperator<TSchema>;

/** @see https://docs.mongodb.com/manual/reference/operator/update-bitwise/ */
$bit?: {
[key: string]: { [key in 'and' | 'or' | 'xor']?: number };
};
};

export type UpdateQuery<T> = _UpdateQuery<DocumentDefinition<T>> & mongodb.MatchKeysAndValues<DocumentDefinition<T>>;

type _AllowStringsForIds<T> = {
[K in keyof T]: [Extract<T[K], mongodb.ObjectId>] extends [never] ? T[K] : T[K] | string;
Expand Down
3 changes: 3 additions & 0 deletions index.pug
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,9 @@ html(lang='en')
<a rel="sponsored" href="https://kajino.com/">
<img class="sponsor" src="https://images.opencollective.com/kajino-com/02c99ee/logo/256.png" style="height: 100px">
</a>
<a rel="sponsored" href="https://www.leoboost.com/buy-instagram-likes">
<img class="sponsor" src="https://images.opencollective.com/leo-boost1/f744783/logo/256.png" style="height: 100px">
</a>
</div>
</div>

Expand Down
8 changes: 4 additions & 4 deletions lib/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -924,7 +924,7 @@ function _setClient(conn, client, options, dbName) {
}
});

db.on('close', function() {
client.on('close', function() {
const type = get(db, 's.topology.s.description.type', '');
if (type !== 'ReplicaSetWithPrimary') {
// Implicitly emits 'disconnected'
Expand All @@ -940,7 +940,7 @@ function _setClient(conn, client, options, dbName) {
});

if (!options.useUnifiedTopology) {
db.on('reconnect', function() {
client.on('reconnect', function() {
_handleReconnect();
});

Expand All @@ -960,7 +960,7 @@ function _setClient(conn, client, options, dbName) {
});
}
if (!options.useUnifiedTopology) {
db.on('close', function() {
client.on('close', function() {
// Implicitly emits 'disconnected'
conn.readyState = STATES.disconnected;
});
Expand All @@ -979,7 +979,7 @@ function _setClient(conn, client, options, dbName) {
}
});

db.on('timeout', function() {
client.on('timeout', function() {
conn.emit('timeout');
});
}
Expand Down
4 changes: 4 additions & 0 deletions lib/helpers/projection/isExclusive.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ const isDefiningProjection = require('./isDefiningProjection');
*/

module.exports = function isExclusive(projection) {
if (projection == null) {
return null;
}

const keys = Object.keys(projection);
let ki = keys.length;
let exclude = null;
Expand Down
41 changes: 22 additions & 19 deletions lib/helpers/query/selectPopulatedFields.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
'use strict';

const isExclusive = require('../projection/isExclusive');
const isInclusive = require('../projection/isInclusive');

/*!
* ignore
*/

module.exports = function selectPopulatedFields(query) {
const opts = query._mongooseOptions;
module.exports = function selectPopulatedFields(fields, userProvidedFields, populateOptions) {
if (populateOptions == null) {
return;
}

if (opts.populate != null) {
const paths = Object.keys(opts.populate);
const userProvidedFields = query._userProvidedFields || {};
if (query.selectedInclusively()) {
for (const path of paths) {
if (!isPathInFields(userProvidedFields, path)) {
query.select(path);
} else if (userProvidedFields[path] === 0) {
delete query._fields[path];
}
const paths = Object.keys(populateOptions);
userProvidedFields = userProvidedFields || {};
if (isInclusive(fields)) {
for (const path of paths) {
if (!isPathInFields(userProvidedFields, path)) {
fields[path] = 1;
} else if (userProvidedFields[path] === 0) {
delete fields[path];
}
} else if (query.selectedExclusively()) {
for (const path of paths) {
if (userProvidedFields[path] == null) {
delete query._fields[path];
}
}
} else if (isExclusive(fields)) {
for (const path of paths) {
if (userProvidedFields[path] == null) {
delete fields[path];
}
}
}
Expand All @@ -37,10 +40,10 @@ function isPathInFields(userProvidedFields, path) {
const len = pieces.length;
let cur = pieces[0];
for (let i = 1; i < len; ++i) {
if (userProvidedFields[cur] != null) {
if (userProvidedFields[cur] != null || userProvidedFields[cur + '.$'] != null) {
return true;
}
cur += '.' + pieces[i];
}
return userProvidedFields[cur] != null;
return userProvidedFields[cur] != null || userProvidedFields[cur + '.$'] != null;
}
19 changes: 3 additions & 16 deletions lib/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const promiseOrCallback = require('./helpers/promiseOrCallback');
const getDiscriminatorByValue = require('./helpers/discriminator/getDiscriminatorByValue');
const hasDollarKeys = require('./helpers/query/hasDollarKeys');
const helpers = require('./queryhelpers');
const isExclusive = require('./helpers/projection/isExclusive');
const isInclusive = require('./helpers/projection/isInclusive');
const mquery = require('mquery');
const parseProjection = require('./helpers/projection/parseProjection');
Expand Down Expand Up @@ -4886,7 +4887,7 @@ Query.prototype._applyPaths = function applyPaths() {
}

if (_selectPopulatedPaths) {
selectPopulatedFields(this);
selectPopulatedFields(this._fields, this._userProvidedFields, this._mongooseOptions.populate);
}
};

Expand Down Expand Up @@ -5402,21 +5403,7 @@ Query.prototype.selectedInclusively = function selectedInclusively() {
*/

Query.prototype.selectedExclusively = function selectedExclusively() {
if (!this._fields) {
return false;
}

const keys = Object.keys(this._fields);
for (const key of keys) {
if (key === '_id') {
continue;
}
if (this._fields[key] === 0 || this._fields[key] === false) {
return true;
}
}

return false;
return isExclusive(this._fields);
};

/*!
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": "5.11.18",
"version": "5.11.20",
"author": "Guillermo Rauch <[email protected]>",
"keywords": [
"mongodb",
Expand Down
45 changes: 45 additions & 0 deletions test/helpers/query.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
'use strict';

require('../common');

const assert = require('assert');
const selectPopulatedFields = require('../../lib/helpers/query/selectPopulatedFields');

describe('Query helpers', function() {
describe('selectPopulatedFields', function() {
it('handles nested populate if parent key is projected in (gh-5669)', function(done) {
const fields = { nested: 1 };
selectPopulatedFields(fields, { nested: 1 }, { 'nested.key1': true });

assert.deepEqual(fields, { nested: 1 });

done();
});

it('handles nested populate if parent key is projected out (gh-5669)', function(done) {
const fields = { nested: 0 };
selectPopulatedFields(fields, { nested: 0 }, { 'nested.key1': true });

assert.deepEqual(fields, { nested: 0 });

done();
});

it('handle explicitly excluded paths (gh-7383)', function(done) {
const fields = { name: 1, other: 0 };
selectPopulatedFields(fields, Object.assign({}, fields), { other: 1 });

assert.deepEqual(fields, { name: 1 });

done();
});

it('handles paths selected with elemMatch (gh-9973)', function(done) {
const fields = { 'arr.$': 1 };
selectPopulatedFields(fields, Object.assign({}, fields), { 'arr.el': 1 });
assert.deepEqual(fields, { 'arr.$': 1 });

done();
});
});
});
82 changes: 0 additions & 82 deletions test/services.query.test.js

This file was deleted.

Loading

0 comments on commit 2170a8b

Please sign in to comment.