Code Monkey home page Code Monkey logo

meteor-simple-schema's Introduction

Meteor SimpleSchema

Meteor Community Package Test suite CodeQL Project Status: Active โ€“ The project has reached a stable, usable state and is being actively developed. GitHub License

Attention! ๐Ÿง

This package is back under maintenance by the Meteor Community Packages group ๐Ÿš€ Consider this a hard-fork to ensure a future-proof maintenance with focus on Meteor-Compatibility (Meteor 2.x; 3.x and beyond)! โ˜„๏ธ

About this package

SimpleSchema validates JavaScript objects to ensure they match a schema. It can also clean the objects to automatically convert types, remove unsupported properties, and add automatic values such that the object is then more likely to pass validation.

There are a lot of similar packages for validating objects. These are some of the features of this package that might be good reasons to choose this one over another:

  • Isomorphic. Works on Server and Client
  • The object you validate can be a MongoDB modifier. SimpleSchema understands how to properly validate it such that the object in the database, after undergoing modification, will be valid.
  • Optional Tracker reactivity
  • Powerful customizable error message system with decent English language defaults and support for localization, which makes it easy to drop this package in and display the validation error messages to end users.
  • Has hundreds of tests and is used in production apps of various sizes
  • Used by the Collection2 and AutoForm Meteor packages.

There are also reasons not to choose this package. Because of all it does, this package is more complex than (but still "simple" :) ) and slower than some other packages. Based on your needs, you should decide whether these tradeoffs are acceptable. One faster but less powerful option is simplecheck.

Table of Contents

The History of SimpleSchema

SimpleSchema was first released as a Meteor package in mid-2013. Version 1.0 was released in September 2014. In mid-2016, new versions were released as an NPM package, which can be used in Meteor, NodeJS, or static browser apps. Afterwards it has been archived in favour of the NPM version.

In 2022/2023 the NPM package has dropped all Meteor compatibility and this package got released again, starting with the latest commit that included full Meteor support.

Installation

meteor add aldeed:simple-schema

Make sure, you installed version 2.0.0 or grater!

Lingo

In this documentation:

  • "key", "field", and "property" generally all mean the same thing: an identifier for some part of an object that is validated by your schema. SimpleSchema uses dot notation to identify nested keys.
  • "validate" means to check whether an object matches what you expect, for example, having the expected keys with the expected data types, expected string lengths, etc.

Quick Start

Validate an Object and Throw an Error

import SimpleSchema from "meteor/aldeed:simple-schema";

new SimpleSchema({
  name: String,
}).validate({
  name: 2,
});

Validate an Array of Objects and Throw an Error

An error is thrown for the first invalid object found.

import SimpleSchema from "meteor/aldeed:simple-schema";

new SimpleSchema({
  name: String,
}).validate([{ name: "Bill" }, { name: 2 }]);

Validate a Meteor Method Argument and Satisfy audit-argument-checks

To avoid errors about not checking all arguments when you are using SimpleSchema to validate Meteor method arguments, you must pass check as an option when creating your SimpleSchema instance.

import SimpleSchema from "meteor/aldeed:simple-schema";
import { check } from "meteor/check";
import { Meteor } from "meteor/meteor";

SimpleSchema.defineValidationErrorTransform((error) => {
  const ddpError = new Meteor.Error(error.message);
  ddpError.error = "validation-error";
  ddpError.details = error.details;
  return ddpError;
});

const myMethodObjArgSchema = new SimpleSchema({ name: String }, { check });

Meteor.methods({
  myMethod(obj) {
    myMethodObjArgSchema.validate(obj);

    // Now do other method stuff knowing that obj satisfies the schema
  },
});

Validate an Object and Get the Errors

import SimpleSchema from "meteor/aldeed:simple-schema";

const validationContext = new SimpleSchema({
  name: String,
}).newContext();

validationContext.validate({
  name: 2,
});

console.log(validationContext.isValid());
console.log(validationContext.validationErrors());

Validate a MongoDB Modifier

import SimpleSchema from "meteor/aldeed:simple-schema";

const validationContext = new SimpleSchema({
  name: String,
}).newContext();

validationContext.validate(
  {
    $set: {
      name: 2,
    },
  },
  { modifier: true }
);

console.log(validationContext.isValid());
console.log(validationContext.validationErrors());

Enable Meteor Tracker Reactivity

import SimpleSchema from "meteor/aldeed:simple-schema";
import { Tracker } from "meteor/tracker";

const validationContext = new SimpleSchema(
  {
    name: String,
  },
  { tracker: Tracker }
).newContext();

Tracker.autorun(function () {
  console.log(validationContext.isValid());
  console.log(validationContext.validationErrors());
});

validationContext.validate({
  name: 2,
});

validationContext.validate({
  name: "Joe",
});

Passing in Tracker causes the following functions to become reactive:

  • ValidationContext#keyIsInvalid
  • ValidationContext#keyErrorMessage
  • ValidationContext#isValid
  • ValidationContext#validationErrors
  • SimpleSchema#label

Automatically Clean the Object Before Validating It

TO DO

Set Default Options for One Schema

import SimpleSchema from "meteor/aldeed:simple-schema";

const mySchema = new SimpleSchema(
  {
    name: String,
  },
  {
    clean: {
      autoConvert: true,
      extendAutoValueContext: {},
      filter: false,
      getAutoValues: true,
      removeEmptyStrings: true,
      removeNullsFromArrays: false,
      trimStrings: true,
    },
    humanizeAutoLabels: false,
    requiredByDefault: true,
  }
);

These options will be used every time you clean or validate with this particular SimpleSchema instance.

Set Default Options for All Schemas

import SimpleSchema from "meteor/aldeed:simple-schema";

SimpleSchema.constructorOptionDefaults({
  clean: {
    filter: false,
  },
  humanizeAutoLabels: false,
});

// If you don't pass in any options, it will return the current defaults.
console.log(SimpleSchema.constructorOptionDefaults());

These options will be used every time you clean or validate with any SimpleSchema instance, but can be overridden by options passed in to the constructor for a single instance.

Important notes:

  • You must call SimpleSchema.constructorOptionDefaults before any of your schemas are created, so put it in an entry-point file and/or at the top of your code file.
  • In a large, complex project where SimpleSchema instances might be created by various JavaScript packages, there may be multiple SimpleSchema objects. In other words, the import SimpleSchema line in one package might be pulling in the SimpleSchema object from one package while that line in another package pulls in a completely different SimpleSchema object. It will be difficult to know that this is happening unless you notice that your defaults are not being used by some of your schemas. To solve this, you can call SimpleSchema.constructorOptionDefaults multiple times or adjust your package dependencies to ensure that only one version of simpl-schema is pulled into your project.

Explicitly Clean an Object

import SimpleSchema from "meteor/aldeed:simple-schema";

const mySchema = new SimpleSchema({ name: String });
const doc = { name: 123 };
const cleanDoc = mySchema.clean(doc);
// cleanDoc is now mutated to hopefully have a better chance of passing validation
console.log(typeof cleanDoc.name); // string

Works for a MongoDB modifier, too:

import SimpleSchema from "meteor/aldeed:simple-schema";

const mySchema = new SimpleSchema({ name: String });
const modifier = { $set: { name: 123 } };
const cleanModifier = mySchema.clean(modifier);
// doc is now mutated to hopefully have a better chance of passing validation
console.log(typeof cleanModifier.$set.name); // string

Defining a Schema

Let's get into some more details about the different syntaxes that are supported when defining a schema. It's probably best to start with the simplest syntax. Here's an example:

Shorthand Definitions

import SimpleSchema from "meteor/aldeed:simple-schema";

const schema = new SimpleSchema({
  name: String,
  age: SimpleSchema.Integer,
  registered: Boolean,
});

This is referred to as "shorthand" syntax. You simply map a property name to a type. When validating, SimpleSchema will make sure that all of those properties are present and are set to a value of that type.

Longhand Definitions

In many cases, you will need to use longhand in order to define additional rules beyond what the data type should be.

import SimpleSchema from "meteor/aldeed:simple-schema";

const schema = new SimpleSchema({
  name: {
    type: String,
    max: 40,
  },
  age: {
    type: SimpleSchema.Integer,
    optional: true,
  },
  registered: {
    type: Boolean,
    defaultValue: false,
  },
});

Mixing Shorthand with Longhand

You can use any combination of shorthand and longhand:

import SimpleSchema from "meteor/aldeed:simple-schema";

const schema = new SimpleSchema({
  name: String,
  age: {
    type: SimpleSchema.Integer,
    optional: true,
  },
  registered: Boolean,
});

More Shorthand

If you set the schema key to a regular expression, then the type will be String and the string must match the provided regular expression.

For example, this:

{
  exp: /foo/;
}

is equivalent to:

{
  exp: { type: String, regEx: /foo/ }
}

You can also set the schema key to an array of some type:

{
  friends: [String],
}

is equivalent to:

{
  friends: { type: Array },
  'friends.$': { type: String },
}

Note: This only applies to shorthand definitions, not to the longhand definition. This example will throw an error { friends: { type: [String] } } even though it was valid in the meteor-version of this package.

Multiple Definitions For One Key

You can define two or more different ways in which a key will be considered valid:

import SimpleSchema from "meteor/aldeed:simple-schema";

const schema = new SimpleSchema({
  id: SimpleSchema.oneOf(String, SimpleSchema.Integer),
  name: String,
});

