Defining annotations
This page explains how to use define queries to define annotations for types and type traits.
Overview
Annotations define constraints and specialized behavior for types and their traits, enabling more precise control over how data must behave in your database.
Example schema
As an example, consider the following schema
define
entity content owns id;
entity page sub content,
owns page-id,
owns name;
entity profile sub page,
owns username;
entity user sub profile,
owns email,
owns phone,
owns language,
owns karma;
attribute id value string;
attribute page-id sub id;
attribute username sub page-id;
attribute name value string;
attribute email value string;
attribute phone value string;
attribute language value string;
attribute karma value double;
In the schema above we may have the following:
-
We may have general
content
data objects side by side with more specializedpage
s,profile
s, anduser
s. -
id
s can be duplicated, i.e. need not be unique per content. -
There can be any number of
name
s for apage
and, thus, auser
. -
phone
andemail
values do not adhere to specific formats. -
…
None of these behaviors may be desirable. TypeDB addresses the issue through a unified annotation mechanism. Annotation, prefixed with @
, can be added to schema definition statements like the ones above. The following list summarizes some of the most common annotations:
-
@key
ensures attributes act as keys to data. E.g.content owns id @key;
-
@regex
enforces string values to adhere to specific regular expressions. E.g.,user owns phone @regex("^\d{8,15}$");
-
@unique
enforce attributes uniquely identify their owner. E.g.,user owns phone @unique;
-
@card
restricts cardinality, i.e., the number of data instances allowed in a specific context. E.g.,profile owns username @card(1..1);
-
@abstract
disallows inserting data instances into types. E.g.,content @abstract;
-
@independent
allows storing attributes without owners. E.g.attribute language @independent;
See the TypeQL Annotation reference for a full list of available annotations.
Annotation semantics
Default behaviors
Schema definitions may have default behavior if no annotation is specified.
-
Role player references of relation types default to
@card(0..1)
behavior (a relation may link 0 or 1 role player). -
Role player traits of other types default to
@card(0..)
behavior (an object may play a specific role in 0 or more relations). -
Attribute ownership traits of default to
@card(0..1)
behavior (an object may own a specific attribute 0 or 1 times).
See @card annotation for more details.
Redefining constraints
A single declaration cannot have multiple different annotations of the same kind. For example:
-
<statement> @card(X) @card(X) @card(X)
will always result intype @card(X)
. -
<statement> @card(X) @card(Y)
is an invalid definition.
A defined annotations whose value should be changed can be redefined.
Constraints and annotations can also be combined as a result of subtyping and specialization. |
Subtyping
Subtyping is a powerful instrument in TypeDB and becomes even more powerful with annotations. As a general rule, subtypes inherit the behavior of their supertypes, but they may further specialize this behavior (e.g., through additional annotations).
See the annotation reference for further details.
Intricacies
Default behaviors are implicitly set for defined traits whenever there is no explicitly defined constraint
E.g., the following schema requires @card(0..)
specification for page owns name
, because the default cardinality would not allow page
s and, thus, profile
s to have 2 or 3 name
s.
At the same time, user
s will only have two cardinality constraints for their names: 0..
and 0..3
as the ownership is inherited.
However, if you were to set a user owns name
again, a default cardinality constraint would be generated for this ownership, and user
would need to comply to three cardinality constraints for name
s.
define
entity page sub content, owns name @card(0..);
entity profile sub page, owns name @card(0..3);
entity user sub profile;