Summary#
An invariant is a rule about the whole row, enforced when the row is written. A
constraint speaks about one member ([Max(5)] int Priority); an invariant speaks about the
relationship between members — and can be conditional, so it applies only to the rows it should.
Signature#
entity <Name> {
invariant <condition>; // always holds
invariant <condition> when <guard>; // holds only for rows where <guard> is true
invariant <condition> when <guard> message "<explanation>"; // …and say why, when it fails
}Description#
How do I write a rule over the whole row?#
The condition is written over the row's own members, and must be true when the row is written:
entity Account {
[Required] string Holder;
decimal Balance;
invariant Balance >= 0;
}Any code path that would leave Balance negative — a withdrawal, an import, an adjustment — fails at commit. You do
not have to remember to check it, and neither does the next person.
A rule that applies to some rows#
when guards the invariant. The rule is only checked for rows where the guard is true, so one entity can hold
several kinds of row without the rules of one contaminating the others:
entity Product {
[Required] string Name;
bool IsPerishable;
int ShelfDays;
invariant ShelfDays <= 30 when IsPerishable
message "Perishable items can have at most 30 shelf days.";
}A tin of beans with ShelfDays = 400 is fine — the guard is false, so the rule never fires. Milk with the same value
is rejected, and the person who tried gets the sentence you wrote rather than a constraint name.
How do I say why it failed? — message#
message is the explanation a human sees. Without it they get a rule that says ShelfDays <= 30, which tells them
what was violated but not what to do. Write the message as though you are talking to the person who hit it — because
you are.
What an invariant can see#
The row it is on. An invariant reads the members of its own entity; it does not run a query and it does not reach across into other rows. That is what keeps it cheap enough to check on every write.
See also#
- constraints — the single-member rules (
[Required],[Unique],[Min]/[Max],[Pattern]) - entity members — the members an invariant reads
- entity — the entity an invariant guards