<commit_before>[![Build Status](https://travis-ci.org/aldeed/meteor-simple-schema.png?branch=master)](https://travis-ci.org/aldeed/meteor-simple-schema)

SimpleSchema
=========================

*aldeed:simple-schema*

A simple, reactive schema validation package for Meteor. It's used by the [Collection2](https://github.com/aldeed/meteor-collection2) and [AutoForm](https://github.com/aldeed/meteor-autoform) packages, but you can use it by itself, too.

## Table of Contents

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents**  *generated with [DocToc](http://doctoc.herokuapp.com/)*

- [Installation](#installation)
- [Basic Usage](#basic-usage)
  - [Example](#example)
  - [Combining SimpleSchemas](#combining-simpleschemas)
  - [Extracting SimpleSchemas](#extracting-simpleschemas)
- [The Object to Validate](#the-object-to-validate)
- [Schema Keys](#schema-keys)
- [Schema Rules](#schema-rules)
  - [type](#type)
  - [label](#label)
  - [optional](#optional)
  - [min/max](#minmax)
  - [exclusiveMin/exclusiveMax](#exclusiveminexclusivemax)
  - [decimal](#decimal)
  - [minCount/maxCount](#mincountmaxcount)
  - [allowedValues](#allowedvalues)
  - [regEx](#regex)
  - [blackbox](#blackbox)
  - [trim](#trim)
  - [custom](#custom)
  - [defaultValue](#defaultvalue)
  - [autoValue](#autovalue)
- [Cleaning Data](#cleaning-data)
- [Validating Data](#validating-data)
  - [Named Validation Contexts](#named-validation-contexts)
  - [Unnamed Validation Contexts](#unnamed-validation-contexts)
  - [Validating an Object](#validating-an-object)
  - [Validating Only One Key in an Object](#validating-only-one-key-in-an-object)
  - [Validation Options](#validation-options)
  - [Validating Using check() or Match.test()](#validating-using-check-or-matchtest)
  - [Custom Validation](#custom-validation)
  - [Manually Adding a Validation Error](#manually-adding-a-validation-error)
  - [Asynchronous Custom Validation on the Client](#asynchronous-custom-validation-on-the-client)
  - [Getting a List of Invalid Keys and Validation Error Messages](#getting-a-list-of-invalid-keys-and-validation-error-messages)
  - [Other Validation Context Methods](#other-validation-context-methods)
  - [Other SimpleSchema Methods](#other-simpleschema-methods)
- [Customizing Validation Messages](#customizing-validation-messages)
- [Dates](#dates)
- [Collection2 and AutoForm](#collection2-and-autoform)
- [Best Practice Code Examples](#best-practice-code-examples)
  - [Make a field conditionally required](#make-a-field-conditionally-required)
  - [Validate one key against another](#validate-one-key-against-another)
- [Debug Mode](#debug-mode)
- [Extending the Schema Options](#extending-the-schema-options)
- [License](#license)
- [Contributing](#contributing)
  - [Thanks](#thanks)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

## Installation

In your Meteor app directory, enter:

```
$ meteor add aldeed:simple-schema
```

## Basic Usage

Create one or more SimpleSchema instances and then use them to validate objects. By adding the `aldeed:collection2` package to your app, you can attach them to collections to get automatic validation of your insert and update operations. By adding the `aldeed:autoform` package to your app, you can attach them to forms, making it easy to both generate and validate the forms from your schema.

### Example

```js
// Define the schema
BookSchema = new SimpleSchema({
  title: {
    type: String,
    label: "Title",
    max: 200
  },
  author: {
    type: String,
    label: "Author"
  },
  copies: {
    type: Number,
    label: "Number of copies",
    min: 0
  },
  lastCheckedOut: {
    type: Date,
    label: "Last date this book was checked out",
    optional: true
  },
  summary: {
    type: String,
    label: "Brief summary",
    optional: true,
    max: 1000
  }
});

// Validate an object against the schema
obj = {title: "Ulysses", author: "<NAME>"};

isValid = BookSchema.namedContext("myContext").validate(obj);
// OR
isValid = BookSchema.namedContext("myContext").validateOne(obj, "keyToValidate");
// OR
isValid = Match.test(obj, BookSchema);
// OR
check(obj, BookSchema);

// Validation errors are available through reactive methods
if (Meteor.isClient) {
  Meteor.startup(function() {
    Tracker.autorun(function() {
      var context = BookSchema.namedContext("myContext");
      if (!context.isValid()) {
        console.log(context.invalidKeys());
      }
    });
  });
}
```

### Combining SimpleSchemas

If you have schemas that share one or more subproperties, you can define them in a sub-schema
to make your code cleaner and more concise. Here's an example:

```js
AddressSchema = new SimpleSchema({
  street: {
    type: String,
    max: 100
  },
  city: {
    type: String,
    max: 50
  },
  state: {
    type: String,
    regEx: /^A[LKSZRAEP]|C[AOT]|D[EC]|F[LM]|G[AU]|HI|I[ADLN]|K[SY]|LA|M[ADEHINOPST]|N[CDEHJMVY]|O[HKR]|P[ARW]|RI|S[CD]|T[NX]|UT|V[AIT]|W[AIVY]$/
  },
  zip: {
    type: String,
    regEx: /^[0-9]{5}$/
  }
});

CustomerSchema = new SimpleSchema({
  billingAddress: {
    type: AddressSchema
  },
  shippingAddresses: {
    type: [AddressSchema],
    minCount: 1
  }
});
```

Alternatively, if you want to reuse mini-schemas in multiple places but you don't want a
subdocument like you get with sub-schemas, you can pass multiple schemas to
the SimpleSchema constructor, and they will be combined.

```js
cmsBaseSchema = new SimpleSchema({ ... });
cmsPageSchema = new SimpleSchema([cmsBaseSchema, {additionalField: {type: String} }]);
```

### Extracting SimpleSchemas

Sometimes you have one large SimpleSchema object, and you need just a subset of it for some purpose. To pull out certain schema keys into a new schema, you can use the `pick` method:

```js
var profileSchema = new SimpleSchema({
  firstName: {type: String},
  lastName: {type: String},
  username: {type: String}
});

var nameSchema = profileSchema.pick(['firstName', 'lastName']);
```

## The Object to Validate

The object you pass in when validating can be a normal object, or it can be
a Mongo modifier object (with `$set`, etc. keys). In other words, you can pass
in the exact object that you are going to pass to `Collection.insert()` or
`Collection.update()`. This is what the [collection2](https://atmospherejs.com/aldeed/collection2)
smart package does for you.

## Schema Keys

A basic schema key is just the name of the key (property) to expect in the
objects that will be validated. If necessary, though, you can use string
keys with mongo-style dot notation to validate nested arrays and objects.

For example:

```js
MySchema = new SimpleSchema({
    "mailingAddress.street": {
        type: String
    },
    "mailingAddress.city": {
        type: String
    }
});
```

To indicate the presence of an array, use a `$`:

```js
MySchema = new SimpleSchema({<commit_msg>Add documenation for edge case when using pick<commit_after>[![Build Status](https://travis-ci.org/aldeed/meteor-simple-schema.png?branch=master)](https://travis-ci.org/aldeed/meteor-simple-schema)

SimpleSchema
=========================

*aldeed:simple-schema*

A simple, reactive schema validation package for Meteor. It's used by the [Collection2](https://github.com/aldeed/meteor-collection2) and [AutoForm](https://github.com/aldeed/meteor-autoform) packages, but you can use it by itself, too.

## Table of Contents

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents**  *generated with [DocToc](http://doctoc.herokuapp.com/)*

- [Installation](#installation)
- [Basic Usage](#basic-usage)
  - [Example](#example)
  - [Combining SimpleSchemas](#combining-simpleschemas)
  - [Extracting SimpleSchemas](#extracting-simpleschemas)
- [The Object to Validate](#the-object-to-validate)
- [Schema Keys](#schema-keys)
- [Schema Rules](#schema-rules)
  - [type](#type)
  - [label](#label)
  - [optional](#optional)
  - [min/max](#minmax)
  - [exclusiveMin/exclusiveMax](#exclusiveminexclusivemax)
  - [decimal](#decimal)
  - [minCount/maxCount](#mincountmaxcount)
  - [allowedValues](#allowedvalues)
  - [regEx](#regex)
  - [blackbox](#blackbox)
  - [trim](#trim)
  - [custom](#custom)
  - [defaultValue](#defaultvalue)
  - [autoValue](#autovalue)
- [Cleaning Data](#cleaning-data)
- [Validating Data](#validating-data)
  - [Named Validation Contexts](#named-validation-contexts)
  - [Unnamed Validation Contexts](#unnamed-validation-contexts)
  - [Validating an Object](#validating-an-object)
  - [Validating Only One Key in an Object](#validating-only-one-key-in-an-object)
  - [Validation Options](#validation-options)
  - [Validating Using check() or Match.test()](#validating-using-check-or-matchtest)
  - [Custom Validation](#custom-validation)
  - [Manually Adding a Validation Error](#manually-adding-a-validation-error)
  - [Asynchronous Custom Validation on the Client](#asynchronous-custom-validation-on-the-client)
  - [Getting a List of Invalid Keys and Validation Error Messages](#getting-a-list-of-invalid-keys-and-validation-error-messages)
  - [Other Validation Context Methods](#other-validation-context-methods)
  - [Other SimpleSchema Methods](#other-simpleschema-methods)
- [Customizing Validation Messages](#customizing-validation-messages)
- [Dates](#dates)
- [Collection2 and AutoForm](#collection2-and-autoform)
- [Best Practice Code Examples](#best-practice-code-examples)
  - [Make a field conditionally required](#make-a-field-conditionally-required)
  - [Validate one key against another](#validate-one-key-against-another)
- [Debug Mode](#debug-mode)
- [Extending the Schema Options](#extending-the-schema-options)
- [License](#license)
- [Contributing](#contributing)
  - [Thanks](#thanks)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

## Installation

In your Meteor app directory, enter:

```
$ meteor add aldeed:simple-schema
```

## Basic Usage

Create one or more SimpleSchema instances and then use them to validate objects. By adding the `aldeed:collection2` package to your app, you can attach them to collections to get automatic validation of your insert and update operations. By adding the `aldeed:autoform` package to your app, you can attach them to forms, making it easy to both generate and validate the forms from your schema.

### Example

```js
// Define the schema
BookSchema = new SimpleSchema({
  title: {
    type: String,
    label: "Title",
    max: 200
  },
  author: {
    type: String,
    label: "Author"
  },
  copies: {
    type: Number,
    label: "Number of copies",
    min: 0
  },
  lastCheckedOut: {
    type: Date,
    label: "Last date this book was checked out",
    optional: true
  },
  summary: {
    type: String,
    label: "Brief summary",
    optional: true,
    max: 1000
  }
});

// Validate an object against the schema
obj = {title: "Ulysses", author: "<NAME>"};

isValid = BookSchema.namedContext("myContext").validate(obj);
// OR
isValid = BookSchema.namedContext("myContext").validateOne(obj, "keyToValidate");
// OR
isValid = Match.test(obj, BookSchema);
// OR
check(obj, BookSchema);

// Validation errors are available through reactive methods
if (Meteor.isClient) {
  Meteor.startup(function() {
    Tracker.autorun(function() {
      var context = BookSchema.namedContext("myContext");
      if (!context.isValid()) {
        console.log(context.invalidKeys());
      }
    });
  });
}
```

### Combining SimpleSchemas

If you have schemas that share one or more subproperties, you can define them in a sub-schema
to make your code cleaner and more concise. Here's an example:

```js
AddressSchema = new SimpleSchema({
  street: {
    type: String,
    max: 100
  },
  city: {
    type: String,
    max: 50
  },
  state: {
    type: String,
    regEx: /^A[LKSZRAEP]|C[AOT]|D[EC]|F[LM]|G[AU]|HI|I[ADLN]|K[SY]|LA|M[ADEHINOPST]|N[CDEHJMVY]|O[HKR]|P[ARW]|RI|S[CD]|T[NX]|UT|V[AIT]|W[AIVY]$/
  },
  zip: {
    type: String,
    regEx: /^[0-9]{5}$/
  }
});

CustomerSchema = new SimpleSchema({
  billingAddress: {
    type: AddressSchema
  },
  shippingAddresses: {
    type: [AddressSchema],
    minCount: 1
  }
});
```

Alternatively, if you want to reuse mini-schemas in multiple places but you don't want a
subdocument like you get with sub-schemas, you can pass multiple schemas to
the SimpleSchema constructor, and they will be combined.

```js
cmsBaseSchema = new SimpleSchema({ ... });
cmsPageSchema = new SimpleSchema([cmsBaseSchema, {additionalField: {type: String} }]);
```

### Extracting SimpleSchemas

Sometimes you have one large SimpleSchema object, and you need just a subset of it for some purpose. To pull out certain schema keys into a new schema, you can use the `pick` method:

```js
var profileSchema = new SimpleSchema({
  firstName: {type: String},
  lastName: {type: String},
  username: {type: String}
});

var nameSchema = profileSchema.pick(['firstName', 'lastName']);
```

**NOTE**: When using `pick` on a field of type Array you also need to pick the array item field.
Take the following as an example:

```js
var profileSchema = new SimpleSchema({
  firstName: {
    type: String
  },
  lastName: {
    type: String
  },
  comments: {
    type: [String]
  }
});

var nameSchema = profileSchema.pick('comments', 'comments.$');
```

## The Object to Validate

The object you pass in when validating can be a normal object, or it can be
a Mongo modifier object (with `$set`, etc. keys). In other words, you can pass
in the exact object that you are going to pass to `Collection.insert()` or
`Collection.update()`. This is what the [collection2](https://atmospherejs.com/aldeed/collection2)
smart package does for you.

## Schema Keys

A basic schema key is just the name of the key (property) to expect in the
objects that will be validated. If necessary, though, you can use string
keys with mongo-style dot notation to validate nested arrays and objects.

For example:

```js
MySchema = new SimpleSchema({
    "mailingAddress.street": {
        type: String
    },
    "mailingAddress.city": {
        type: String
    }
});
```

To indicate the presence of an array, use a `$`:

```js
MySchema = new SimpleSchema({
{'fraction_non_alphanumeric': 0.1398732855253081, 'fraction_numerical': 0.0033419202116549466, 'mean_word_length': 4.221374045801527, 'pattern_counts': {'":': 4, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 10, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7070623', 'n_tokens_mistral': 4702, 'n_tokens_neox': 4400, 'n_words': 1337}