Skip to content
Merged
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,6 +1,5 @@
= Entities, Relations, Attributes
:page-aliases: {page-version}@typeql::data_model.adoc
// TODO: Out links to manual / fundamentals articles

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.
Expand Down
1 change: 1 addition & 0 deletions core-concepts/modules/ROOT/pages/typeql/glossary.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

This page lists out terms reused across pages in this section,
and links to where they are introduced.
A more complete list can be found in the xref:{page-version}@reference::typeql/keywords.adoc[TypeQL reference].

* xref:{page-version}@core-concepts::typeql/constraining-data.adoc#definition-annotation[Annotation]: Language fragments mainly used to add additional constraint to types.
* xref:{page-version}@core-concepts::typeql/query-variables-patterns.adoc#definition-answer[Answer]: A mapping of variables to the concepts the pattern "matched" in the database.
Expand Down
1 change: 0 additions & 1 deletion core-concepts/modules/ROOT/pages/typeql/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ The relevant sections of the reference are linked at the end of each page.
[.clickable]
****
A gentle introduction to the PERA data model - Entities, relations, attributes
// TODO: Or: Introduces the TypeQL data model - entities, relations, and attributes -
and what it means to "own" attributes and "play" roles in relations.
****

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@ using the reduce return modifier.
[,typeql]
.Find the number of posts by a page
----
fun post_count($page: page) -> { integer }:
fun post_count($page: page) -> integer:
match
$posting isa posting, links (posted: $page);
return count($post);
----

[NOTE]
====
Since `reduce` can be used with `groupby`, the `reduce` modifier returns a stream.
`reduce` returns a single answer, since it aggregates all answers into one.
====

== Cyclic functions & tabling
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,8 @@ See xref:{page-version}@core-concepts::typeql/schema-data.adoc[].
Variable names are unique within a pipeline -
every usage of a variable with a certain name refers to the same variable.

In the following sections, the term [[definition-local-variable]]"local" is used to mean
In the following sections, the term [[definition-internal-variable]]"internal" is used to mean
a variable is bound in that pattern but not in its parent.
This contrasts with the usage in programming languages where it refers to the scope of a variable name.
As mentioned above, the scope of variable names in TypeQL is the xref:{page-version}@core-concepts::typeql/query-clauses.adoc[pipeline].

== Disjunctions, negations & optionals

Expand Down Expand Up @@ -159,7 +157,7 @@ An answer to any pattern in the disjunction is an answer to the disjunction.

A variable is "bound" in a disjunction if it is bound in every branch of the disjunction.
Variables which are present in & bound by only some of the branches of the disjunction
(and not present outside it) are considered "local" to that disjunction.
(and not present outside it) are considered "internal" to that disjunction.

----
match
Expand All @@ -174,7 +172,7 @@ $p isa person, has name $p-name;
};
----

Here, `$emp`, `$company`, `$edu`, `$institute` are local to their patterns.
Here, `$emp`, `$company`, `$edu`, `$institute` are internal to their patterns.
`$p` occurs outside the disjunction.
`$org-name` is present in every-branch and returned by the disjunction.

Expand Down Expand Up @@ -203,11 +201,11 @@ Any variable that is present both outside and inside the negation is considered
and *must* be bound before matching the negated pattern.
This requires that the variable is bound in the parent conjunction.

Variables that are present only inside the negation are considered local to the negation.
Variables that are present only inside the negation are considered internal to the negation.
A negation without any inputs is extremely unusual.
[NOTE]
====
Local variables are not bound by the negation,
internal variables are not bound by the negation,
since the negation is satisfied only if there are no answers to the negated pattern.
====

Expand All @@ -221,7 +219,7 @@ match
};
----

Here, `$p` is an input to the negation. `$e, $c` are local. The query returns:
Here, `$p` is an input to the negation. `$e, $c` are internal. The query returns:
----
-------------
$p-name | isa name "Jeff"
Expand Down Expand Up @@ -322,7 +320,7 @@ Finished. Total rows: 3

[NOTE]
====
Optional variables *are* bound by the optional block and not local to it.
Optional variables *are* bound by the optional block and not internal to it.
====

== Notes on variables
Expand Down Expand Up @@ -476,14 +474,14 @@ This will return any persons `$p1` & `$p2` when
either (1) `$p1` is employed by *any* and `$p2` attended *any* institute;
or (2) `$p2` is employed by *any* company and `$p1` attended *any* institute.

Notice `$company` is "local" to both the first and second disjunctions (The same is the case for `$institute`).
Notice `$company` is "internal" to both the first and second disjunctions (The same is the case for `$institute`).
TypeQL throws a "disjoint variable re-use" error for such cases.

==== Valid variable scopes:
From these, it can be seen that a variable is either:

1. Local to one branch of one disjunction.
2. Local to one negation.
1. Internal to one branch of one disjunction.
2. Internal to one negation.
3. Bound & present in the answer of the pipeline.

== The select statement
Expand Down
2 changes: 1 addition & 1 deletion core-concepts/modules/ROOT/pages/typeql/schema-data.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ insert
----

