- Index
- »
- doc.xeto
- »
- Constraints
Constraints
Overview
Xeto includes a built-in set of constraint rules that are used for data validation.
Number Constraints
Number specs can be annotated with the following meta to constrain their value space:
minVal: inclusive minimum valuemaxVal: inclusive maximum valueunit: requires the number to have a specific unitquantity: requires the number to have a unit of a specific quantity
Examples:
Foo: {
percent: Number <minVal: 0, maxVal: 100, unit:"%">
powerVal: Number <quantity:"power">
}
// Slot 'percent': Number 50°C must have unit of '%'
@a: Foo { percent:50°C, powerVal:70kW }
// Slot 'percent': Number 200% > maxVal 100
@b: Foo { percent:200%, powerVal:70kW }
// Slot 'power': Number must be 'power' unit; '°C' has quantity of 'temperature'
@c: Foo { percent:50%, powerVal:70°C }
Str Constraints
Str specs can be annotated with the following meta to constrain their value space:
minVal: inclusive minimum lengthmaxVal: inclusive maximum lengthnonEmpty: marker tag to require string to have non-whitespace characterspattern: regex for required string pattern (example further below)
Foo: {
name: Str <nonEmpty>
phone: Str <minVal: 7, maxVal:10>
}
// Slot 'name': String must be non-empty
@a: Foo { name:"", phone:"5551234" }
// Slot 'phoneNum': String size 3 < minSize 7
@b: Foo { name:"Bob", phone:"555" }
// Slot 'phoneNum': String size 11 > maxSize 10
@c: Foo { name:"Bob", phone:"21255512345" }
List Constraints
List specs can be annotated with the following meta to constrain their value space:
minSize: inclusive minimum lengthmaxSize: inclusive maximum lengthnonEmpty: marker tag to require at least one item
Foo: {
listA: List <nonEmpty>
listB: List <minSize:2, maxSize:3>
}
// Slot 'listA': List must be non-empty
@a: Foo { listA:{}, listB:{"a", "b"}}
// Slot 'listB': List size 1 < minSize 2
@b: Foo { listA:{"x"}, listB:{"a"}}
// Slot 'listB': List size 4 > maxSize 3
@c: Foo { listA:{"x"}, listB:{"a", "b", "c", "d"}}
Scalar Constraints
All scalars must support a string encoding. The string encoding can
be constrained at compile time using the pattern tag with a regular
expression:
SocialSecurityNumber: Scalar <pattern:"\\d{3}-\\d{2}-\\d{4}">
// ok
@a: {ssn: SocialSecurityNumber "123-43-5678"}
// String encoding does not match pattern for 'acme::SocialSecurityNumber'
@b: {ssn: SocialSecurityNumber "123435678"}
Invariant Values
A spec can define a fixed value for a slot via the invariant marker.
This requires all instances to have that exact value as defined by
the slot spec:
Foo: {
// requires all instances to use the invariant value "%"
unit: Unit <invariant> "%"
}
// Slot 'unit': Must have invariant value '%'
@a: Foo {unit:"meter"}
Query Constraints
Query slots may declare constraints used to validate an instance's reference graph. The canonical example is the required points of an equip:
StandardVav: Equip {
points: {
temp: ZoneAirTempSensor
co2: ZoneCo2Sensor?
}
}
Query constraints validated by computing the queries extent. In the example above the points contained by the equip. Then each constraint must match exactly one entity in the extent:
- zero matches is an error unless the constraint is a maybe type
- multiple matches is always an error, even for a maybe type, because the match is ambiguous
Constraints may be declared as named types or as inline as anonymous tags:
DTemp: {discharge, temp}
DFlow: {discharge, flow}
Ahu1: Equip {
points: {
// named shape types; auto-named constraints report by type qname
DTemp
DFlow
// inline anonymous marker sets
Point {run, cmd}
}
}
An extent entity matches a constraint using the same rules as sugar matching: the constraint's nominal type plus its constraint tags.
An entity whose spec tag names a constraint slot itself (such as
acme::Vav.points.zoneTemp), or a subtype's override of it, is
anchored to that constraint and matches it alone. Constraints with
no anchored entity fall back to matching the unanchored entities by
type and tags. So a template may declare constraints which differ
only by name, such as vendor configuration points, and instances
created from it still match exactly one each.
Queries make specs suitable as named validation profiles: a shareable, versioned spec describing the required shape of an installation - for example the required points of an ASHRAE Guideline 36 VAVs.