Skip to content

Commit

Permalink
Merge pull request #11316 from Automattic/6.2
Browse files Browse the repository at this point in the history
6.2
  • Loading branch information
vkarpov15 authored Feb 2, 2022
2 parents 27bb443 + 7f3a43e commit 998e778
Show file tree
Hide file tree
Showing 27 changed files with 1,108 additions and 183 deletions.
45 changes: 21 additions & 24 deletions docs/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -1158,40 +1158,37 @@ const schema = Schema({
});
```

<h3 id="useNestedStrict"><a href="#useNestedStrict">option: useNestedStrict</a></h3>
<h3 id="pluginTags"><a href="#pluginTags">option: pluginTags</a></h3>

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

```javascript
const childSchema = new Schema({}, { strict: false });
const parentSchema = new Schema({ child: childSchema }, { strict: 'throw' });
const Parent = mongoose.model('Parent', parentSchema);
Parent.update({}, { 'child.name': 'Luke Skywalker' }, (error) => {
// Error because parentSchema has `strict: throw`, even though
// `childSchema` has `strict: false`
// Add a `meta` property to all schemas
mongoose.plugin(function myPlugin(schema) {
schema.add({ meta: {} });
});
```

Sometimes, you may only want to apply a given plugin to some schemas.
In that case, you can add `pluginTags` to a schema:

const update = { 'child.name': 'Luke Skywalker' };
const opts = { strict: false };
Parent.update({}, update, opts, function(error) {
// This works because passing `strict: false` to `update()` overwrites
// the parent schema.
```javascript
const schema1 = new Schema({
name: String
}, { pluginTags: ['useMetaPlugin'] });

const schema2 = new Schema({
name: String
});
```

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

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

<h3 id="selectPopulatedPaths">
Expand Down
133 changes: 92 additions & 41 deletions index.d.ts

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions lib/cast.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
const CastError = require('./error/cast');
const StrictModeError = require('./error/strict');
const Types = require('./schema/index');
const cast$expr = require('./helpers/query/cast$expr');
const castTextSearch = require('./schema/operators/text');
const get = require('./helpers/get');
const getConstructorName = require('./helpers/getConstructorName');
Expand Down Expand Up @@ -79,9 +80,7 @@ module.exports = function cast(schema, obj, options, context) {

continue;
} else if (path === '$expr') {
if (typeof val !== 'object' || val == null) {
throw new Error('`$expr` must be an object');
}
val = cast$expr(val, schema);
continue;
} else if (path === '$elemMatch') {
val = cast(schema, val, options, context);
Expand Down
36 changes: 33 additions & 3 deletions lib/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const Schema = require('./schema');
const Collection = require('./driver').get().Collection;
const STATES = require('./connectionstate');
const MongooseError = require('./error/index');
const SyncIndexesError = require('./error/syncIndexes');
const PromiseProvider = require('./promise_provider');
const ServerSelectionError = require('./error/serverSelection');
const applyPlugins = require('./helpers/schema/applyPlugins');
Expand Down Expand Up @@ -1380,11 +1381,40 @@ Connection.prototype.setClient = function setClient(client) {
return this;
};

Connection.prototype.syncIndexes = async function syncIndexes() {
/**
*
* Syncs all the indexes for the models registered with this connection.
*
* @param {Object} options
* @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.
* @returns
*/
Connection.prototype.syncIndexes = async function syncIndexes(options = {}) {
const result = {};
for (const model in this.models) {
result[model] = await this.model(model).syncIndexes();
const errorsMap = { };

const { continueOnError } = options;
delete options.continueOnError;

for (const model of Object.values(this.models)) {
try {
result[model.modelName] = await model.syncIndexes(options);
} catch (err) {
if (!continueOnError) {
errorsMap[model.modelName] = err;
break;
} else {
result[model.modelName] = err;
}
}
}

if (!continueOnError && Object.keys(errorsMap).length) {
const message = Object.entries(errorsMap).map(([modelName, err]) => `${modelName}: ${err.message}`).join(', ');
const syncIndexesError = new SyncIndexesError(message, errorsMap);
throw syncIndexesError;
}

return result;
};

Expand Down
11 changes: 11 additions & 0 deletions lib/error/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,17 @@ MongooseError.OverwriteModelError = require('./overwriteModel');

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

/**
* Thrown when the MongoDB Node driver can't connect to a valid server
* to send an operation to.
*
* @api public
* @memberOf Error
* @static MongooseServerSelectionError
*/

MongooseError.MongooseServerSelectionError = require('./serverSelection');

/**
* An instance of this error will be returned if you used an array projection
* and then modified the array in an unsafe way.
Expand Down
30 changes: 30 additions & 0 deletions lib/error/syncIndexes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict';

/*!
* Module dependencies.
*/

const MongooseError = require('./mongooseError');

/**
* SyncIndexes Error constructor.
*
* @param {String} message
* @param {String} errorsMap
* @inherits MongooseError
* @api private
*/

class SyncIndexesError extends MongooseError {
constructor(message, errorsMap) {
super(message);
this.errors = errorsMap;
}
}

Object.defineProperty(SyncIndexesError.prototype, 'name', {
value: 'SyncIndexesError'
});


module.exports = SyncIndexesError;
3 changes: 2 additions & 1 deletion lib/helpers/model/discriminator.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const CUSTOMIZABLE_DISCRIMINATOR_OPTIONS = {
*/

module.exports = function discriminator(model, name, schema, tiedValue, applyPlugins) {

if (!(schema && schema.instanceOfSchema)) {
throw new Error('You must pass a valid discriminator Schema');
}
Expand Down Expand Up @@ -201,7 +202,7 @@ module.exports = function discriminator(model, name, schema, tiedValue, applyPlu

model.schema.discriminators[name] = schema;

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

Expand Down
Loading

0 comments on commit 998e778

Please sign in to comment.