Constraining Data
TypeDB allows additional constraints to be defined on the types in the schema.
These constraints can restrict the cardinality of an interface, or the domain of values of an attribute type.
These constraints are written as annotations on the schema declarations they apply to. Annotations are prefixed with the @
symbol.
Cardinality constraints
Cardinality constraints restrict the number of interfaces of a specific type that may be attached to an instance.
These are specified using the @card
annotation. It can be written using either:
-
a range
@card(x..[y])
, wherex
is the minimum number permitted, andy
is the maximum number (y
may be omitted to not enforce an upper limit); -
a scalar value
@card(x)
, wherex
is the required exact number of interfaces for each instance.
E.g., we can restrict a friendship
relation to relate exactly two friends
.
friendship relates friend @card(2);
We can also restrict the number of roles of a specific type an instance plays, or the number of attributes of a specific type it owns.
E.g., a person can be involved in at most one employment, but own any number of emails.
person plays employment:employee @card(0..1);
person owns email @card(0..);
On specialisation of roles
Cardinality constraints declared on a connection apply to all instances of that connection (including specialisations). For example:
relation sports-team,
relates player @card(11);
relation football-team sub sports-team,
relates goal-keeper as player @card(1),
relates defender as player,
relates midfielder as player,
relates forward as player;
Here, a sports-team
is constrained to have exactly 11 players.
football-team
is a subtype of sports-team, and the various positions are specialisations of the player
role.
Since all positions of are specialisations of player
, it is enforced that a football team has 11 players across
whatever may be the distribution across the positions.
Additionally, the @card(1)
ensures a team has exactly one goal-keeper
.
When an interface has multiple constraints (declared and/or inherited), all of them must be satisfied.
For example, let’s restrict our football-team
to the more common distribution across positions.
relation football-team sub sports-team,
relates goal-keeper as player @card(1),
relates defender as player @card(3..5),
relates midfielder as player @card(3..5),
relates forward as player @card(1..3);
The cardinality restrictions on the individual positions do not rule out a "(1-)4-5-3" formation,
but the @card(11)
constraint on the player
does.
On specialisation of plays and owns
Similarly, inherited cardinality constraints on plays
& owns
can be specialized. For instance:
entity page owns name @card(1..3);
entity profile sub page;
entity user sub profile,
owns first-name @card(1),
owns surname @card(0..);
attribute name @abstract, value string;
attribute first-name sub name;
attribute surname sub name;
Here, a page must have between 1 & 3 names. A person must have exactly one first-name and up to two surnames.
@unique
and @key
These are special constraints which can be applied to ownerships.
owner owns attribute @unique
constrains a given attribute
instance to be owned by at most one owner
instance.
owner owns attribute @key
requires every owner
instance to own exactly one instance of the attribute
type.
Additionally, the @unique
constraint applies, requiring an attribute
instance to be owned by at most one owner
instance.
Attribute value constraints
Attribute types may be annotated with constraints to restrict the values that an instance may hold. This allows an extra level of validation to be built into the schema.
-
@values(<value1>, …)
: requires values to be one of those specified; -
@range(<min>..<max>)
: requires values of numeric or time value types to lie within a range; -
@regex(<regex>)
: requires values of string types to match the regex.
Value constraints are inherited by subtypes. A subtype may add its own value constraints to the inherited ones. An instance of the subtype must satisfy all such declared & inherited value constraints.
Value constraints can also be placed on owns
declarations to restrict values within the context of one ownership.