Defining types
This page explains how to define types and type traits in TypeDB schemas.
Schema definition queries
All schema (un)definitions in TypeDB are run in schema
transactions. There are three kinds of schema definition queries:
-
define <statements>
. Adefine
query defines types and their traits, subtyping, as well as more specific annotations on those statements. -
undefine <statements>
. Anundefine
query can be used to remove definitions of type, their traits, subtyping, and statement annotations. -
redefine <statement>
. Aredefine
query can be used to change a single statement at a time, overwriting any analogous previously defined statement.
Entity types
Entity types are first defined using the entity
keyword.
define entity user;
Subtypes of entity types are always entity types themselves, and can be introduced using the sub
keyword.
define entity admin sub user;
Traits of entity types are defined as before using the plays
and owns
keywords.
Relation types
Relation types are first defined using the relation
keyword.
define
relation friendship,
relates friend @card(2);
Here, @card(2)
is an example of annotation, specifying that there will be exactly two friends in each friendship relation. Without this annotation the role cardinality would default to @card(0..1)
(allowing between 0 and 1 friend). See annotations for more.
Subtypes of relation types are always relation types themselves, and can be introduced using the sub
keyword.
-
Relation subtypes can specialize the roles of their supertype using the
as
keyword. -
Otherwise, if a role is not specialized, relations subtypes automatically inherit that role.
For example
define
relation close-friendship sub friendship; # inherits friend role
relation best-friendship sub friendship, # specializes friend role
relates best-friend as friend @card(1),
relates other-friend as friend @card(1);
This defines “close friendship” and “best-friendship” relations as a subtype of our friendship relations above.
Note that unlike friendship relations, the subtype of best-friendships contains asymmetric relations (indeed, unfortunately, if A is the best friend of B this need not imply that B is the best friend of A). In general, a single role can be specialized into any number of roles, as long as role cardinalities are compatible.
Note |
In the above example, the cardinality annotations |
Traits of relation types are defined as before using the plays
and owns
keywords.
Attribute types
Attribute types are first defined using the attribute
keyword, and they must be supplied with a value type using the value
keyword (unless, they are annotated as being @abstract
, see annotations)
define
attribute id,
value string;
Subtypes of attributes types are always attributes types themselves, and inherit the value type of its supertype (if set; otherwise, a new value type can be set). For example:
define
attribute comment-id sub id;
Note |
Recall that attributes do not play roles or own other attributes. |
Type traits
To implement a “role player trait” (which enables type instances to be used as players in a given role type) use the keyword plays
. To implement an “ownership trait” (which enables type instances to be used as owners for a given attribute type) use the keyword owns
. For example,
define
user plays friendship:friend,
owns id;
defines that user
instances may act as friends in friendship relations, and ownd ids. Since admin
s are users, these traits get inherited! However, admin
may have additional more specialized traits:
define
attribute access-level, value integer;
admin plays best-friendship:best-friend,
plays best-friendship:other-friend,
owns access-level;
Undefining definitions
Any of the above statements can be undefined. For example
undefine admin;
will completely remove the admin from your schema, and with it all traits of the admin type.
Note |
Removing a type from your schema will, in general, only succeed if there are no data instance in the type and no other definitions depend on the type (i.e., the type appears neither in another type’s trait nor as another type’s supertype). |
If we instead write
undefine sub user from admin;
then this removes admin
having user
as its supertype, but it does not remove the type admin
itself.
Similarly, writing
undefine plays friendship:friend from user;
removes the friend trait from the user type, but leaves the type itself intact. And
undefine owns id from user;
removes the trait of owning usernames.
Redefining definitions
TypeDB also allows concise redefinitions of single statements. For example, after we define
define
entity user;
entity admin sub user;
entity superuser sub user;
we may redefine:
redefine admin sub superuser;
This will turn the initial tree-like
type hierarchy into a linear type hierarchy, where admin < superuser < user
.
Re-define semantics are the most complex of all three definition queries. However, the simple key property of redefine is: after a successful redefinition, the re-defined statement holds fully, replacing any conflicting prior statement.
Note |
While both |