Skip to content

Commit

Permalink
Merge pull request #12466 from Automattic/vkarpov15/gh-12430
Browse files Browse the repository at this point in the history
docs(validation): add section on global schematype validation, clean up other issues
  • Loading branch information
vkarpov15 committed Sep 25, 2022
2 parents e6ac7e8 + 4fcf0a5 commit f50ec33
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 49 deletions.
40 changes: 27 additions & 13 deletions docs/validation.md
Expand Up @@ -15,6 +15,20 @@ Before we get into the specifics of validation syntax, please keep the following
[require:Validation$]
```

- [Built-in Validators](#built-in-validators)
- [Custom Error Messages](#custom-error-messages)
- [The `unique` Option is Not a Validator](#the-unique-option-is-not-a-validator)
- [Custom Validators](#custom-validators)
- [Async Custom Validators](#async-custom-validators)
- [Validation Errors](#validation-errors)
- [Cast Errors](#cast-errors)
- [Global SchemaType Validation](#global-schematype-validation)
- [Required Validators On Nested Objects](#required-validators-on-nested-objects)
- [Update Validators](#update-validators)
- [Update Validators and `this`](#update-validators-and-this)
- [Update Validators Only Run On Updated Paths](#update-validators-only-run-on-updated-paths)
- [Update Validators Only Run For Some Operations](#update-validators-only-run-for-some-operations)

### Built-in Validators

Mongoose has several built-in validators.
Expand Down Expand Up @@ -107,6 +121,15 @@ fails. That means your custom validators may assume `v` is `null`,
[require:Cast Errors]
```

### Global SchemaType Validation

In addition to defining custom validators on individual schema paths, you can also configure a custom validator to run on every instance of a given `SchemaType`.
For example, the following code demonstrates how to make empty string `''` an invalid value for _all_ string paths.

```javascript
[require:Global SchemaType Validation]
```

### Required Validators On Nested Objects

Defining validators on nested objects in mongoose is tricky, because
Expand Down Expand Up @@ -148,15 +171,6 @@ not defined.
[require:Update Validators and `this`]
```

### The `context` option

The `context` option lets you set the value of `this` in update validators
to the underlying query.

```javascript
[require:The `context` option]
```

### Update Validators Only Run On Updated Paths

The other key difference is that update validators only run on the paths
Expand All @@ -178,10 +192,10 @@ following update operators:

- `$set`
- `$unset`
- `$push` (>= 4.8.0)
- `$addToSet` (>= 4.8.0)
- `$pull` (>= 4.12.0)
- `$pullAll` (>= 4.12.0)
- `$push`
- `$addToSet`
- `$pull`
- `$pullAll`

For instance, the below update will succeed, regardless of the value of
`number`, because update validators ignore `$inc`.
Expand Down
63 changes: 27 additions & 36 deletions test/docs/validation.test.js
Expand Up @@ -380,6 +380,33 @@ describe('validation docs', function() {
// acquit:ignore:end
});

it('Global SchemaType Validation', async function() {
// Add a custom validator to all strings
mongoose.Schema.Types.String.set('validate', v => v == null || v > 0);

const userSchema = new Schema({
name: String,
email: String
});
// acquit:ignore:start
db.deleteModel(/User/);
// acquit:ignore:end
const User = db.model('User', userSchema);

const user = new User({ name: '', email: '' });

const err = await user.validate().then(() => null, err => err);
err.errors['name']; // ValidatorError
err.errors['email']; // ValidatorError
// acquit:ignore:start
assert.ok(err);
assert.equal(err.errors['name'].name, 'ValidatorError');
assert.equal(err.errors['email'].name, 'ValidatorError');

delete mongoose.Schema.Types.String.defaultOptions;
// acquit:ignore:end
});

/**
* Defining validators on nested objects in mongoose is tricky, because
* nested objects are not fully fledged paths.
Expand Down Expand Up @@ -503,42 +530,6 @@ describe('validation docs', function() {
assert.ok(error);
});

/**
* The `context` option lets you set the value of `this` in update validators
* to the underlying query.
*/

it('The `context` option', async function() {
// acquit:ignore:start
const toySchema = new Schema({
color: String,
name: String
});
// acquit:ignore:end
toySchema.path('color').validate(function(value) {
// When running update validators, `this` refers to the query object.
if (this.getUpdate().$set.name.toLowerCase().indexOf('red') !== -1) {
return value === 'red';
}
return true;
});

const Toy = db.model('Figure', toySchema);

const update = { color: 'blue', name: 'Red Power Ranger' };
// Note the context option
const opts = { runValidators: true, context: 'query' };

let error;
try {
await Toy.updateOne({}, update, opts);
} catch (err) {
error = err;
}

assert.ok(error.errors['color']);
});

/**
* The other key difference is that update validators only run on the paths
* specified in the update. For instance, in the below example, because
Expand Down

0 comments on commit f50ec33

Please sign in to comment.