And this can be done in any mixture of shorthand and longhand:

import SimpleSchema from "meteor/aldeed:simple-schema";

const schema = new SimpleSchema({
  id: SimpleSchema.oneOf(
    {
      type: String,
      min: 16,
      max: 16,
    },
    {
      type: SimpleSchema.Integer,
      min: 0,
    }
  ),
  name: String,
});

When one of the allowed types is an object, use a subschema. Don't mix the object property definitions in with the main schema.

Correct:

import SimpleSchema from "meteor/aldeed:simple-schema";

const objSchema = new SimpleSchema({
  _id: String,
});

const schema = new SimpleSchema({
  foo: SimpleSchema.oneOf(String, objSchema),
});

Incorrect:

import SimpleSchema from "meteor/aldeed:simple-schema";

const schema = new SimpleSchema({
  foo: SimpleSchema.oneOf(String, Object),
  "foo._id": {
    type: String,
    optional: true,
  },
});

NOTE: Multiple definitions is still an experimental feature and may not work as you expect in complex situations, such as where one of the valid definitions is an object or array. By reporting any weirdness you experience, you can help make it more robust.

Extending Schemas

If there are certain fields that are repeated in many of your schemas, it can be useful to define a SimpleSchema instance just for those fields and then merge them into other schemas:

import SimpleSchema from "meteor/aldeed:simple-schema";
import { idSchema, addressSchema } from "./sharedSchemas";

const schema = new SimpleSchema({
  name: String,
});
schema.extend(idSchema);
schema.extend(addressSchema);

Overriding When Extending

If the key appears in both schemas, the definition will be extended such that the result is the combination of both definitions.

import SimpleSchema from "meteor/aldeed:simple-schema";
import { idSchema, addressSchema } from "./sharedSchemas";

const schema = new SimpleSchema({
  name: {
    type: String,
    min: 5,
  },
});
schema.extend({
  name: {
    type: String,
    max: 15,
  },
});

The above will result in the definition of the name field becoming:

{
  name: {
    type: String,
    min: 5,
    max: 15,
  },
}

Note also that a plain object was passed to extend. If you pass a plain object, it is converted to a SimpleSchema instance for you.

Subschemas

Similar to extending, you can also reference other schemas as a way to define objects that occur within the main object:

import SimpleSchema from "meteor/aldeed:simple-schema";
import { addressSchema } from "./sharedSchemas";

const schema = new SimpleSchema({
  name: String,
  homeAddress: addressSchema,
  billingAddress: {
    type: addressSchema,
    optional: true,
  },
});

Extracting Schemas

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:

import SimpleSchema from "meteor/aldeed:simple-schema";

const schema = new SimpleSchema({
  firstName: String,
  lastName: String,
  username: String,
});

const nameSchema = schema.pick("firstName", "lastName");

To keep all but certain keys in a new schema, you can use the omit method:

import SimpleSchema from "meteor/aldeed:simple-schema";

const schema = new SimpleSchema({
  firstName: String,
  lastName: String,
  username: String,
});

const nameSchema = schema.omit("username");

To pull a subschema out of an Object key in a larger schema, you can use getObjectSchema:

import SimpleSchema from "meteor/aldeed:simple-schema";

const schema = new SimpleSchema({
  firstName: String,
  lastName: String,
  address: Object,
  "address.street1": String,
  "address.street2": { type: String, optional: true },
  "address.city": String,
  "address.state": String,
  "address.postalCode": String,
});

const addressSchema = schema.getObjectSchema("address");

// addressSchema is now the same as this:
// new SimpleSchema({
//   street1: String,
//   street2: { type: String, optional: true },
//   city: String,
//   state: String,
//   postalCode: String,
// });

Raw Definition

Sometimes if you want to get the rawDefinition of some schema just pass in the options { keepRawDefinition: true}(if not arg is passed the value will be null). Example:

const userSchema = new SimpleSchema(
  {
    name: String,
    number: "SimpleSchema.Integer",
    email: String,
  },
  { keepRawDefintion: true }
);
userSchema.rawDefinition;
//{
//   name: String,
//   number: 'SimpleSchema.Integer',
//   email: String
//}

Schema Keys

A basic schema key is just the name of the key (property) to expect in the objects that will be validated.

Use string keys with MongoDB-style dot notation to validate nested arrays and objects. For example:

import SimpleSchema from "meteor/aldeed:simple-schema";

const schema = new SimpleSchema({
  mailingAddress: Object,
  "mailingAddress.street": String,
  "mailingAddress.city": String,
});

To indicate array items, use a $:

import SimpleSchema from "meteor/aldeed:simple-schema";

const schema = new SimpleSchema({
  addresses: {
    type: Array,
    minCount: 1,
    maxCount: 4,
  },
  "addresses.$": Object,
  "addresses.$.street": String,
  "addresses.$.city": String,
});

Schema Rules

Here are some specifics about the various rules you can define in your schema.

type

One of the following:

  • String
  • Number
  • SimpleSchema.Integer (same as Number but with decimals/floats disallowed)
  • Boolean
  • Object
  • Array
  • Any custom or built-in class like Date
  • Another SimpleSchema instance, meaning Object type with this schema
  • SimpleSchema.oneOf(...), with multiple of the above types

label

Can also be a function that returns the label

A string that will be used to refer to this field in validation error messages. The default is an inflected (humanized) derivation of the key name itself. For example, the key "firstName" will have a default label of "First name" if you do not include the label property in your definition.

You can use the labels function to alter one or more labels on the fly:

schema.labels({
  password: "Enter your password",
});

If you have enabled Tracker reactivity, this method causes reactive labels to update.

To get the label for a field, use schema.label(fieldName), which returns a usable string. If you have enabled Tracker reactivity, this method is reactive.

optional

Can also be a function that returns true or false

By default, all keys are required. Set optional: true to change that.

With complex keys, it might be difficult to understand what "required" means. Here's a brief explanation of how requiredness is interpreted:

  • If type is Array, then "required" means that key must have a value, but an empty array is fine. (If an empty array is not fine, add the minCount: 1 option.)
  • For array items (when the key name ends with ".$"), if optional is true, then null values are valid. If array items are required, then any null items will fail the type check.
  • If a key is required at a deeper level, the key must have a value only if the object it belongs to is present.
  • When the object being validated is a Mongo modifier object, changes that would unset or null a required key result in validation errors.

That last point can be confusing, so let's look at a couple examples:

  • Say you have a required key "friends.address.city" but "friends.address" is optional. If "friends.address" is set in the object you're validating, but "friends.address.city" is not, there is a validation error. However, if "friends.address" is not set, then there is no validation error for "friends.address.city" because the object it belongs to is not present.
  • If you have a required key "friends.$.name", but the friends array has no objects in the object you are validating, there is no validation error for "friends.$.name". When the friends array does have objects, every present object is validated, and each object could potentially have a validation error if it is missing the name property. For example, when there are two objects in the friends array and both are missing the name property, there will be a validation error for both "friends.0.name" and "friends.1.name".

required

Can also be a function that returns true or false

If you would rather have all your schema keys be optional by default, pass the requiredByDefault: false option and then use required: true to make individual keys required.

const schema = new SimpleSchema(
  {
    optionalProp: String,
    requiredProp: { type: String, required: true },
  },
  { requiredByDefault: false }
);

min/max

Can also be a function that returns the min/max value

  • If type is Number or SimpleSchema.Integer, these rules define the minimum or maximum numeric value.
  • If type is String, these rules define the minimum or maximum string length.
  • If type is Date, these rules define the minimum or maximum date, inclusive.

You can alternatively provide a function that takes no arguments and returns the appropriate minimum or maximum value. This is useful, for example, if the minimum Date for a field should be "today".

exclusiveMin/exclusiveMax

Can also be a function that returns true or false

Set to true to indicate that the range of numeric values, as set by min/max, are to be treated as an exclusive range. Set to false (default) to treat ranges as inclusive.

minCount/maxCount

Can also be a function that returns the minCount/maxCount value

Define the minimum or maximum array length. Used only when type is Array.

allowedValues

Can also be a function that returns the array or the Set of allowed values

An array or a Set of values that are allowed. A key will be invalid if its value is not one of these.

You can use schema.getAllowedValuesForKey(key) to get the allowed values array for a key.

Note: If you wish to restrict the items allowed in an Array, the allowedValues property must be on the array item definition.

const schema = new SimpleSchema({
  myArray: {
    type: Array,
  },
  "myArray.$": {
    type: String,
    allowedValues: ["foo", "bar"],
  },
});

regEx

Can also be a function that returns a regular expression or an array of them

Any regular expression that must be matched for the key to be valid, or an array of regular expressions that will be tested in order.

