Skip to content

Commit 998e778

Browse files
authored
Merge pull request #11316 from Automattic/6.2
6.2
2 parents 27bb443 + 7f3a43e commit 998e778

27 files changed

+1108
-183
lines changed

docs/guide.md

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,40 +1158,37 @@ const schema = Schema({
11581158
});
11591159
```
11601160

1161-
<h3 id="useNestedStrict"><a href="#useNestedStrict">option: useNestedStrict</a></h3>
1161+
<h3 id="pluginTags"><a href="#pluginTags">option: pluginTags</a></h3>
11621162

1163-
Write operations like `update()`, `updateOne()`, `updateMany()`,
1164-
and `findOneAndUpdate()` only check the top-level
1165-
schema's strict mode setting.
1163+
Mongoose supports defining global plugins, plugins that apply to all schemas.
11661164

11671165
```javascript
1168-
const childSchema = new Schema({}, { strict: false });
1169-
const parentSchema = new Schema({ child: childSchema }, { strict: 'throw' });
1170-
const Parent = mongoose.model('Parent', parentSchema);
1171-
Parent.update({}, { 'child.name': 'Luke Skywalker' }, (error) => {
1172-
// Error because parentSchema has `strict: throw`, even though
1173-
// `childSchema` has `strict: false`
1166+
// Add a `meta` property to all schemas
1167+
mongoose.plugin(function myPlugin(schema) {
1168+
schema.add({ meta: {} });
11741169
});
1170+
```
1171+
1172+
Sometimes, you may only want to apply a given plugin to some schemas.
1173+
In that case, you can add `pluginTags` to a schema:
11751174

1176-
const update = { 'child.name': 'Luke Skywalker' };
1177-
const opts = { strict: false };
1178-
Parent.update({}, update, opts, function(error) {
1179-
// This works because passing `strict: false` to `update()` overwrites
1180-
// the parent schema.
1175+
```javascript
1176+
const schema1 = new Schema({
1177+
name: String
1178+
}, { pluginTags: ['useMetaPlugin'] });
1179+
1180+
const schema2 = new Schema({
1181+
name: String
11811182
});
11821183
```
11831184

1184-
If you set `useNestedStrict` to true, mongoose will use the child schema's
1185-
`strict` option for casting updates.
1185+
If you call `plugin()` with a `tags` option, Mongoose will only apply that plugin to schemas that have a matching entry in `pluginTags`.
11861186

11871187
```javascript
1188-
const childSchema = new Schema({}, { strict: false });
1189-
const parentSchema = new Schema({ child: childSchema },
1190-
{ strict: 'throw', useNestedStrict: true });
1191-
const Parent = mongoose.model('Parent', parentSchema);
1192-
Parent.update({}, { 'child.name': 'Luke Skywalker' }, error => {
1193-
// Works!
1194-
});
1188+
// Add a `meta` property to all schemas
1189+
mongoose.plugin(function myPlugin(schema) {
1190+
schema.add({ meta: {} });
1191+
}, { tags: ['useMetaPlugin'] });
11951192
```
11961193

11971194
<h3 id="selectPopulatedPaths">

index.d.ts

Lines changed: 92 additions & 41 deletions
Large diffs are not rendered by default.

lib/cast.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
const CastError = require('./error/cast');
88
const StrictModeError = require('./error/strict');
99
const Types = require('./schema/index');
10+
const cast$expr = require('./helpers/query/cast$expr');
1011
const castTextSearch = require('./schema/operators/text');
1112
const get = require('./helpers/get');
1213
const getConstructorName = require('./helpers/getConstructorName');
@@ -79,9 +80,7 @@ module.exports = function cast(schema, obj, options, context) {
7980

8081
continue;
8182
} else if (path === '$expr') {
82-
if (typeof val !== 'object' || val == null) {
83-
throw new Error('`$expr` must be an object');
84-
}
83+
val = cast$expr(val, schema);
8584
continue;
8685
} else if (path === '$elemMatch') {
8786
val = cast(schema, val, options, context);

lib/connection.js

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const Schema = require('./schema');
1010
const Collection = require('./driver').get().Collection;
1111
const STATES = require('./connectionstate');
1212
const MongooseError = require('./error/index');
13+
const SyncIndexesError = require('./error/syncIndexes');
1314
const PromiseProvider = require('./promise_provider');
1415
const ServerSelectionError = require('./error/serverSelection');
1516
const applyPlugins = require('./helpers/schema/applyPlugins');
@@ -1380,11 +1381,40 @@ Connection.prototype.setClient = function setClient(client) {
13801381
return this;
13811382
};
13821383

1383-
Connection.prototype.syncIndexes = async function syncIndexes() {
1384+
/**
1385+
*
1386+
* Syncs all the indexes for the models registered with this connection.
1387+
*
1388+
* @param {Object} options
1389+
* @param {Boolean} options.continueOnError `false` by default. If set to `true`, mongoose will not throw an error if one model syncing failed, and will return an object where the keys are the names of the models, and the values are the results/errors for each model.
1390+
* @returns
1391+
*/
1392+
Connection.prototype.syncIndexes = async function syncIndexes(options = {}) {
13841393
const result = {};
1385-
for (const model in this.models) {
1386-
result[model] = await this.model(model).syncIndexes();
1394+
const errorsMap = { };
1395+
1396+
const { continueOnError } = options;
1397+
delete options.continueOnError;
1398+
1399+
for (const model of Object.values(this.models)) {
1400+
try {
1401+
result[model.modelName] = await model.syncIndexes(options);
1402+
} catch (err) {
1403+
if (!continueOnError) {
1404+
errorsMap[model.modelName] = err;
1405+
break;
1406+
} else {
1407+
result[model.modelName] = err;
1408+
}
1409+
}
13871410
}
1411+
1412+
if (!continueOnError && Object.keys(errorsMap).length) {
1413+
const message = Object.entries(errorsMap).map(([modelName, err]) => `${modelName}: ${err.message}`).join(', ');
1414+
const syncIndexesError = new SyncIndexesError(message, errorsMap);
1415+
throw syncIndexesError;
1416+
}
1417+
13881418
return result;
13891419
};
13901420

lib/error/index.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,17 @@ MongooseError.OverwriteModelError = require('./overwriteModel');
181181

182182
MongooseError.MissingSchemaError = require('./missingSchema');
183183

184+
/**
185+
* Thrown when the MongoDB Node driver can't connect to a valid server
186+
* to send an operation to.
187+
*
188+
* @api public
189+
* @memberOf Error
190+
* @static MongooseServerSelectionError
191+
*/
192+
193+
MongooseError.MongooseServerSelectionError = require('./serverSelection');
194+
184195
/**
185196
* An instance of this error will be returned if you used an array projection
186197
* and then modified the array in an unsafe way.

lib/error/syncIndexes.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
'use strict';
2+
3+
/*!
4+
* Module dependencies.
5+
*/
6+
7+
const MongooseError = require('./mongooseError');
8+
9+
/**
10+
* SyncIndexes Error constructor.
11+
*
12+
* @param {String} message
13+
* @param {String} errorsMap
14+
* @inherits MongooseError
15+
* @api private
16+
*/
17+
18+
class SyncIndexesError extends MongooseError {
19+
constructor(message, errorsMap) {
20+
super(message);
21+
this.errors = errorsMap;
22+
}
23+
}
24+
25+
Object.defineProperty(SyncIndexesError.prototype, 'name', {
26+
value: 'SyncIndexesError'
27+
});
28+
29+
30+
module.exports = SyncIndexesError;

lib/helpers/model/discriminator.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const CUSTOMIZABLE_DISCRIMINATOR_OPTIONS = {
1717
*/
1818

1919
module.exports = function discriminator(model, name, schema, tiedValue, applyPlugins) {
20+
2021
if (!(schema && schema.instanceOfSchema)) {
2122
throw new Error('You must pass a valid discriminator Schema');
2223
}
@@ -201,7 +202,7 @@ module.exports = function discriminator(model, name, schema, tiedValue, applyPlu
201202

202203
model.schema.discriminators[name] = schema;
203204

204-
if (model.discriminators[name]) {
205+
if (model.discriminators[name] && !schema.options.overwriteModels) {
205206
throw new Error('Discriminator with name "' + name + '" already exists');
206207
}
207208

0 commit comments

Comments
 (0)