Inserting a new instance will fail if the type is abstract. In the case of attributes,
the value must also be of the value-type specified by the attribute, and satisfy all value constraints defined on the type.
the value must also be of the value type specified by the attribute, and satisfy all value constraints defined on the type.

[#_iid]
Remember that inserted entities and relations don't have a natural identifier in your domain unless you provide one. The caveat here is that TypeDB generates an instance ID (`iid`, which you'll see in output logs) for your inserted entities and relations. However, it is recommended that you create meaningful identifiers, especially keys, when needing to refer to specific entities or relations.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ The `@abstract` annotation does not accept any arguments.

// tag::description[]
When defined for a type, the `@abstract` annotation enforces the `abstract` constraint, making the type abstract.
An abstract type cannot be a direct type for an instance.
Thus, a concrete subtype is required for instances creation, and an abstract type can be used as a query target to retrieve information about its subtypes.
An abstract type cannot be instantiated, but can be used in a query (e.g., in an `isa` constraint to match instances of its subtypes).
// end::description[]

[,typeql]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ The `@card` annotation can be defined for any `<interface>` of: `owns`, `relates
It accepts either a range argument or a single scalar argument.
Arguments must be integers.

- Both bounds are inclusive.
- A partially unbounded range `N..` has an infinite upper bound.
- The minimal lower bound is `0` and must be explicitly specified (e.g., use `0..M` instead of `..M`).
- A single scalar argument `N` is shorthand for `N..N` and means "exactly N".
Expand Down
28 changes: 27 additions & 1 deletion reference/modules/ROOT/pages/typeql/expressions/index.adoc
Original file line number Diff line number Diff line change
@@ -1,8 +1,34 @@
= Expressions
:page-aliases: {page-version}@typeql::expressions.adoc

This reference covers the usage of expressions in TypeQL.
A TypeQL expression uses operators and functions to
compute a value from other values. It uses the following syntax:
[,typeql]
----
let <var> = <expression>;
----
Examples:
[,typeql]
----
let $x = 5;

let $y = $x * 3.1;

let $z = ceil($y + 1);
----

== Validation
The following rules apply to variables involved in expressions:

* The variables used on the right-hand side of an expression must be bound to either attributes or values.
* The attribute may be of various attribute types as long as they all have the same value type.
* A value variable must be assigned to exactly once.

During compilation, the types of every subexpression are resolved, and the expression tree is constructed.
If any function which is passed an argument which does not match the expected type,
or any operator which is not defined for the given combination of types, will fail compilation with an error.

== Explore expressions
[cols-3]
--
.xref:{page-version}@reference::typeql/expressions/literals.adoc[]
Expand Down
2 changes: 1 addition & 1 deletion reference/modules/ROOT/pages/typeql/functions/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

// tag::description[]
Functions provide powerful abstractions of query logic. They are a cornerstone of the functional xref:{page-version}@reference::typeql/data-model.adoc[query programming model], and generalize logic programs à la Datalog.
Functions calls can be nested, recursive, and negated. There syntax natively embeds into TypeQL’s declarative pattern language.
Functions calls can be nested, recursive, and negated. Their syntax natively embeds into TypeQL’s declarative pattern language.
// end::description[]

[[fun_types]]
Expand Down
4 changes: 2 additions & 2 deletions reference/modules/ROOT/pages/typeql/keywords.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ Constructs a xref:{page-version}@reference::typeql/statements/let-eq.adoc[], use
Constructs a xref:{page-version}@reference::typeql/statements/let-in.adoc[], used to assign a stream or list element to a variable.

`contains`::
Constructs a xref:{page-version}@reference::typeql/statements/contains.adoc[], used to specify that a stream or list contains a data instance, or that a string contains a specified substring.
Constructs a xref:{page-version}@reference::typeql/statements/comparisons.adoc#_string_comparison[], used to specify that a string contains a specified substring.

`like`::
Constructs a xref:{page-version}@reference::typeql/statements/like.adoc[], used to specify that a string matches a specified regex pattern.
Constructs a xref:{page-version}@reference::typeql/statements/comparisons.adoc#_string_comparison[], used to specify that a string matches a specified regex pattern.

=== Identity statements

Expand Down
92 changes: 19 additions & 73 deletions reference/modules/ROOT/pages/typeql/patterns/disjunctions.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Disjunctive patterns can be used in `match` stages. They allow queries to match
{ <pattern1> } or { <pattern2> } [ or { <pattern3> } ... ] ;
----

The individual blocks `{ <pattern-i> }` of a disjunction are called it *branches*.
The individual blocks `{ <pattern-i> }` of a disjunction are called its *branches*.

[NOTE]
====
Expand All @@ -25,110 +25,56 @@ Moreover, since disjunctions are themselves patterns, they can also be nested, e
----
{ <p1> }
or {
{ <p2> }
or { <p1> };
{ <p2> } or { <p3> };
};
----
====

== Behavior
A disjunction pattern is satisfied if one of its branches is satisfied.

Disjunctions may appear in `match` stages, where they behave as follows.

* *Optionality*. An output variable whose xref:{page-version}@reference::typeql/patterns/index.adoc[scope] is the branch of a disjunction becomes an xref:{page-version}@reference::typeql/data-model.adoc[optional] variable. This means the variable may be left empty `()` in the output of the match stage. For example:
+
--
=== Variable scopes
A variable that appears in every branch will appear in the answers to the disjunction,
and is considered to be in the scope of the parent pattern.
Results to the following query will contain answers for `$x` and `$id`:
[,typeql]
----
match
$x isa $user;
{ $x has email $e; } or { $x has phone $p; };
select $e, $p;
----
will return users that have either mobile phone or email attributes. The output rows of this match stage may be of the form
{ $x has email $id; } or { $x has phone $id; };
----
{ $e="[email protected]", $p=() }
{ $e=(), $p="+1234" }
{ $e=(), $p="+1235" }
{ $e="[email protected]", $p=() }
----
--

* *Satisfaction*. A disjunction pattern is satisfied if one of its branches is satisfied, while variables bound in the other branches are left empty. For example,
+
--
A variable that occurs in only one branch AND not outside the disjunction is considered local to the branch.
Results to the following query will only contain answers for `$x`:
[,typeql]
----
match
$x isa $user;
{ $x has email $e; } or { $x has phone $p; } or { $x has address $a; }
----
may output
----
{ $e="[email protected]", $p=(), $a=() }
{ $e=(), $p="+1234", $a=() }
{ $e=(), $p=(), $a="1 Big Street, New City, NC1234" }
----
but will never output
----
{ $e=(), $p="+1234", $a="1 Big Street, New City, NC1234" }
----
--

* *Deduplication*. Outputs do not get duplicated if they satisfy multiple branches of the disjunction at the same time (in other words, branches are not executed "one after the other"). For example, the query
+
--
[,typeql]
----
match
$x isa $user; $y isa $user;
{ following(follower: $x, followed: $y); }
or { following(follower: $y, followed:$x); };
----
will output each `{ $x=..., $y=... }` row exactly once, even if both `$x` follows `$y` and `$y` follows `$x`.
----
{ $x=0x1, $y=0x3 }
{ $x=0x7, $y=0x2 }
{ $x has email $e; } or { $x has phone $p; };
----
where each row satisfies both branches at the same time.
--

== Validation

Recall that each variable must have a xref:{page-version}@reference::typeql/patterns/index.adoc[unique scope]. Therefore, the following pattern would be invalid.
In line with the unique scope principle, a variable that is local to more than one pattern is invalid.
The following query is invalid as `$e` has multiple scopes.
[,typeql]
----
match
$x isa $user;
{ following(follower: $x, followed: $y); }
or { following(follower: $y, followed:$x); };
{ $x has email $e; } or { $x has phone $p; };
not { $e contains "@typedb.com"; };
----
Indeed, the variable `$y` does _not_ have a unique scope: it appears at the top-level of both branches of the disjunction.

== Examples

1. Retrieve phone numbers of a specific user _if available_:
+
--
[,typeql]
----
match
$x isa user, has username "john_1";
{ $x has phone $p; } or { not { $x has phone $np; }; };
----
Note that `$p` and `$np` have different variable names to ensure the xref:{page-version}@reference::typeql/patterns/index.adoc[unique scope principle].
--
// Note: A version of this document exists for the version of disjunctions
// that could return None values for branch-local variables.
// Revert to 19fb67756bfb76018315c6c7b380913683ca052c if needed (2025/08/08).

== Examples
1. Retrieve friends and friends of friends of a user;
+
--
[,typeql]
----
match
$x isa user, has username "john_1";
$y isa user;
{ friendship($x, $y); }
or { friendship($x, $z); friendship($z, $y); };
select $x, $y; # omit $z from results
----
--
21 changes: 15 additions & 6 deletions reference/modules/ROOT/pages/typeql/patterns/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@

This reference covers the usage of patterns in TypeQL.

== Scopes and operations

== Scopes
Pattern comprise statements containing variables. Given a pattern, the *scope* of a variable is:

* the block `{ ... }` in which variable appears at top-level (i.e., not nested in further `{...}`) but it does not appear outside of the block,
* the block `{ ... }` in which variable appears at top-level (i.e., not nested in further `{...}`) but it does not appear outside of the block.
* or, the entire pattern itself if the variable appears at the top-level of the pattern itself.

Exceptionally, if the variable appears in all branches of a disjunction, it counts as appearing in the parent pattern.

A key principle of valid TypeQL pattern is:

> *_Every variable must have a unique scope._*

While a statement by itself is an (elementary) patterns, *operations* allow us to construct larger and more interesting patterns from smaller ones, and they create new scopes of variables.
== Combining patterns

== Operation reference
TypeQL allows us to construct larger and more interesting patterns from smaller ones,
allowing us to express more than simple conjunctions.
They can also create new scopes of variables.

[cols-3]
--
Expand All @@ -37,4 +40,10 @@ Use of disjunctions to allow for several branches in a query to be executed in p
****
Use of negations to exclude patterns from your query results.
****
--

.xref:{page-version}@reference::typeql/patterns/optionals.adoc[]
[.clickable]
****
Use of optionals for optionally matching subpatterns.
****
--
Loading