The SimpleSchema.RegEx object defines standard regular expressions you can use as the value for the regEx key.

  • SimpleSchema.RegEx.Email for emails (uses a permissive regEx recommended by W3C, which most browsers use. Does not require a TLD)
  • SimpleSchema.RegEx.EmailWithTLD for emails that must have the TLD portion (.com, etc.). Emails like me@localhost and [email protected] won't pass this one.
  • SimpleSchema.RegEx.Domain for external domains and the domain only (requires a tld like .com)
  • SimpleSchema.RegEx.WeakDomain for less strict domains and IPv4 and IPv6
  • SimpleSchema.RegEx.IP for IPv4 or IPv6
  • SimpleSchema.RegEx.IPv4 for just IPv4
  • SimpleSchema.RegEx.IPv6 for just IPv6
  • SimpleSchema.RegEx.Url for http, https and ftp urls
  • SimpleSchema.RegEx.Id for IDs generated by Random.id() of the random package, also usable to validate a relation id.
  • SimpleSchema.RegEx.idOfLength(min, max) for IDs generated by Random.id(length) where min/max define lower and upper bounds. Call without params for allowing an arbitrary length. Call with min only for fixed length. Call with max = null for fixed lower and arbitrary upper bounds.
  • SimpleSchema.RegEx.ZipCode for 5- and 9-digit ZIP codes
  • SimpleSchema.RegEx.Phone for phone numbers (taken from Google's libphonenumber library)

skipRegExCheckForEmptyStrings

Can also be a function that returns true or false

Set to true when regEx is set if you want an empty string to always pass validation, even though the regular expression may disallow it.

blackbox

If you have a key with type Object, the properties of the object will be validated as well, so you must define all allowed properties in the schema. If this is not possible or you don't care to validate the object's properties, use the blackbox: true option to skip validation for everything within the object.

Prior to SimpleSchema 2.0, objects that are instances of a custom class were considered to be blackbox by default. This is no longer true, so if you do not want your class instance validated, be sure to add blackbox: true in your schema.

trim

Used by the cleaning process but not by validation

When you call simpleSchemaInstance.clean() with trimStrings set to true, all string values are trimmed of leading and trailing whitespace. If you set trim to false for certain keys in their schema definition, those keys will be skipped.

custom

Refer to the Custom Validation section.

defaultValue

Used by the cleaning process but not by validation

Set this to any value that you want to be used as the default when an object does not include this field or has this field set to undefined. This value will be injected into the object by a call to mySimpleSchema.clean() with getAutovalues: true.

Note the following points of confusion:

  • A default value itself is not cleaned. So, for example, if your default value is "", it will not be removed by the removeEmptyStrings operation in the cleaning.
  • A default value is added only if there isn't a value set AND the parent object exists. Usually this is what you want, but if you need to ensure that it will always be added, you can add defaultValue: {} to all ancestor objects.

If you need more control, use the autoValue option instead.

To get the defaultValue for a field, use schema.defaultValue(fieldName). It is a shorthand for schema.get(fieldName, 'defaultValue').

autoValue

Used by the cleaning process but not by validation

The autoValue option allows you to specify a function that is called by simpleSchemaInstance.clean() to potentially change the value of a property in the object being cleaned. This is a powerful feature that allows you to set up either forced values or default values, potentially based on the values of other fields in the object.

An autoValue function this context provides a variety of properties and methods to help you determine what you should return:

  • this.closestSubschemaFieldName: If your schema is used as a subschema in another schema, this will be set to the name of the key that references the schema. Otherwise it will be null.
  • this.field(): Use this method to get information about other fields. Pass a field name (schema key) as the only argument. The return object will have isSet, value, and operator properties for that field.
  • this.genericKey: The generic schema key for which the autoValue is running ($ in place of actual array index).
  • this.isInArrayItemObject: True if we're traversing an object that's in an array.
  • this.isInSubObject: True if we're traversing an object that's somewhere within another object.
  • this.isModifier: True if this is running on a MongoDB modifier object.
  • this.isSet: True if the field is already set in the document or modifier
  • this.key: The schema key for which the autoValue is running. This is usually known, but if your autoValue function is shared among various keys or if your schema is used as a subschema in another schema, this can be useful.
  • this.obj: The full object.
  • this.operator: If isSet = true and isUpdate = true, this contains the name of the update operator in the modifier in which this field is being changed. For example, if the modifier were {$set: {name: "Alice"}}, in the autoValue function for the name field, this.isSet would be true, this.value would be "Alice", and this.operator would be "$set".
  • this.parentField(): Use this method to get information about the parent object. Works the same way as field().
  • this.siblingField(): Use this method to get information about other fields that have the same parent object. Works the same way as field(). This is helpful when you use sub-schemas or when you're dealing with arrays of objects.
  • this.unset(): Call this method to prevent the original value from being used when you return undefined.
  • this.value: If isSet = true, this contains the field's current (requested) value in the document or modifier.

If an autoValue function does not return anything (i.e., returns undefined), the field's value will be whatever the document or modifier says it should be. If that field is already in the document or modifier, it stays in the document or modifier with the same value. If it's not in the document or modifier, it's still not there. If you don't want it to be in the doc or modifier, you must call this.unset().

Any other return value will be used as the field's value. You may also return special pseudo-modifier objects for update operations. Examples are {$inc: 1} and {$push: new Date}.

autoValue gotchas

  • If your autoValue for one field relies on the autoValue or defaultValue of another field, make sure that the other field is listed before the field that relies on it in the schema. autoValues are run in order from least nested, to most nested, so you can assume that parent values will be set, but for fields at the same level, schema order matters. Refer to issue #204.
  • An autoValue function will always run during cleaning even if that field is not in the object being cleaned. This allows you to provide complex default values. If your function applies only when there is a value, you should add if (!this.isSet) return; at the top.

Function Properties

You may have noticed that many of the rule properties can be set to functions that return the value. If you do this, the this context within those functions will have the following properties:

  • this.field(): Use this method to get information about other fields. Pass a field name (schema key) as the only argument. The return object will have isSet, value, and operator properties for that field.
  • this.genericKey: The generic schema key for which the autoValue is running ($ in place of actual array index).
  • this.isInArrayItemObject: True if we're traversing an object that's in an array.
  • this.isInSubObject: True if we're traversing an object that's somewhere within another object.
  • this.isModifier: True if this is running on a MongoDB modifier object.
  • this.isSet: True if the field is already set in the document or modifier
  • this.key: The schema key for which the autoValue is running. This is usually known, but if your autoValue function is shared among various keys or if your schema is used as a subschema in another schema, this can be useful.
  • this.obj: The full object.
  • this.operator: If isSet = true and isUpdate = true, this contains the name of the update operator in the modifier in which this field is being changed. For example, if the modifier were {$set: {name: "Alice"}}, in the autoValue function for the name field, this.isSet would be true, this.value would be "Alice", and this.operator would be "$set".
  • this.parentField(): Use this method to get information about the parent object. Works the same way as field().
  • this.siblingField(): Use this method to get information about other fields that have the same parent object. Works the same way as field(). This is helpful when you use sub-schemas or when you're dealing with arrays of objects.
  • this.validationContext: The current validation context
  • this.value: If isSet = true, this contains the field's current (requested) value in the document or modifier.

Getting field properties

To obtain field's property value, just call the get method.

const schema = new SimpleSchema({
  friends: {
    type: Array,
    minCount: 0,
    maxCount: 3,
  },
});

schema.get("friends", "maxCount"); // 3

Validating Data

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 package does for you.

Ways to Perform Validation

There are three ways to validate an object against your schema:

  1. With a throwaway context, throwing an Error for the first validation error found (schema.validate())
  2. With a unique unnamed validation context, not throwing any Errors (schema.newContext().validate())
  3. With a unique named validation context, not throwing any Errors (schema.namedContext('someUniqueString').validate())
  4. With the default validation context, not throwing any Errors. (schema.namedContext().validate())

A validation context provides reactive methods for validating and checking the validation status of a particular object.

Named Validation Contexts

It's usually best to use a named validation context. That way, the context is automatically persisted by name, allowing you to easily rely on its reactive methods.

Here is an example of obtaining a named validation context:

import SimpleSchema from "meteor/aldeed:simple-schema";

const schema = new SimpleSchema({
  name: String,
});

const userFormValidationContext = schema.namedContext("userForm");

The first time you request a context with a certain name, it is created. Calling namedContext() passing no arguments is equivalent to calling namedContext('default').

Unnamed Validation Contexts

To obtain an unnamed validation context, call newContext():

import SimpleSchema from "meteor/aldeed:simple-schema";

const schema = new SimpleSchema({
  name: String,
});

const myValidationContext = schema.newContext();

An unnamed validation context is not persisted anywhere. It can be useful when you need to see if a document is valid but you don't need any of the reactive methods for that context, or if you are going to keep the context reference in memory yourself.

Validating an Object

To validate an object against the schema in a validation context, call validationContextInstance.validate(obj, options). This method returns true if the object is valid according to the schema or false if it is not. It also stores a list of invalid fields and corresponding error messages in the context object and causes the reactive methods to react if you injected Tracker reactivity.

You can call myContext.isValid() to see if the object last passed into validate() was found to be valid. This is a reactive method that returns true or false.

For a list of options, see the Validation Options section.

Validating Only Some Keys in an Object

You may have the need to (re)validate certain keys while leaving any errors for other keys unchanged. For example, if you have several errors on a form and you want to revalidate only the invalid field the user is currently typing in. For this situation, call myContext.validate with the keys option set to an array of keys that should be validated. This may cause all of the reactive methods to react.

This method returns true only if all the specified schema keys and their descendent keys are valid according to the schema. Otherwise it returns false.

Validation Options

validate() accepts the following options:

  • modifier: Are you validating a Mongo modifier object? False by default.
  • upsert: Are you validating a Mongo modifier object potentially containing upsert operators? False by default.
  • extendedCustomContext: This object will be added to the this context in any custom validation functions that are run during validation. See the Custom Validation section.
  • ignore: An array of validation error types (in SimpleSchema.ErrorTypes enum) to ignore.
  • keys: An array of keys to validate. If not provided, revalidates the entire object.

Validating and Throwing ValidationErrors

  • Call mySimpleSchema.validate(obj, options) to validate obj against the schema and throw a ValidationError if invalid.
  • Call SimpleSchema.validate(obj, schema, options) static function as a shortcut for mySimpleSchema.validate if you don't want to create mySimpleSchema first. The schema argument can be just the schema object, in which case it will be passed to the SimpleSchema constructor for you. This is like check(obj, schema) but without the check dependency and with the ability to pass full schema error details back to a callback on the client.
  • Call mySimpleSchema.validator() to get a function that calls mySimpleSchema.validate for whatever object is passed to it. This means you can do validate: mySimpleSchema.validator() in the mdg:validated-method package.
  • Call mySimpleSchema.getFormValidator() to get a function that validates whatever object is passed to it and returns a Promise that resolves with errors. The returned function is compatible with the Composable Form Specification.

Customize the Error That is Thrown

You can defineValidationErrorTransform one time somewhere in your code to customize the error or change it to a more specific type.

import SimpleSchema from "meteor/aldeed:simple-schema";

SimpleSchema.defineValidationErrorTransform((error) => {
  const customError = new MyCustomErrorType(error.message);
  customError.errorList = error.details;
  return customError;
});

For example, in a Meteor app, in order to ensure that the error details are sent back to the client when throwing an error in a server method, you can convert it to a Meteor.Error:

import SimpleSchema from "meteor/aldeed:simple-schema";

SimpleSchema.defineValidationErrorTransform((error) => {
  const ddpError = new Meteor.Error(error.message);
  ddpError.error = "validation-error";
  ddpError.details = error.details;
  return ddpError;
});

Custom Field Validation

There are three ways to attach custom validation methods.

To add a custom validation function that is called for ALL keys in ALL schemas (for example, to publish a package that adds global support for some additional rule):

SimpleSchema.addValidator(myFunction);

To add a custom validation function that is called for ALL keys for ONE schema:

import SimpleSchema from "meteor/aldeed:simple-schema";

const schema = new SimpleSchema({ ... });
schema.addValidator(myFunction);

To add a custom validation function that is called for ONE key in ONE schema:

import SimpleSchema from "meteor/aldeed:simple-schema";

const schema = new SimpleSchema({
  someKey: {
    type: String,
    custom: myFunction,
  },
});

All custom validation functions work the same way. First, do the necessary custom validation, use this to get whatever information you need. Then, if valid, return undefined. If invalid, return an error type string. The error type string can be one of the built-in strings or any string you want.

  • If you return a built-in string, it's best to use the SimpleSchema.ErrorTypes constants.
  • If you return a custom string, you'll usually want to define a message for it.

Within your custom validation function, this provides the following properties:

  • key: The name of the schema key (e.g., "addresses.0.street")
  • genericKey: The generic name of the schema key (e.g., "addresses.$.street")
  • definition: The schema definition object.
  • isSet: Does the object being validated have this key set?
  • value: The value to validate.
  • operator: The Mongo operator for which we're doing validation. Might be null.
  • validationContext: The current ValidationContext instance
  • field(): Use this method to get information about other fields. Pass a field name (non-generic schema key) as the only argument. The return object will have isSet, value, and operator properties for that field.
  • siblingField(): Use this method to get information about other fields that have the same parent object. Works the same way as field(). This is helpful when you use sub-schemas or when you're dealing with arrays of objects.
  • addValidationErrors(errors): Call this to add validation errors for any key. In general, you should use this to add errors for other keys. To add an error for the current key, return the error type string. If you do use this to add an error for the current key, return false from your custom validation function.

NOTE: If you need to do some custom validation on the server and then display errors back on the client, refer to the Asynchronous Custom Validation on the Client section.

Custom Whole-Document Validators

Add a validator for all schemas:

import SimpleSchema from "meteor/aldeed:simple-schema";

SimpleSchema.addDocValidator((obj) => {
  // Must return an array, potentially empty, of objects with `name` and `type` string properties and optional `value` property.
  return [{ name: "firstName", type: "TOO_SILLY", value: "Reepicheep" }];
});

Add a validator for one schema:

import SimpleSchema from "meteor/aldeed:simple-schema";

const schema = new SimpleSchema({ ... });
schema.addDocValidator(obj => {
  // Must return an array, potentially empty, of objects with `name` and `type` string properties and optional `value` property.
  return [
    { name: 'firstName', type: 'TOO_SILLY', value: 'Reepicheep' }
  ];
});

Whole-document validators have the following available on this context:

  • this.ignoreTypes: The value of the ignore option that was passed to validate.
  • this.isModifier: True if this is running on a MongoDB modifier object.
  • this.isUpsert: True if this is running on a MongoDB modifier object that is for an upsert.
  • this.keysToValidate: The value of the keys option that was passed to validate.
  • this.mongoObject: The MongoObject instance.
  • this.obj: The full object.
  • this.schema: The schema instance.
  • this.validationContext: The ValidationContext instance.

Manually Adding a Validation Error

If you want to reactively display an arbitrary validation error and it is not possible to use a custom validation function (perhaps you have to call a function onSubmit or wait for asynchronous results), you can add one or more errors to a validation context at any time by calling myContext.addValidationErrors(errors), where errors is an array of error objects with the following format:

{name: key, type: errorType, value: anyValue}
  • name: The schema key as specified in the schema.
  • type: The type of error. Any string you want, or one of the strings in the SimpleSchema.ErrorTypes list.
  • value: Optional. The value that was not valid. Will be used to replace the [value] placeholder in error messages.

If you use a custom string for type, be sure to define a message for it. (See Customizing Validation Messages).

Example:

SimpleSchema.setDefaultMessages({
  messages: {
    en: {
      wrongPassword: "Wrong password",
    },
  },
});

myValidationContext.addValidationErrors([
  { name: "password", type: "wrongPassword" },
]);

Asynchronous Custom Validation on the Client

NOTE: To use the unique option in this example, you need to be in a Meteor app with the aldeed:schema-index package added.

Validation runs synchronously for many reasons, and likely always will. This makes it difficult to wait for asynchronous results as part of custom validation. Here's one example of how you might validate that a username is unique on the client, without publishing all usernames to every client:

username: {
  type: String,
  regEx: /^[a-z0-9A-Z_]{3,15}$/,
  unique: true,
  custom() {
    if (Meteor.isClient && this.isSet) {
      Meteor.call("accountsIsUsernameAvailable", this.value, (error, result) => {
        if (!result) {
          this.validationContext.addValidationErrors([{
            name: "username",
            type: "notUnique"
          }]);
        }
      });
    }
  }
}

Note that we're calling our "accountsIsUsernameAvailable" server method and waiting for an asynchronous result, which is a boolean that indicates whether that username is available. If it's taken, we manually invalidate the username key with a "notUnique" error.

This doesn't change the fact that validation is synchronous. If you use this with an autoform and there are no validation errors, the form would still be submitted. However, the user creation would fail and a second or two later, the form would display the "notUnique" error, so the end result is very similar to actual asynchronous validation.

You can use a technique similar to this to work around asynchronicity issues in both client and server code.

Getting a List of Invalid Keys and Validation Error Messages

This is a reactive method if you have enabled Tracker reactivity.

Call myValidationContext.validationErrors() to get the full array of validation errors. Each object in the array has at least two keys:

  • name: The schema key as specified in the schema.
  • type: The type of error. See SimpleSchema.ErrorTypes.

There may also be a value property, which is the value that was invalid.

There may be a message property, but usually the error message is constructed from message templates. You should call ctxt.keyErrorMessage(key) to get a reactive message string rather than using error.message directly.

Customizing Validation Messages

Error messages are managed by the message-box package.

In most cases you probably want to set default messages to be used by all SimpleSchema instances. Example:

SimpleSchema.setDefaultMessages({
  messages: {
    en: {
      too_long: "Too long!",
    },
  },
});

The object syntax is the same as shown here for MessageBox.defaults. When you call setDefaultMessages, it simply extends the default defaults. Be sure to call it before you create any of your SimpleSchema instances

The MessageBox instance for a specific schema instance is simpleSchemaInstance.messageBox. You can call messages function on this to update the messages for that schema only. Example:

simpleSchemaInstance.messageBox.messages({
  en: {
    too_long: "Too long!",
  },
});

Other Validation Context Methods

myContext.keyIsInvalid(key) returns true if the specified key is currently invalid, or false if it is valid. This is a reactive method.

myContext.keyErrorMessage(key) returns the error message for the specified key if it is invalid. If it is valid, this method returns an empty string. This is a reactive method.

Call myContext.reset() if you need to reset the validation context, clearing out any invalid field messages and making it valid.

myContext.name is set to the context name, if it is a named context. Create named contexts by calling schema.namedContext(name) or new ValidationContext(schema, name).

Other SimpleSchema Methods

Call MySchema.schema([key]) to get the schema definition object. If you specify a key, then only the schema definition for that key is returned.

Note that this may not match exactly what you passed into the SimpleSchema constructor. The schema definition object is normalized internally, and this method returns the normalized copy.

Cleaning Objects

You can call simpleSchemaInstance.clean() or simpleSchemaValidationContextInstance.clean() to clean the object you're validating. Do this prior to validating it to avoid any avoidable validation errors.

The clean function takes the object to be cleaned as its first argument and the following optional options as its second argument:

  • mutate: The object is copied before being cleaned. If you don't mind mutating the object you are cleaning, you can pass mutate: true to get better performance.
  • isModifier: Is the first argument a modifier object? False by default.
  • filter: true by default. If true, removes any keys not explicitly or implicitly allowed by the schema, which prevents errors being thrown for those keys during validation.
  • autoConvert: true by default. If true, helps eliminate unnecessary validation messages by automatically converting values where possible.
    • Non-string values are converted to a String if the schema expects a String
    • Strings that are numbers are converted to Numbers if the schema expects a Number
    • Strings that are "true" or "false" are converted to Boolean if the schema expects a Boolean
    • Numbers are converted to Boolean if the schema expects a Boolean, with 0 being false and all other numbers being true
    • Non-array values are converted to a one-item array if the schema expects an Array
  • removeEmptyStrings: Remove keys in normal object or $set where the value is an empty string? True by default.
  • trimStrings: Remove all leading and trailing spaces from string values? True by default.
  • getAutoValues: Run autoValue functions and inject automatic and defaultValue values? True by default.
  • extendAutoValueContext: This object will be added to the this context of autoValue functions. extendAutoValueContext can be used to give your autoValue functions additional valuable information, such as userId. (Note that operations done using the Collection2 package automatically add userId to the autoValue context already.)

You can also set defaults for any of these options in your SimpleSchema constructor options:

const schema = new SimpleSchema(
  {
    name: String,
  },
  {
    clean: {
      trimStrings: false,
    },
  }
);

NOTE: The Collection2 package always calls clean before every insert, update, or upsert.

Dates

For consistency, if you care only about the date (year, month, date) portion and not the time, then use a Date object set to the desired date at midnight UTC (note, the clean function won't strip out time). This goes for min and max dates, too. If you care only about the date portion and you want to specify a minimum date, min should be set to midnight UTC on the minimum date (inclusive).

Following these rules ensures maximum interoperability with HTML5 date inputs and usually just makes sense.

Best Practice Code Examples

Make a field conditionally required

If you have a field that should be required only in certain circumstances, first make the field optional, and then use a custom function similar to this:

{
  field: {
    type: String,
    optional: true,
    custom: function () {
      let shouldBeRequired = this.field('saleType').value === 1;

      if (shouldBeRequired) {
        // inserts
        if (!this.operator) {
          if (!this.isSet || this.value === null || this.value === "") return SimpleSchema.ErrorTypes.REQUIRED;
        }

        // updates
        else if (this.isSet) {
          if (this.operator === "$set" && this.value === null || this.value === "") return SimpleSchema.ErrorTypes.REQUIRED;
          if (this.operator === "$unset") return SimpleSchema.ErrorTypes.REQUIRED;
          if (this.operator === "$rename") return SimpleSchema.ErrorTypes.REQUIRED;
        }
      }
    }
  }
}

Where customCondition is whatever should trigger it being required.

Validate one key against another

Here's an example of declaring one value valid or invalid based on another value using a custom validation function.

SimpleSchema.messageBox.messages({
  en: {
    passwordMismatch: "Passwords do not match",
  },
});

MySchema = new SimpleSchema({
  password: {
    type: String,
    label: "Enter a password",
    min: 8,
  },
  confirmPassword: {
    type: String,
    label: "Enter the password again",
    min: 8,
    custom() {
      if (this.value !== this.field("password").value) {
        return "passwordMismatch";
      }
    },
  },
});

Translation of Regular Expression Messages

The built-in English messages for regular expressions use a function, so to provide similar messages in another language, you can also use a function with a switch statement:

messages: {
  fr: {
    regEx({ label, regExp }) {
                switch (regExp) {
                    case (SimpleSchema.RegEx.Email.toString()):
                    case (SimpleSchema.RegEx.EmailWithTLD.toString()):
                        return "Cette adresse e-mail est incorrecte";
                    case (SimpleSchema.RegEx.Domain.toString()):
                    case (SimpleSchema.RegEx.WeakDomain.toString()):
                        return "Ce champ doit รชtre un domaine valide";
                    case (SimpleSchema.RegEx.IP.toString()):
                        return "Cette adresse IP est invalide";
                    case (SimpleSchema.RegEx.IPv4.toString()):
                        return "Cette adresse IPv4 est invalide";
                    case (SimpleSchema.RegEx.IPv6.toString()):
                        return "Cette adresse IPv6 est invalide";
                    case (SimpleSchema.RegEx.Url.toString()):
                        return "Cette URL est invalide";
                    case (SimpleSchema.RegEx.Id.toString()):
                        return "Cet identifiant alphanumรฉrique est invalide";
                    case (SimpleSchema.RegEx.ZipCode.toString()):
                        return "Ce code postal est invalide";
                    case (SimpleSchema.RegEx.Phone.toString()):
                        return "Ce numรฉro de tรฉlรฉphone est invalide";
                    default:
                        return "Ce champ n'a pas passรฉ la validation Regex";
                }
            },
    }
  }
}

Debug Mode

Set SimpleSchema.debug = true in your app before creating any named validation contexts to cause all named validation contexts to automatically log all invalid key errors to the browser console. This can be helpful while developing an app to figure out why certain actions are failing validation.

Extending the Schema Options

You may find at some point that there is something extra you would really like to define within a schema for your package or app. However, if you add unrecognized options to your schema definition, you will get an error. To inform SimpleSchema about your custom option and avoid the error, you need to call SimpleSchema.extendOptions. By way of example, here is how the Collection2 package adds the additional schema options it provides:

SimpleSchema.extendOptions(["index", "unique", "denyInsert", "denyUpdate"]);

Obviously you need to ensure that extendOptions is called before any SimpleSchema instances are created with those options.

Add On Packages

mxab:simple-schema-jsdoc Generate jsdoc from your schemas.

(Submit a PR to list your package here)

Contributors

This project exists thanks to all the people who contribute.

License

MIT

Contributing

Anyone is welcome to contribute. Before submitting a pull request, make sure that you've read our contribution guide.

Thanks

(Add your name if it's missing.)

  • @mquandalle
  • @Nemo64
  • @DavidSichau

meteor-simple-schema's People

Contributors

aj07mm avatar aldeed avatar chmac avatar dandv avatar dburles avatar gabrielpoca avatar hiphapis avatar jankapunkt avatar jhgaylor avatar leite08 avatar mjgallag avatar mquandalle avatar nieziemski avatar okland avatar olragon avatar pociej avatar rlora avatar samnicholsonuk avatar sbking avatar simonsimcity avatar sleiber avatar subhog avatar wursttheke avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

meteor-simple-schema's Issues

Async callback for "valueIsAllowed"

I think that "valueIsAllowed" should provide async features on the client side. It may be helpfull to check values (using meteor methods), that can be verified on the server side only (for security and app's architecture reasons).

States for validation results

It would be nice if there were more than two validation states (error or no error). I like using four message classes: error, success, warning, and info. For example, I might use warning to tell someone their password isn't very strong while still letting them use it. I also use an info class to visually let the user know that a field is required when they haven't entered anything into it yet.

Allowing custom properties

What do you think of allowing custom properties to let other packages have the possibility to enhance the Simple Schema with additional information? As an example:

var schema = new SimpleSchema({
    'image' : {
        'type' : String,
        'otherPackage' : {
            'animated' : true
        }
    }
});

I'd also be okay with only one property called "custom" or something where one can define such informations.

Custom validation message for array elements

I'm trying to write a custom validation message for keys in an array of sub-schema elements. The message keys are matched literally, while my key includes the array index of the element: groups.0.name. Here is the (simplified) relevant schema code:

var group = new SimpleSchema({
  name: {
    type: String
  }
});

var schema = new SimpleSchema({
  groups: {
    type: [group]
  }
});

I have two potential solutions in mind:

Solution 1. It would be great if I could either add a message to the messages object of the group object from the above example, which will be automatically picked up when validating against the parent schema schema. This solution could also be taken into account, when working on issue #46. Like this:

group.messages({
  'required name': 'my_error_message'
});

Solution 2. Add a message to the messages object of the schema object with a wildcard for matching the array index. Example:

schema.messages({
  'required groups.$.name': 'my_error_message'
});

Collection Question

Hello,

I think I am missing something. Where do you create your collection and how do you tie it to the schema? (without using collection2)

Thanks

default value

I miss an option defaultValue which would be inserted by the clean method. I know that collection2 delivers a autoValue but things aren't always inserted into the database and even then it takes some of the same logic every time I want to implement a default value.

Callbacks for Strings

I'm thinking that a callback for string fields like messages or labels would help implement multiple languages. Think of that:

label: __.bind(__, "some.language.key")
// the language function of the i18n package bound with the key so its called when needed

This would allow Meteor.render to dynamically change the label when the language changes. To make it compatible the label function might have to be wrapped in an object with a toString method.

Collapsing Update Objects

There are a number of areas where the variety of possible modifier formats makes things confusing for validation, or for extra checks that are done in collection2. A good solution might be to collapse update objects in a manner similar to what is currently done with insert objects. In other words, rearrange keys in the modifier object so that the first level of keys matches the format of the schema keys. Then have all the modifier objects below that. Certain modifier objects might make this difficult, so we'll have to see if it's possible.

An example:

{
  $set: {
    'name.first': Foo,
    'name.last': Bar,
    age: 45
  },
  $inc: { updates: 1 },
  $push: { scores: 89 }
}

Is run through the collapse function and becomes:

{
  'name.first': { $set: Foo },
  'name.last': { $set: Bar },
  age: { $set: 45 },
  updates: { $inc: 1 },
  scores: { $push: 89 }
}

This makes validation much easier because we now only have to loop through the first level and look from schema rules, and then check for any operators under that and perform appropriate validations. This will make it much easier to implement validation checks for the remaining operators that are not currently supported. Also, the rearranged object can be passed to custom validation functions, autoValue functions, etc. to make it much easier for those to validate, set values, etc.

getNativeStringProperties crashes on Firefox 26

Hi,

I don't know yet, if this is triggered by a misconfiguration in my Schemas, but getNativeStringProperties (strings.js:582) crashes in my browser , as the try - catch - Block is probably not working as intended.

//...
      var func = __nsp[name];
      try {
        var type = typeof func.apply('teststring', []);
        retObj[name] = type;
      } catch (e) {}
//...

Apparently func can be undefined in this situation. As a safeguard i added an if - clause around it, which works for me. But I'm not really sure, if this is the correct approach, as I don't understand the module and the implications of this change (yet).

//...
      var func = __nsp[name];
      if (func) {
        try {
          var type = typeof func.apply('teststring', []);
          retObj[name] = type;
        } catch (e) {}
     }
//...

Cutom validation problem

Hi,

I think I have found a problem with the example at "Validating One Key Against Another". Using that example just throws:

Error: Invalid definition for confirmPassword field.
     at packages/simple-schema/simple-schema.js:81
     at Function._.each._.forEach (packages/underscore/underscore.js:87)
     at SimpleSchema (packages/simple-schema/simple-schema.js:78)
     at app/both/collections/modules/accounts.js:1:49
     at app/both/collections/modules/accounts.js:71:3
     at /home/j/www/sandbox.arandu.meteor/src/.meteor/local/build/programs/server/boot.js:155:10
     at Array.forEach (native)
     at Function._.each._.forEach (/home/j/.meteor/tools/09b63f1ed5/lib/node_modules/underscore/underscore.js:79:11)
     at /home/j/www/sandbox.arandu.meteor/src/.meteor/local/build/programs/server/boot.js:82:5

I'm using the following schema:

AccountsSS = new SimpleSchema({
  "username": {
    type: String,
    label: 'Username'
  },
  password: {
    type: String,
    label: "Enter a password",
    min: 8
  },
  confirmPassword: {
    type: String,
    label: "Enter the password again",
    min: 8,
    custom: function () {
      if (this.value !== this.field('password').value) {
        return "passwordMismatch";
      }
    }
  }
});

validating objects fails when setting as object

My app is breaking with a recent update to simple-schema and collection2. I have tracked it down to the following case:

var ss = new SimpleSchema({
  'foo.bar': { type: Number }
});

var ctx = ss.newContext();

ctx.validate({$set: { 'foo.bar': 29 }}, { modifier: true });  // works
console.log(ctx.invalidKeys());
// prints: []

ctx.validate({$set: { foo: {bar : 30 }}}, { modifier: true });  // doesn't work, but should?
console.log(ctx.invalidKeys());
// prints: [ { name: 'foo.$.bar',
//             type: 'keyNotInSchema',
//             message: 'foo.$.bar is not allowed by the schema' } ]

My app is using collection2, and doing Collection.update({_id: whatever}, {$set: {foo: someobj}}) which worked before, but now fails as in the example above. foo.bar is not an array, so the error is incorrect.

Problem with array validation

Hi there,

first of all, I would like to express a big Thank You to you for investing the time to create and maintain the simple-schema, collection2 and autoform packages. They are very helpful to me!

Today, however, I experienced an odd issue with array validation. My collection definition and insertion look like the following:

StudiesSmartCollection = new Meteor.SmartCollection 'studies'
@Studies = new Meteor.Collection2 StudiesSmartCollection,
    schema:
        'name':
            label: "study name"
            type: String
        'researchers':
            label: "researchers"
            type: [Object]
            minCount: 1
        'researchers.$._id':
            label: "researcher's ID"
            type: String
        'researchers.$.role':
            label: "researcher's role"
            type: String
            allowedValues: allowedStudyRoleValues

newStudyId = Studies.insert
    name: 'Give-me-a-name study'
    researchers: [
        {
            '_id': Meteor.user()._id
            'role': "creator"
        }
    ]

I am getting the following error trace in the client console:

insert failed: Error: failed validation
    at _.extend._insertOrUpdate (http://localhost:3000/packages/collection2.js?dd6c26f37df1d4741e85f32967cc7f36d5ce8ca2:186:21)
    at _.extend.insert (http://localhost:3000/packages/collection2.js?dd6c26f37df1d4741e85f32967cc7f36d5ce8ca2:196:21)
    at Object.Template.studies.events.click .bd-create-study (http://localhost:3000/studies/main.coffee.js?6f62ebfa8370124f8bc9e97ad5f895778c5e72ba:87:28)
    at Object.<anonymous> (http://localhost:3000/packages/templating.js?05b762a6c16769651cfe346f68018b47eacac716:196:32)
    at Spark.attachEvents._renderer.annotate.range.handler (http://localhost:3000/packages/spark.js?c9939ae1b11c764e0ce2709f852e72f6382467e6:878:38)
    at http://localhost:3000/packages/spark.js?c9939ae1b11c764e0ce2709f852e72f6382467e6:775:11
    at Array.forEach (native)
    at Function._.each._.forEach (http://localhost:3000/packages/underscore.js?a1286cdb983623d4d035c8d7cd7a1e8e15274cf5:130:11)
    at http://localhost:3000/packages/spark.js?c9939ae1b11c764e0ce2709f852e72f6382467e6:774:9
    at http://localhost:3000/packages/universal-events.js?5bfa39513d2caa4af4f829d7f4907afae3601adf:143:26 

Printing the invalid keys to the console (using Studies.simpleSchema().invalidKeys()), yields the following output:

invalid key 1: Object {name: "researchers.$._id", type: "required", message: "researcher's ID is required"}
invalid key 2: Object {name: "researchers.$.role", type: "required", message: "researcher's role is required"}

Adding an attribute optional: true to the fields researchers.$._id and researchers.$.role seems to suppress the error from being thrown and the fields are correctly inserted into the database. However, I would like to make them required fields. Am I missing an important detail here or is that a bug that needs to be fixed?

Cheers,
Mike

Clean is removing actual fields whose names are subsets of virtual fields.

position.slice(0, p.length) === p
https://github.com/aldeed/meteor-simple-schema/blob/master/mongo-object.js#L135

Collection2 insert doValidate calls simple-schema's clean which calls mongo-object's removeValueForPosition intending to remove virtual fields, but due to the line above, which I don't understand the purpose of, it also removes actual fields whose names are subsets of virtual fields.

For example, I have a virtual field called distancePath & an actual field called distance, they both get removed and the insert fails. I'm not sure which version introduced this bug, but it was working until I upgraded today so it is definitely a regression:

autoform v0.4.10 - v0.4.13
collection2 v0.3.3 - v0.3.7
simple-schema v0.2.30 - v0.2.34

Faulty ruleset when reusing objects with Array types

With the creation of a SimpleSchema the used object may be altered causing any creation of SimpleSchema's using the same object to contain a faulty ruleset.

for example:

var example = {
    something: {
        label: 'something',
        type: [String]
    }
}

var schema = new SimpleSchema(example);

now when logging the original example object you'll get this:

{
    "something": {
        "label": "something"
    },
    "something.$": {
        "label": "something",
        "optional":true
    }
} 

I'm guessing this is used by SimpleSchema to handle Arrays as type.

The issue I encountered was when I later reusing this example object (and adding some new fields) that the something.$ was still present.

With this new ruleset the SimpleSchema will no longer accept an Array of strings.

// reusing the example variable
var otherSchema = new SimpleSchema(example);

var valid = otherSchema.newContext().validate({ 
    something: ['hello', 'world'] 
});

valid will be false and the following errors will be present:

[
    { 
        name: 'something.0',
        type: 'keyNotInSchema',
        message: 'something.0 is not allowed by the schema' 
    },
    { 
        name: 'something.1',
        type: 'keyNotInSchema',
        message: 'something.1 is not allowed by the schema' 
    }
]

Now I don't know if this is something known or something that should be fixed. It's something I came across and you should probably be vigilant for.

Validation Messages are defined at the Schema level but apply to all Schemas

With the following validation message definitions "regEx Results.name message" is used for both regEx Races.name & regEx Results.name because it was defined second replacing "regEx Races.name message".

Races.simpleSchema().messages({
  'regEx name': "regEx Races.name message"
});
Results.simpleSchema().messages({
  'regEx name': "regEx Results.name message"
});

First part of this issue is more bug, messages should be defined on global SimpleSchema object if they effect all schemas:

SimpleSchema.messages({
  'regEx name': "regEx name message"
});

Second part of this issue is more enhancement. It'd be great to be to able to use the same key name on two different schemas and retain the ability to have different error messages by specifying the schema name:

SimpleSchema.messages({
  \\ effects regEx error message for all keys equal to 'name' regardless of schema
  'regEx name': "regEx name message",
  \\ effects regEx error message only for key equal to 'name' on 'Results' schema
  'regEx Results.name': "regEx Results.name message"
});

Embrace the Meteor Match API

Currently type can be a JavaScript object like String, an object constructor like Date or any of those wrapped in brackets like [String].

This is a strict subset of what the Meteor Match API propose.

It would be nice to accept every Match pattern.

conditional optional

Is there any way to have a 'conditional optional'? I'm trying to make a situation work where a key would only be required when another key is set.

new SimpleSchema({
  firstname: {
    type: String,
    label: "First name",
    optional: true
  },
  lastname: {
    type: String,
    label: "Last name",
    optional: true
  }
})

Considering this schema. How would I go ahead and make lastname required or optional: false when and only when firstname is set?

Context sensitive valueIsAllowed

There should be a way to validate fields that rely on other fields. For example, a verify password or verify email field needs to be matched against another value. Maybe there could be a valueIsAllowed function that was passed the entire object instead of just the value?

Referencing documents

Hello, this is more a question than an issue:
what "type" should be set when we want to reference another doc within a Schema?

I've tried:

schema: {
  userId: {
    type: Meteor.Collection.ObjectID
  }
}

But got a failed validation.

Thanks!

Empty string as acceptable value on non-optional field?

What is the correct way to allow an empty string ('') to validate? I haven't marked this field as optional, but I set min to 0. I'd expect it to reject my insert if I passed null, undefined, or omitted the field entirely, but it seems to also reject an empty string. Is this by design? For certain applications, might it make sense to allow empty string as an acceptable value? I'm willing to try to work around this, but wanted to be sure it's a design decision that I can learn, and not a bug. Thanks!

Storing objects that cannot be defined

Hi, we are creating an application that needs to save user generated data. The user uploads a csv file and we create a document for each of the rows of the csv file. We later use the data in the csv in lists, edit screens and to pass to other parts of the application.

The problem we are having is that every csv file can have a different column definition. This makes it almost impossible to validate the rest of the docment we are inserting, as simple-schema does not allow black box objects (the csv data needs to be a key-value object).

Example pseudocode:

CSV = new Meteor.Collection2('csv', {
    schema: {
        uploadId: {
            type: String,
            label: "data is part of this upload"
        },
        data: {
            type: Object,
            label: "Answers in csv"
        }
    }
});

csv_data = {
    uploadId: "1234567890",
    data: {
                COL1: 1,
                COL2: "some string",
                COL3: 3.324,
                COL4: 4
    }
};

Would there be no way of telling simple-schema to just accept the object and ignore what else is in there? It is not an option for us to JSON.stringify the data as suggested earlier as we use this data all over our application, and very often want to access the data from a column directly (data.COL1 for instance) in Mongo queries (in C++ applications). The csv data can be a very large object.

getArrayInfoForKey(line 150) and affectsGenericKey(line 334) with arrays in mongo-object.js

Assuming that you have an array field in your Collection2 schema like this one:

 member_ids: {
            type: Array(String),
            label: "liste of member Ids",
            autoValue: function () {
                console.log("this",this)
                console.log("this.field('member_ids')",this.field("member_ids"))
               }
}

When I do a $pull:{member_ids:"xyz"} (or an $addToSet),I assumed that
this.operator is $pull,
this.value is xyz
this.isSet() is true.

But this.operator and this.value are undefined and this.isSet() is false

this.isSet() is false because affectsGenericKey is looking for member_ids in _genericAffectedKeys but there is only member__ids.$. (line 342)

this.operator and this.value are undefined because getArrayInfoForKey() never returns a value due to getValueForPosition(line 86) which never returns a value too.

In collection2.js (line 462 getAutoValues)

...
var keyInfo = mDoc.getArrayInfoForKey(fieldName) || mDoc.getInfoForKey(fieldName) || {};
....
isSet: mDoc.affectsGenericKey(fieldName),
....
value: keyInfo.value,
 operator: keyInfo.operator,
field: function(fName) {
        var keyInfo = mDoc.getArrayInfoForKey(fName) || mDoc.getInfoForKey(fName) || {};
        return {
          isSet: (keyInfo.value !== void 0),
          value: keyInfo.value,
          operator: keyInfo.operator
        };
      }
    }, doc);

Performance Improvement for Clean and Validate Workflow

Right now collection2 and probably most other use cases do this:

//clean up doc
doc = schema.filter(doc);
doc = schema.autoTypeConvert(doc);
//validate doc
schema.validate(doc);

For a client-side insert or update, this happens twice in the collection2 pkg. Each of those functions is doing some kind of looping over either the doc object or the schema object. With some significant rewriting, it should be possible to change the API to the following and gain some efficiency:

doc = schema.validate(doc, {
  filter: true,
  typeConvert: true
});

For sure, the filter() and autoTypeConvert() functions can be combined and called from validate() based on options passed in. And since validate() currently does not return anything, it can then return the modified doc.

Some further combination with the validation loop may be possible, but I think there will need to be two loops no matter what because it needs to check both that no required fields are missing and also that no extra fields are present.

Possible problems with validation of embedded objects?

It seems that (server side?) updates fail when an it is done on a collection that has "Object" fields.

If you do something like:

@col = new Meteor.Collection2 "col",
    schema:
        "name":
            type: String
        "embed":
            type: Object
        "embed._id":
            type: String

The following will fail:

col.update {_id: ...},{$set:{name:"Updated name"}}

More specifically, you'll get an "invalid key" for "embed._id", even though it is simply not touched by the update. I guess this can be circumvented by using the _collection field directly, but that doesn't sound like what should happen here. (Sorry for using Coffeescript syntax.)

Since this specifically interacts with "partial validation" scenario's where not all fields need to be validated, it's hard to think of a way to trigger this directly in simple-schema.

min: and max: constraint don't detect 0

hi,

I tried to set a positive constraint for a Number value:

MySchema = new SimpleSchema({
    area: {
         type:Number,
         min:0
    }
}

but validation does not detect e.g.

obj={area:-1};
ssContext.validate(obj);

as in simple-schema-contexts.js check is:

} else if (max && max < keyValue) {
      invalidKeys.push(errorObject("maxNumber", keyName, keyValue, def, ss));
    } else if (min && min > keyValue) {
      invalidKeys.push(errorObject("minNumber", keyName, keyValue, def, ss));

thus ignoring 0 limited min and max range.

I fixed this with

} else if (max !== undefined && max < keyValue) {
      invalidKeys.push(errorObject("maxNumber", schemaKeyName, keyValue, def, ss));
    } else if (min !== undefined && min > keyValue) {
      invalidKeys.push(errorObject("minNumber", schemaKeyName, keyValue, def, ss));

Should something else be changed in addition?

Jyrki

Label improvements

Labels should be dynamic through an API similar to messages in case they need to change for multiple-language/I18N support. They are a bit different from messages because they necessarily correspond to a schema key and are not related to error type, whereas messages can be custom per key but need not be and are necessarily related to error type.

The plan: define in schema, as now, but allow them to be changed at any time with a labels method.

Also add label inflection from property names. This would help with the simple English-only cases where you're just capitalizing the first letter or whatnot. Inflection can be done when the schema object is initially parsed in the constructor function. If label is not defined, define it automatically using inflection. Other areas of the code can then be streamlined to assume label will always be set rather than falling back to the property name.

Probably use _.humanize from underscore.string.

Allow function for min/max

For cases where runtime calculations are necessary for min/max, it would be nice if min and max could be a function that returns the min/max value. This would be most useful for dates, where you might want a minimum of "today at 8 AM" for example.

Entering a Date

What is the correct way to set a minimum date? Also how should we insert a date to to a collection?

sharing primary document attributes (schema parts)

The README shows an example where a "AdressSchema" sub-schema gets embedded into multiple document attributes.
However, because DDP syncing operates on the level of document attributes:

Is there also a proper way to use/share a schema for defining first level document attributes accross multiple collections (not embedded subfields), so that Meteor can sync/transfer the documents attributes individually?

Embedded Documents

How would I go about embedding documents in a collection? Like embedding comments into a post?

invalidkeys() not set when separately constructed schema is included in collection definition of collection2

The following is a schema design that incorporates a common base schema. (autovalues etc may not make sense, I just used them to see if features are interchangeable between collection2 and simple-schema)

/********************************
Base Collection Schema
********************************/
CoolProject.Collections.BaseSchema = new SimpleSchema({
  active: {
    type: Boolean
  },
  createdAt: {
    type: Date,
    min: new Date(),
    autoValue: function() {
      if (this.isInsert) {
        return new Date;
      } else if (this.isUpsert) {
        return {$setOnInsert: new Date};
      } else {
        this.unset();
      }
    },
    denyUpdate: true
  },
  updatedAt: {
    type: Date,
    min: new Date(),
    autoValue: function() {
      if (this.isUpdate) {
        return new Date();
      }
    },
    denyInsert: true,
    optional: true
  }
});

/********************************
Tag Collection Schema
********************************/
CoolProject.Collections.TagsSchema = new SimpleSchema([
  CoolProject.Collections.BaseSchema,
  {
    title: {
      type: String,
      label: 'Title',
      min: 5,
      max: 10
    },
    slug: {
      type: String,
      label: 'Slug',
      autoValue: function() {
        var title = this.field("title");
        if (title.isSet) {
          return URLify2(title.value);
        } else {
          this.unset();
        }
      }
    }
  }
]);

/********************************
The Actual Collection
********************************/
CoolProject.Collections.Tags = new Meteor.Collection('tags', {
  schema: CoolProject.Collections.TagsSchema,
  virtualFields: {
    virtualTest: function(tag) {
      return tag.title + ' // ' + tag.slug;
    }
  }});

Then on the browser console, I test the code by inserting some values using:

/********************************
Browser Console
********************************/
CoolProject.Collections.Tags.insert(
  {/*  WRITE SOME DOC HERE */},
  function(err,res) {
    if (err) return CoolProject.Collections.Tags.simpleSchema().namedContext().invalidKeys();   
  }
);

If the document is valid, it passes successfully through and I receive back the inserted document id. The autovalue, and nesting seems to be working. ( Except that the virtual field does not work, but it is already reported on another issue #47 )

THE PROBLEM:

If the doc is invalid (e.g. missing active or too short a title) then all I receive on the console output returns undefined whereas an array of error objects should have returned. This is reproducible on both 0.2.17 and 0.3.0

Regex validation causes Max validation to be ignored on String

If there is a Regex check on a key, the Max attribute does not seem to be validated against -- e.g. in the following, isValid() still allows a string with more than 15 characters to pass validation:
username: {
type: String,
min: 3,
max: 15,
regEx: /^[a-z0-9_]+$/
}

This might happen for other types as well, but I haven't looked into this.

Validate Custom Objects

When the type option is a custom object type (or array of them), and that custom type exposes a simpleSchema() method, we should validate custom objects during validation, and merge any errors into the main invalidKeys array.

In addition to being generically useful, this will specifically help with collection2 development to support relationships between collections.

TypeError: Cannot read property 'type' of undefined

Getting a new error in 0.2.31

  /lib/node_modules/fibers/future.js:173
            throw(ex);
                 ^
  TypeError: Cannot read property 'type' of undefined
    at packages/simple-schema/simple-schema.js:575
    at Function._.each._.forEach (packages/underscore/underscore.js:82)
    at expandSchema (packages/simple-schema/simple-schema.js:573)
    at packages/simple-schema/simple-schema.js:549
     at Array.forEach (native)
     at Function._.each._.forEach (packages/underscore/underscore.js:79)
     at mergeSchemas (packages/simple-schema/simple-schema.js:542)
     at SimpleSchema (packages/simple-schema/simple-schema.js:39)
     at Meteor.Collection (packages/collection2/collection2.js:45)
     at __coffeescriptShare (packages/reaction-shop/common/collections.coffee:381:15) 

I see it's from a little recent funkiness of mine:

@Orders = new Meteor.Collection "Orders",
  schema = new SimpleSchema([Cart,
    additionalField:
      type: String
      optional: true
    status:
      type: String
  ])

Guess, you might want to catch this error.

Validating elements of array

Right now The following wouldn't work:

  tags: {
    type: [String],
    label: "Tags",
    min: 0,
    max: 12
  },
  "tags.$": {
    min: 2,
    max: 64
  }

It would give you error saying 'tags.$ is required'.

Support Additional Update Operators

This is to track progress adding support for additional update operators beyond $set and $unset.

The following operators need to be parsed and understood (but not necessarily validated) by the validation and cleanup functions in simple-schema:

  • $setOnInsert (treat this just like $set, merge contents with contents of $set)
  • $rename
  • $inc
  • $addToSet
  • $push
  • $pushAll (deprecated but might still work?)
  • $pull
  • $pullAll
  • $pop
  • $each (used with $push or $addToSet; probably remove the $each and treat like setting directly)
  • $slice

The following operators need to be validated as best they can by simple-schema:

  • $setOnInsert (treat this just like an insert)
  • $rename (make sure old name is not required and new name is in schema)
  • $addToSet (check allowed values and validate each item)
  • $push (check allowed values and validate each item)
  • $pushAll (deprecated but might still work?) (throw error)
  • $each (used with $push or $addToSet; probably remove the $each and treat like setting directly)

And all except $setOnInsert will probably need some extended validation added in the collection2 package.

Validation of subdocuments

Hi, I have an issue which I think is a bug but it may also be my misunderstanding.

Here's my case. With schema as this:

Pet = new SimpleSchema({
    name: {
        type: String
    }
});

Person = new SimpleSchema({
    name: {
        type: String
    }
});

Family = new SimpleSchema({
    pets: {
        type: [Pet]
    },
    kids: {
        type: [Person]
    },
    parents: {
        type: [Person]
    },
    id: {
        type: String
    }
});

Validation seems to work for non-array properties just as one could imagine:

sc = Family.newContext();
sc.validate({$set:{id:"12"}}, {modifier:true});
sc.isValid(); // returns true

sc.validate({$addToSet:{pets:{name:"Felix"}}}, {modifier:true});
sc.isValid(); //false
sc.invalidKeys(); 

Now, the last statement returns

"[{"name":"kids.$.name","type":"required","message":"Name is required"},{"name":"parents.$.name","type":"required","message":"Name is required"}]"

which I interpret as it expects the object to be full schema compatible, even though I think it should validate only against "Pet" schema.

I encountered this with Collections2, where it's very hard to add an element into a subdocument array when schema is complex. Basically only using $set to replace the full array seems to work.

Or do I get it wrong?

Thanks,
Jyrki

Validate API is confusing

If find this API confusing:

MySchema.validate(obj); // return undefined
MySchema.valid(); // reactive bool

How can I validate more than one reactive object? (imagine a html table where each line is a element from a collection, and at the end of the line a indicator that show if the line is correct, same model for all the lines, different objects)

Any thoughts on it?

[Enhancement Request]: Ability to define virtual fields within Simple Schema

A powerful feature of Collection2 is the ability to define schema structure outside the collection definition.

Coupled with the ability to combine multiple schema structures within Simple Schema, we have a good mechanism for keeping the code dry, abstract and clean.

Virtual fields are a great addition to Collection2. But consider a use case where we have a base schema (e.g. createdAt, createdBy, updatedAt, updatedBy) which we include in all our collections through their respective schemas.

And consider for each document in any collection, I would like to have a virtual field that gives me the email address for the user who has created the document.

In its current form, we need to include such virtual field in every collection or hack it using _.extend etc.

It would be a great feature if one could define virtual field at the schema level as well.

Not typeconverting values of nested objects

Using simple-schema v0.2.10

Simple-schema does not seem to be typeconverting some string values of a nested object into numbers/decimal numbers when I call clean. I was looking through the code of simple-schema.js and it's something in here:

//clean
  newDoc = {};
  _.each(cDoc, function(val, key) {
    var okToAdd = true;

    //filter
    if (options.filter === true) {
      okToAdd = self.allowsKey(key);
    }

    if (okToAdd) {
      //autoconvert
      if (options.autoConvert === true) {
        var def = self._schema[key];
        if (def) {
          var type = def.type;
          if (_.isArray(type)) {
            type = type[0];
          }
          if (looksLikeModifier(val)) {
            //convert modifier values
            _.each(val, function(opVal, op) {
              if (_.isArray(opVal)) {
                for (var i = 0, ln = opVal.length; i < ln; i++) {
                  opVal[i] = typeconvert(opVal[i], type); //typeconvert
                }
              } else if (_.isObject(opVal) && ("$each" in opVal)) {
                for (var i = 0, ln = opVal.$each.length; i < ln; i++) {
                  opVal.$each[i] = typeconvert(opVal.$each[i], type); //typeconvert
                }
              } else {
                opVal = typeconvert(opVal, type); //typeconvert
              }
              val[op] = opVal;
            });
          } else if (_.isArray(val)) {
            for (var i = 0, ln = val.length; i < ln; i++) {
              val[i] = typeconvert(val[i], type); //typeconvert
            }
          } else {
            val = typeconvert(val, type); //typeconvert
          }
        }
      }

      newDoc[key] = val;
    }
  });

If I understand correctly, looksLikeModifier(val) needs to be true in order to get to this line: } else if (_.isObject(opVal) && ("$each" in opVal)) { which I think is what would typeconvert the nested values? I don't really understand what the "$each" is except that opVal is the first argument to the iterator of the _.each call and represents the current element. http://underscorejs.org/#each

Some of the values i'm trying to convert include negative integers and negative decimals.

Let me know what you think and if i'm totally misunderstanding what's going on and doing something wrong.

Default Values

Is there a way to set default values? Not sure if the schema is the place to set defaults but I'm thinking it would be nice in some cases.

SchemaRegEx.Email is not entirely valid

SchemaRegEx.Email is not correnct.

However this needs to be discussed. Technically the address root+something@localhost is a valid email and will be accepted by the browsers input type email. Maybe multiple pre made expressions are needed to fill what the developer needs.

I eg. like to allow the '+' as it allows the user (if he knows about that) to figure out where the mail came from.

Then again I dislike allowing domains that don't have a '.' as in the normal case we are not in an intranet and such mails aren't what we want. However for the intranet case this should be there too.

Multiple RegEx Per Key

It was mentioned in #5 that regEx should support multiple regular expressions for a single schema key. This seems like a good idea. Might be best to name them rather than using an array, and then those names can be used for custom messages:

MySchema = new SimpleSchema({
  password: {
    type: String,
    regEx: {
      numbers: twoNumbersRegEx
    }
  }
});

MySchema.messages({
    'regEx.numbers': "[label] must have two numbers"
});

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.