Constraint Rules

A rule is a reference to a validation unit (test method, context, constraint, constraint array) in the VSD, optionally prefixed by a target property.

They can be used

  • in a constraint test, poll, results, or if parameters.
  • in an include condition if parameter.

Reference Marks

Generally straints can figure out which validation unit a rule refers to. However, it is possible that the name of a test method could clash with the name of a context or constraint reference. In these cases, you can use an atmark (@) prefix for a context reference or a hashmark (#) prefix for a validator method to force straints to evaluate accordingly.

For example,

constrain:
  name: [ exists, string ]

is the same as

constrain:
  name: [ '#exists', '#string' ]

and (assuming 'address' is an object on the validation target and 'validAddress' is a context defined elsewhere)

constrain:
  address: [ validAddress ]

is the same as

constrain:
  address: [ '@validAddress' ]

Setting the Target Property

Prefix a rule reference with a property name using a colon (:) to have it evaluate that property in the current object.

constrain:
  nameOne: [ exists, alphanumeric ]
  nameTwo: [ nameOne:#not.numeric ]

Here, 'nameTwo' is only valid if 'nameOne' is not numeric.

Rule as Constrain Key

A rule can also be used as a constrain key to be applied to properties when prefixed with a tilde (~).

constrain:
  ~exists: [ nameOne ]
  ~alphanumeric: [ nameOne ]
  ~nameOne:#not.numeric: [ nameTwo ]

Inline Test Method Parameters

A test method rule reference may also use have simple parameters applied inline.

Recall that there are two ways to pass test method parameters in a constraint.

  • param (!)
    Passes an array of values as a single parameter to the test method.

  • params (?)
    Passes an array of values as individual parameters to the test method.

Inline parameters are passed directly to a test method reference by appending a ! or ? followed by a colon-delimited list.

constrain:
  rgbComponent: [ itemIn!red:green:blue ]
  colorValue: [ between?0:255 ]

When using inline parameters, remember that

  • each one is parsed as a literal with a fallback to string
  • they cannot contain whitespace as this will cause rule reference parsing to fail
  • they will override parameters applied to a constraint via param or params

Constraint Rule Expressions

A rule expression is two or more rules compared by logic gates, or even a single rule prefixed by a 'not' switch.

constrain:
  confirm: [ missing or true ]
  details: [ not exists or (confirm:true and @detail) ]

This example says that 'confirm' is either missing or true. Property 'details' must either not exist or, if 'confirm' is true, must validate against the context specification 'detail'.

Rule expressions are simply evaluated from left to right so use parentheses for grouping as necessary.

For x in A x B you can use the following logic gates:

  • and - Both A and B must be true.
  • or - At least one of A or B must be true.
  • nor - Both A and B must be false.
  • nand - At least one of A or B must be false.
  • xnor - A and B must be the same boolean value.
  • xor - A and B must not be the same boolean value.

You may also use not in a rule expression to negate the test after it.

Rules Become Constraints

Behind the scenes, straints ultimately works with constraint objects as it applies validations to object properties. Therefore, standalone rules and rule expressions found in the VSD need to be converted into constraint objects.

Straints uses a 'path' attribute on the constraint to identify it. The value of 'path' is how you would reference the constraint from a results object.

instance.validate( ... ).then(results =>
{
    var constraint = results.constraints[CONSTRAINT_NAME];
    ...
});

Test Methods

When a test method (without inline parameters) is specified as a constraint

my_context:
  constrain:
    name: [ method ]

the resulting constraint becomes

{ test: '#method', path: '#method' }

When a test method (with inline parameters) is specified as a constraint

my_context:
  constrain:
    name: [ method!7:apple ]

the resulting constraint becomes

{ test: 'method!7:apple', path: 'my_context.constrain.name.0' }

Contexts

When a context is specified as a constraint

my_context:
  constrain:
    address: [ context ]

the resulting constraint becomes

{ test: '@context', path: '@context' }

Property Prefixed

When a property prefixed rule is specified

my_context:
  constrain:
    address: [ property:method ]

the resulting constraint becomes

{ test: 'property:method', path: 'property:method' }

Rule Expressions

When a rule expression is specified as a constraint

my_context:
  constrain:
    address: [ not @context or property:#method ]

the resulting constraint becomes

{ test: 'not @context or property:#method', path: 'my_context.constrain.address.0' }

Some Caveats

You should avoid doing the following:

  1. Don't reference an array of constraints in a rule expression
    This is not supported yet, but may be in the future.

  2. Don't reference a constraint with an if condition in a rule expression
    If the if fails, the constraint will return null and destroy the expression.

  3. Don't use property names that contain anything other than ASCII-based javascript identifier characters
    This limitation may be resolved in the future.