Validation Constraints
Constraints can be defined in arrays anywhere in the VSD. They are put to use, however, within the constrain
directive or other validation levels within a context or within rules or rule expressions.
Constraint Objects
In the VSD, a constraint object may be defined with some combination of the following properties:
-
name
(string)
A name for the constraint object that makes it easier to reference from elsewhere in the VSD. -
test
(string)
A rule or rule expression that defines a validation test for a given property of the current validation target. -
poll
(string)
A rule or rule expression that defines a validation test for all properties of the current validation target. This is ignored iftest
is given. -
results
(string)
A rule or rule expression used withpoll
to evaluate its aggregated validation test results. -
if
(string)
A rule or rule expression that, whentrue
, allowstest
orpoll
to be executed. -
param
(array)
Additional parameter that is passed to test methods appearing in any rule or rule expression in the constraint. -
params
(array)
Additional parameters that are applied to test methods appearing in any rule or rule expression in the constraint. This is ignored ifparam
is given. -
property
(string)
Locks the target property used with anytest
,poll
, orif
rule expression. -
flip
(boolean)
Set totrue
to reverse the boolean value ultimately returned bytest
orresults
. payload
(any)
Arbitrary data to attach to the constraint that will be available in results object via.payload()
.
Remember that either test
or poll
is required for a constraint object.
Referencing a Constraint
Constraints are identified by the path to their definition in the VSD.
pizza:
constrain:
cheese:
- { test: itemIn, param: [ mozzarella, provolone, jack ] }
topping:
- in.available.toppings
in:
available:
- { name: toppings, test: itemIn, param: [ pepperoni, mushroom, olives ] }
This one-topping pizza validation schema has two referenceable constraints.
- pizza.constrain.cheese.0
- in.available.toppings
When a constraint has no 'name' specified then it's name is the index of its position in the array where it is defined.
Constraint arrays can also be referenced:
pizza:
constrain:
sauce: [ good.name ]
good:
name:
- [ exists, lowercase ]
- { test: not longer, param: 16 }
Here, the named pizza sauce must be a lowercase string of no more than 16 characters. Note here also that constraint arrays can be nested.
Test Method Parameters
Other target object properties can be used as parameters to test methods in a constraint.
constrain:
email:
- email
emailConfirmation:
- { test: equal, params: $_.email }
The above ensures that 'emailConfirmation' is equal to 'email'.
In param
and params
, you can reference a property of the target object by prefixing it with a dollar-sign ($
).
Additionally, you can specify:
-
_
- current target object
The current target being validated (same ass
unless nested) __
- parent target object
The parent of the object being validated. Use these with the dot-notation to check higher-level parents.
Aggregate Constraints
A neat feature of straints is the ability to validate against aggregate validation results.
The way this works is through the poll
constraint object parameter.
Consider the following VSD.
activity:
constrain:
participants: [ not.missing, array ]
nested:
participants:
constrain:
_:
- { name: enoughAdults, poll: age:is.atLeast21, results: passCount:atLeast2 }
nested:
____:
constrain:
name: [ exists, string ]
age: [ exists, number ]
is:
- { name: atLeast21, test: not.less, params: [ 21 ] }
- { name: atLeast2, test: not.less, params: [ 2 ] }
There is quite a bit going on here, so lets break it down.
-
The context 'activity' stipulates that an object must have an array of 'participants', each having a 'name' and 'age' that are a string and a number, respectively.
-
The 'enoughAdults'
poll
constraint stipulates that 'age' must be at least 21 (See rules page for more info on this syntax) for every object value of the current target.NOTE
Remember that the target value ofpoll
is always the current target object, and it aims to aggregate validation results across all property values of that object. The property to which apoll
constraint is attached is merely the one to be blamed for any error that may result. To emphasize this point (or cause further confusion), the special_
property being used here actually refers to the current target object, which works as if the object had a property that referred to itself. - The
results
rule in thepoll
constraint is evaluated against a separate aggregate results object (described below), and here we are checking that 'passCount', the number of values that passed thepoll
validation, is at least two.
So, in a nutshell, this validation scheme is ensuring that a given activity has some participants (with names and ages) and that at least two of them are "adults" 21 or older. We don't want to see any children getting hurt, of course.
The Aggregate Results Object
Here are the properties of a poll
constraint's aggregate object that is made available in results
.
-
valid (boolean)
This istrue
if all tests passed. Also, if aresults
test is not provided on apoll
constraint then this is the value that will be returned from the constraint. -
passed (array)
Names of properties that passed -
failed (array)
Names of properties that failed -
tested (array)
Names of properties that were tested -
passCount (number)
Number of properties that passed -
failCount (number)
Number of properties that failed - testCount (number)
Number of properties that were tested