Osy#the first language built for agents
Agents firstAgentic appsWorkflowsDurable Execution — built inSecurityTestingThe editorThe UI modelOne program

Reference / Entity

invariant

invariant <condition>; invariant <condition> when <guard> message "<text>";

A row-level rule spanning several members, checked when the row is written. Use it when a constraint on one member is not enough — a balance that may not go negative, or a rule that only applies to some rows.

stable2 examples compiled by CIentitymodelvalidation

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

Related

constraints

The per-member rules the database enforces — Required, Unique, MaxLength/MinLength, Min/Max, Pattern, and the…

entity

Declares a persisted type — a table of rows the app stores, queries and secures. Every entity gets an Id and audit…

entity members

The typed members an entity holds — text, numbers, dates, booleans, Guids, enums and references. A member's type…