Once: constraint
Inside the block of a property,constraint takes a message, an optional code, and a predicate that receives the value
and returns true when it is valid:
Int here, so the predicate needs no casts and no null checks. In the message,
{path} and {value} are filled in.
Everywhere: an extension on ValidationNode
A constraint you use in several classes is a function. Every built-in constraint is an extension ofValidationNode<V> that calls constraint, and yours can be too:
SkuConstraints.kt
String:
Product.kt
Follow the conventions of the built-in constraints and yours will read the same:
- The code is the name of the function, so a program can tell
skufromminLength. - The message is a parameter with a default, so one call can change it.
- The message completes a sentence about the value, in lower case:
must be a SKU such as ABC-1234. nullarguments skip the rule, asmin(null)does, so a rule fed by optional data never fails on its own.
A message built from the value
Every built-in constraint that takes an argument has a second form whose message is a function. It receives the value asthis and the argument as its parameter, so the message can say what is wrong with this value:
constraint has the same form: constraint(message = { "$it is not in stock" }) { it in stock }.
Rules that suspend
The predicate and the message aresuspend lambdas, so a constraint can call a repository or a client directly:
Rules about time
A rule about “now” should read the clock of the configuration, not the system clock, so tests can fix it.now { } gives you the current time from that clock: