Skip to content

TypeQL section for docathon #949

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 7 commits into
base: 3.x-development
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,97 @@
= Constraining Data

[placeholder]
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.

== 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 annotation `@card(x..[y])`, where `x` is the minimum number permitted, and `y` is the maximum number. `y` may be omitted to not enforce an upper limit.

E.g. We can restrict a `friendship` relation to relate exactly two `friends`.
[,typeql]
----
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.
[,typeql]
----
person plays employment:employee @card(0..1);
person owns email @card(0..);
----

=== Cardinality constraints on specialisation
Cardinality constraints declared on an interface applies to all instances of that interface (including specialisations).
e.g.
[,typeql]
----
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.
[,typeql]
----
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 implementations
Similarly, cardinality constraints on `plays` & `owns` can be specialised. e.g.:
[,typeql]
----
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 cardinality 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.


== Other constraints
* `@abstract` prevents the type from being instantiated
// Other?

== Reference
* xref:{page-version}@typeql::annotations/index.adoc[Annotations]
Original file line number Diff line number Diff line change
@@ -1,4 +1,137 @@
= Entities, Relations, Attributes
// TODO: Out links to manual / fundamentals articles

[placeholder]
TypeQL data model concepts.
TypeDB implements the Polymorphic Entity-Relation-Attribute (PERA) data model.
A TypeDB schema defines a hierarchy of these types, and how they interact with each other through interface-types.

=== Entity

Entities are standalone types, which exist independent of other types.

E.g. A `person` exists, regardless of whether they are involved in friendships or have a name.
[,typeql]
----
entity person;
----

=== Relation
Relations are types which define one-or-more associated "role" types.
The relation "depends" on other types in the schema to "play" these roles.

E.g. An `employment` relation exists to relate an `employer` to an `employee`.
An `employment` instance cannot exist without the other instances which play these roles,
hence the idea that `employment` "depends" on the participating player types.
[,typeql]
----
relation employment, relates employer, relates employee;
----

=== Attribute
Attributes are types which hold a value. An attribute type must specify the primitive `value-type` of the values it will hold
An instance of an attribute type is identified by its value.

E.g. Any instance which has an age of 10 will refer to the same instance of the `age` attribute type.

[,typeql]
----
attribute age, value integer;`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stray `

----

== Owning attributes & playing roles

Entity & relation types may be defined to "own" attribute types.

E.g. A `person` may own an attribute `birth-date`, or an `employment` may own a `start-date`;
[,typeql]
----
person owns age;
----
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth noting what this does - <This is the only way to associate concrete data with entities or relations, so you'll be doing this frequently>


Entity & relation types may be defined to "play" a role defined by a relation.

E.g. The entity type `company` may play the `employer` role of an `employment` relation.

[,typeql]
----
company plays employment:employer;
----

== Polymorphism

Polymorphism in TypeDB comes is realised in two ways:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete comes


=== Interfaces
Multiple types may "implement" the same interface. In the following schema snippet, the `employer` role in the `employment` relation can be played by a `company` or an `charity`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's worth pulling up the idea that a role is a kind of interface you define by creating the role, and can impement with plays, and that attributes define an implicit interface you impement with owns.

Then go on to say that:

< multiple types may implement the same interface (i.e. use own the same attribute, or play the same role >

Again this is a new/different idea so I think worth repeating multiple times in slightly different ways.


[,typeql]
----
define
relation employment,
relates employer,
relates employee;

entity company sub organisation,
plays employment:employer;
entity charity sub organisation,
plays employment:employer;
----

Here, the role `employer` is the interface declared by the `employment` type. The `company` and `charity` types implement the interface.
The `relates` keyword is used to define the new role-type interface.
The `plays` keyword is used to implement a role-type interface.

[NOTE]
====
Attribute types always declare an implicit interface. A type can be defined to implement this interface using the `owns` keyword.
====

=== Subtyping
TypeDB follows a single-inheritance *subtyping* system which allows types to specialize an existing type.
The subtype "inherits" all owns or plays implementations from its supertype.
Thus, an instance of the subtype may be used at any interface or function argument that accepts an instance of its super-type.

In the following schema snippet, entities of type `company` or `charity` can play the `employer` in an `employment`,
although it is their supertype `organisation` which is defined to play the role.

[,typeql]
----
define
relation employment,
relates employer,
relates employee;

entity organisation sub profile,
plays employment:employer;
entity company sub organisation;
entity charity sub organisation;
----

==== Inheriting & specialising interfaces
A subtype also inherits any interfaces defined by its supertype.
It may optionally "specialise" an inherited interface by defining a subtype of that interface.

In the following schema snippet, `content-engagement` inherits the `content` role from `interaction` as-is, and "specialises" the inherited `subject` role into the `author` role.

[,typeql]
----
define
relation interaction @abstract,
relates subject,
relates content;
relation content-engagement @abstract, sub interaction,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's put the sub on the next line as a style IMO

relates author as subject;
----

[NOTE]
====
An attribute type inherits and implicitly specialises the interface of its supertype.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure it's worth saying as the user never sees this IMO?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's why it's in a note rather than in the main text.
I think it's easier to understand the behaviour of attribute ownerships if they understand how plays works and know the mapping to attributes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough, i think it's a usefu parallel

====

// TODO:
// ==== Specialising interface implementations
// When a type implements a specialisation of an interface, the inherited implementation (if any) is hidden.
//
// E.g.
// [,typeql]
// ----
// ----