| name | typeql |
| description | Write and debug TypeQL queries for TypeDB 3.8+. Use when working with TypeDB schemas, data queries, insertions, deletions, or functions. Covers schema definition, CRUD operations, pattern matching, aggregations, and common pitfalls. |
TypeQL Language Reference for TypeDB 3.8+
This skill provides comprehensive guidance for writing TypeQL queries against TypeDB databases.
Note (3.8+): Trailing commas are now allowed in all comma-separated contexts (variable lists, statements, reductions) for easier query composition.
Note (3.8+): Unicode identifiers are now supported. Type names, attribute names, and variable names can use any Unicode XID_START character followed by XID_CONTINUE characters (e.g., 名前, prénom, город).
Quick Reference
Transaction Types
| Type | Use For | Commit |
|---|
schema | Define/undefine types, functions | Yes |
write | Insert, update, delete data | Yes |
read | Match, fetch, select queries | No (use close) |
Query Structure
[with ...] -- Inline function preamble
[define|undefine|redefine] -- Schema operations
[match] -- Pattern matching
[insert|put|update|delete] -- Data mutations
[select|sort|offset|limit] -- Stream operators
[require|distinct] -- Filtering operators
[reduce ... groupby] -- Aggregations
[fetch] -- JSON output
; -- EVERY query MUST end with a semicolon
1. Schema Definition
Schema definitions create types and constraints. Run in schema transactions.
Root Types (TypeDB 3.x)
In TypeDB 3.x, thing is no longer a valid root. The three roots are:
entity
relation
attribute
Attribute Types
define
# Basic value types
attribute name, value string;
attribute age, value integer;
attribute salary, value double;
attribute is_active, value boolean;
attribute created_at, value datetime;
# With constraints
attribute email, value string @regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$");
attribute priority, value integer @range(1..5);
attribute status, value string @values("pending", "active", "completed");
Entity Types
define
# Simple entity
entity person;
# Entity with attributes
entity person,
owns name,
owns email @key, # Unique identifier
owns age @card(0..1); # Optional (0 or 1)
# Abstract entity (cannot be instantiated)
entity artifact @abstract,
owns name,
owns created_at;
# Entity inheritance
entity user sub artifact,
owns email @key;
Relation Types
define
# Basic relation with roles
relation employment,
relates employer,
relates employee;
# Entities playing roles
entity company,
plays employment:employer;
entity person,
plays employment:employee;
# Relation with cardinality on roles
relation manages,
relates manager @card(1), # Exactly one manager
relates report @card(1..); # One or more reports
# Relation owning attributes
relation employment,
relates employer,
relates employee,
owns start_date,
owns end_date @card(0..1);
# Self-referential relation
relation friendship,
relates friend; # Same role played twice
entity person,
plays friendship:friend;
Role Overriding (Inheritance)
define
# Base relation
relation relationship,
relates partner;
# Specialized relation with role override
relation marriage sub relationship,
relates spouse as partner; # 'spouse' overrides 'partner'
entity person,
plays marriage:spouse;
Type Aliases
define
# Create an alias for an existing type
attribute username alias name; # username is an alias for name
Annotations Reference
| Annotation | Usage | Description |
|---|
@key | owns name @key | Unique identifier for type |
@unique | owns email @unique | Unique but not primary key |
@card(n) | owns age @card(0..1) | Cardinality constraint |
@regex(...) | value string @regex(...) | Pattern validation |
@range(...) | value integer @range(1..100) | Value range |
@values(...) | value string @values("a","b") | Enum-like constraint |
@abstract | entity @abstract | Cannot be instantiated |
@cascade | owns ref @cascade | Cascade delete when owner deleted |
@independent | owns tag @independent | Attribute exists independently of owner |
@distinct | owns item @distinct | Each value can only be owned once |
@subkey(...) | owns code @subkey(region) | Composite key with another attribute |
Note: @key and @unique can only be put on owns, not directly on an attribute value definition.
2. Schema Modification
Undefine (Remove Schema Elements)
undefine
# Remove entire type
person;
# Remove capability from type
owns email from person;
plays employment:employee from person;
relates employee from employment;
# Remove annotation from type
@abstract from artifact;
# Remove annotation from capability
@key from person owns email;
# Remove role specialization
as spouse from marriage relates spouse;
# Remove function
fun get_active_users;
# Remove struct
struct address;
Redefine (Modify Existing Schema)
redefine
# Change annotation on type
entity person @abstract;
# Change annotation on capability
person owns age @card(1..1); # Make required
# Redefine function (replaces entirely)
fun count_users() -> integer:
match $u isa user, has status "active";
return count;
3. Data Operations (CRUD)
Insert
# Insert entity with attributes
insert
$p isa person,
has name "Alice",
has email "alice@example.com";
# Insert using anonymous variable (when reference not needed)
insert
$_ isa person, has name "Bob";
# Insert relation (match entities first)
match
$p isa person, has email "alice@example.com";
$c isa company, has name "Acme Inc";
insert
$_ isa employment, links (employer: $c, employee: $p),
has start_date 2024-01-15;
Put (Upsert)
# Put creates if not exists, matches if exists
# Useful for idempotent operations
match
$c isa company, has name "Acme Inc";
put
$p isa person, has email "alice@example.com", has name "Alice";
insert
employment (employer: $c, employee: $p);
# Put finds existing person by email (key) or creates new one
# Then insert creates the relation
Update
# Update single-cardinality attribute (implicit replacement)
match
$p isa person, has email "alice@example.com";
update
$p has email "alice.smith@example.com";
# Update multi-cardinality: delete old, insert new
match
$p isa person, has name "Alice";
$p has nickname $old;
delete
$p has $old;
insert
$p has nickname "Ally";
Delete
# Delete entity
match
$p isa person, has email "alice@example.com";
delete
$p;
# Delete attribute from entity
match
$p isa person, has email "alice@example.com", has nickname $n;
delete
$p has $n;
# Alternative: delete attribute using 'of'
match
$p isa person, has email "alice@example.com", has nickname $n;
delete
has $n of $p;
# Delete relation
match
$p isa person, has email "alice@example.com";
$c isa company, has name "Acme Inc";
$e isa employment, links (employer: $c, employee: $p);
delete
$e;
# Delete role player from relation (keeps relation)
match
$rel isa membership, links (member: $old_member, group: $g);
$old_member has email "alice@example.com";
delete
links ($old_member) of $rel;
# Optional delete (try) - no error if not found
match
$p isa person, has email "alice@example.com";
delete
try {
$p has nickname $n;
};
4. Querying Data
Match + Fetch (Primary Query Pattern)
# Fetch specific attributes
match
$p isa person, has name $n, has email $e;
fetch {
"name": $n,
"email": $e
};
# Fetch all attributes of entity
match
$p isa person, has email "alice@example.com";
fetch {
"person": { $p.* }
};
# Fetch with attribute projection
match
$p isa person;
fetch {
"name": $p.name,
"email": $p.email
};
# Fetch multi-valued attributes as list
match
$p isa person, has email "alice@example.com";
fetch {
"name": $p.name,
"all_nicknames": [ $p.nickname ]
};
# Nested fetch for related data
# NOTE: the inner `fetch` inside `[ ... ]` is the terminal stage of a sub-pipeline,
# so it also needs a trailing `;` (just like the outer fetch).
match
$c isa company, has name "Acme Inc";
fetch {
"company": $c.name,
"employees": [
match
employment (employer: $c, employee: $p);
fetch {
"name": $p.name
};
]
};
# Fetch with inline function
# NOTE: the sub-query in parens is a function block — it ends with `return`,
# not `reduce`. Use `return count;` (or `return first $x;` etc.) for scalar results.
match
$c isa company;
fetch {
"company": $c.name,
"employee_count": (
match
employment (employer: $c, employee: $e);
return count;
)
};
Filtering Patterns
# Filter by type
match $x isa person;
# Filter by exact type (not subtypes)
match $x isa! person;
# Filter by attribute value
match $p isa person, has age > 30;
# Filter by relation
match
$c isa company, has name "Acme Inc";
employment (employer: $c, employee: $p);
# Filter by relation with relation variable
match
$c isa company, has name "Acme Inc";
$rel isa employment, links (employer: $c, employee: $p);
# Comparison operators: ==, !=, <, <=, >, >=, like, contains
match
$p isa person, has name $n;
$n like "^A.*"; # Regex match
match
$p isa person, has bio $b;
$b contains "engineer"; # Substring match
Identity Check (is)
# Check if two variables refer to the same concept
match
$p1 isa person;
$p2 isa person;
friendship (friend: $p1, friend: $p2);
not { $p1 is $p2; }; # Exclude self-friendship
fetch { "person": $p1.name };
Conjunction (Grouping with AND)
# Explicit grouping with curly braces
match
$p isa person;
{
$p has age > 18;
$p has status "active";
}; # Both conditions must be true
Disjunction (OR)
match
$p isa person, has email $e;
{
$p has name "Alice";
} or {
$p has name "Bob";
};
fetch { "email": $e };
Negation (NOT)
# Find persons not employed by Acme
match
$p isa person;
not {
$c isa company, has name "Acme Inc";
employment (employer: $c, employee: $p);
};
fetch { "unemployed": $p.name };
Optional Patterns (TRY)
# Match with optional pattern
match
$p isa person, has name $n;
try {
$p has email $e;
};
fetch {
"name": $n,
"email": $e # May be null if no email
};
5. Stream Operators
These operators can be reordered or repeated within a pipeline.
# Sort results
match
$p isa person, has name $n;
sort $n asc;
# Sort descending
match
$p isa person, has age $a;
sort $a desc;
# Pagination
match
$p isa person, has name $n;
sort $n asc;
offset 10;
limit 10;
# Select specific variables (like SQL SELECT)
match
$p isa person, has name $n, has email $e;
select $n, $e;
# Distinct results
match
$p isa person, has name $n;
distinct;
# Require variables to be bound (filter nulls from try)
match
$p isa person, has name $n;
try { $p has email $e; };
require $e; # Only return rows where email exists
6. Aggregations
# Count
match
$p isa person;
reduce $count = count;
# Count specific variable
match
$p isa person, has email $e;
reduce $count = count($e);
# Multiple aggregations
match
$p isa person, has salary $s;
reduce
$max = max($s),
$min = min($s),
$avg = mean($s);
# Group by
match
$c isa company;
employment (employer: $c, employee: $e);
reduce
$count = count groupby $c;
# Multiple groupby variables
match
$c isa company, has industry $ind;
employment (employer: $c, employee: $e);
$e has department $dept;
reduce
$count = count groupby $ind, $dept;
Available Reducers
| Reducer | Usage | Description |
|---|
count | count or count($var) | Count results |
sum($var) | sum($salary) | Sum numeric values |
min($var) | min($age) | Minimum value |
max($var) | max($age) | Maximum value |
mean($var) | mean($score) | Average |
median($var) | median($score) | Median |
std($var) | std($score) | Standard deviation |
list($var) | list($name) | Collect into list |
7. Expressions and Computed Values
Arithmetic Operators
match
$p isa product, has price $price, has quantity $qty;
let $subtotal = $price * $qty; # Multiplication
let $with_tax = $subtotal * 1.1; # More multiplication
let $discount = $subtotal / 10; # Division
let $final = $subtotal - $discount; # Subtraction
let $total = $final + 5.00; # Addition (shipping)
let $squared = $price ^ 2; # Power/exponent
let $remainder = $qty % 3; # Modulo
fetch {
"product": $p.name,
"total": $total
};
Assignment and Literals
match
$p isa product, has price $price;
let $vat_rate = 0.2; # Assign literal
let $price_with_vat = $price * (1 + $vat_rate);
fetch {
"price_with_vat": $price_with_vat
};
Built-in Functions
match
$p isa product, has price $price, has name $name;
# NOTE: ceil, floor, round only work on double/decimal, not integers
let $rounded = round($price); # Round to nearest integer
let $ceiling = ceil($price); # Round up
let $floored = floor($price); # Round down
let $absolute = abs($price - 100); # Absolute value
let $name_len = len($name); # String length (note: len, not length)
let $higher = max($price, 10.0); # Maximum of two values
let $lower = min($price, 100.0); # Minimum of two values
fetch {
"rounded": $rounded,
"ceiling": $ceiling,
"floored": $floored
};
# String concatenation
match
$u isa user, has first_name $fn, has last_name $ln;
let $full = concat($fn, " ", $ln);
fetch { "full_name": $full };
# Get IID of a concept (3.8+)
match
$p isa person, has email "alice@example.com";
fetch {
"iid": iid($p) # Get internal identifier
};
# Get type label (3.8+) - NOTE: label() works on TYPE variables, not instances!
# Use isa! to bind the exact type of an instance to a type variable.
match
$p isa! $t, has email "alice@example.com";
fetch {
"iid": iid($p),
"type": label($t) # label() on TYPE variable $t
};
8. List Operations
List Literals
match
$p isa person, has name $name;
let $tags = ["active", "verified", "premium"]; # List literal
fetch { "name": $name, "tags": $tags };
List Indexing
match
$p isa person, has score $scores; # Multi-valued attribute
let $first = $scores[0]; # First element (0-indexed)
let $second = $scores[1]; # Second element
fetch { "first_score": $first };
List Slicing
match
$p isa person, has score $scores;
let $top_three = $scores[0..3]; # Elements 0, 1, 2
let $rest = $scores[3..10]; # Elements 3 through 9
fetch { "top_scores": $top_three };
9. Structs
Struct Definition
define
# Define a struct type
struct address:
street value string,
city value string,
zip value string?, # Optional field (nullable)
country value string;
WARNING: structs are not yet implemented as of TypeDB 3.8.0, so should not be used.
Using Structs
# Insert with struct value
insert
$p isa person,
has name "Alice",
has home_address { street: "123 Main St", city: "Boston", zip: "02101", country: "USA" };
# Match struct fields
match
$p isa person, has home_address $addr;
$addr isa address { city: "Boston" };
fetch { "person": $p.name };
Struct Destructuring
# Destructure struct in let
match
$p isa person, has home_address $addr;
let { city: $city, zip: $zip } = $addr;
fetch {
"person": $p.name,
"city": $city
};
10. Functions
Define reusable query logic in schema.
Function Definition
define
# Return stream of values
fun get_active_users() -> { string }:
match
$u isa user, has status == "active", has email $e;
return { $e };
# Return single value with aggregation
fun count_users() -> integer:
match
$u isa user;
return count;
# Function with parameters
fun get_user_projects($user_email: string) -> { string }:
match
$u isa user, has email == $user_email;
membership (member: $u, project: $p);
$p has name $name;
return { $name };
# Return multiple values in stream
fun get_user_details($email: string) -> { string, string }:
match
$u isa user, has email == $email, has name $n, has role $r;
return { $n, $r };
# Return first match only
fun get_oldest_user() -> string:
match
$u isa user, has name $n, has age $a;
sort $a desc;
return first $n;
# Return last match only
fun get_youngest_user() -> string:
match
$u isa user, has name $n, has age $a;
sort $a desc;
return last $n;
# Return boolean (existence check)
fun user_exists($email: string) -> boolean:
match
$u isa user, has email == $email;
return check; # Returns true if match found, false otherwise
Using Functions
# Call function in match with 'let ... in'
match
let $emails in get_active_users();
fetch { "active_emails": $emails };
# Call function with parameter
match
let $projects in get_user_projects("alice@example.com");
fetch { "projects": $projects };
# Call function returning single value
match
let $count in count_users();
fetch { "total_users": $count };
# Use function in expression
match
$u isa user;
let $exists in user_exists($u.email);
fetch { "user": $u.name, "verified": $exists };
Inline Functions with WITH
# Define function inline for single query
with
fun active_in_dept($dept: string) -> { user }:
match
$u isa user, has department == $dept, has status "active";
return { $u };
match
let $user in active_in_dept("Engineering");
fetch { "engineer": $user.name };
11. IID (Internal Identifier) Operations
# Match by IID (for direct lookups)
match
$entity iid 0x1f0005000000000000012f;
fetch { "data": { $entity.* } };
# Get IID using iid() function (3.8+)
match
$p isa person, has email "alice@example.com";
fetch {
"person": $p.name,
"iid": iid($p)
};
# Get IID and exact type label together (3.8+)
# NOTE: label() requires a TYPE variable, use isa! to bind it
match
$p isa! $t, has email "alice@example.com";
fetch {
"iid": iid($p),
"type": label($t)
};
12. Rules (Inference)
TypeDB 3.0 and on no longer uses rules, and uses only functions instead.
13. Common Patterns
Note: clauses like match, insert, update, and delete are not themselves terminated with a trailing semicolon — each statement within them already ends in ;. The fetch clause is the exception: the closing } of the fetch object must be followed by a terminating ;.
Upsert (Insert if not exists)
# Use 'put' for upsert behavior
match
$c isa company, has name "Acme Inc";
put
$p isa person, has email "new@example.com", has name "New Person";
insert
employment (employer: $c, employee: $p);
Polymorphic Queries
# Query abstract supertype to get all subtypes
match
$artifact isa artifact, has name $n; # Gets all subtypes
fetch { "name": $n };
# Query exact type only (not subtypes)
match
$artifact isa! artifact, has name $n; # Only direct instances
fetch { "name": $n };
Graph Traversal
# Find all connected nodes (1-hop via any relation, role types omitted)
match
$center isa entity, has id == "target-id";
$_ links ($center, $neighbor);
not { $neighbor is $center; };
fetch {
"center": $center.id,
"neighbor": $neighbor.id
};
Existence Check
# Check if pattern exists
match
$u isa user, has email "alice@example.com";
not { team_membership (member: $u); };
# Returns results only if user exists but has no team
14. Critical Pitfalls
TypeDB 3 relation syntax
Use only these two forms. Other shapes that parse — e.g. (<players>) isa <rel-type> (reversed) or $r isa <rel-type> (<players>) (compact-typed) — are deprecated or ambiguous; do not generate them. A bare anonymous relation with no anchor — (<players>); — is not valid: it needs either a relation type or a relation variable (see polymorphic note below).
1. Anonymous (no relation variable):
<rel-type> (<role-type>: <player var>, <role-type-2>: <player var 2>, ...);
Use this when you don't need to refer to the relation instance.
2. Typed relation variable with links:
$rel-var isa <rel-type>,
links (<role-type>: <player var>, <role-type-2>: <player var 2>, ...);
Use this when you need a variable for the relation instance — e.g. to delete it, attach has to it, or reference it elsewhere in the query.
Role types can be omitted to match any role (friendship ($a, $b);). For fully-polymorphic matching (matching any relation type), use an anonymous relation variable with links: $_ links ($a, $b);.
Reserved keywords
These are reserved identifiers. Never use them as user-defined identifier like type labels or variables, in any capitalization. If required, append _ instead:
with, match, fetch, update, define, undefine, redefine, insert, put, delete, end , entity, relation, attribute, role , asc, desc, struct, fun, return, alias, sub, owns, as, plays, relates, iid, isa, links, has, is, or, not, try, in, true, false, of, from, first, last
Match Clauses are Simultaneous (AND)
All statements in match must be satisfied together. Not sequential.
# WRONG assumption: "get all books, then find promotions"
# ACTUAL: Only returns books that ARE in promotions
match
$b isa book;
promotion (book: $b, promo: $p);
Unconstrained Variables = Cross Join
# PROBLEM: Returns every book x every promotion (Cartesian product)
match
$b isa book;
$p isa promotion; # Not linked to $b!
# FIX: Link variables through relations
match
$b isa book;
book_promotion (book: $b, promotion: $p);
Symmetric Relations Return Duplicates
# PROBLEM: Returns (A,B) and (B,A)
match
friendship (friend: $p1, friend: $p2);
# FIX: Add asymmetric constraint
match
$p1 has email $e1;
$p2 has email $e2;
friendship (friend: $p1, friend: $p2);
$e1 < $e2; # Each pair only once
Cardinality Validated at Commit
Insert violations don't fail immediately - only on commit.
Sorting Loads All Results
sort requires loading all matching data into memory before pagination.
Variable Scoping in OR/NOT
Variables inside or blocks are not guaranteed bound outside:
# INVALID: $company might not be bound
match
$p isa person;
{
employment (employee: $p, employer: $company);
} or {
$p has status "freelancer";
};
not { $company has name "BadCorp"; }; # $company may be unbound!
# VALID: Bind variable in parent scope first
match
$p isa person;
employment (employee: $p, employer: $company);
not { $company has name "BadCorp"; };
Variable Reuse in OR Branches
# INVALID: $x means different things in each branch
match {
editing (person: $p, document: $x);
} or {
messaging (person: $p, message: $x);
};
# VALID: Use different variable names
match {
editing (person: $p, document: $doc);
} or {
messaging (person: $p, message: $msg) ;
};
15. CLI Notes
Command Execution
typedb console --command "database list"
typedb console --command "transaction mydb schema" --command "define entity person;"
Script Files (.tqls)
# Console commands without semicolons
transaction mydb schema
define
entity person;
commit
Transaction Lifecycle
schema, write transactions: use commit
read transactions: use close
16. Value Types Reference
| TypeQL Type | Description | Example Literal |
|---|
string | UTF-8 text | "hello" |
boolean | true/false | true, false |
integer | 64-bit signed int | 42, -17 |
double | Double-precision float | 3.14159 |
decimal | Precise decimal | 99.99dec |
date | Date only | 2024-01-15 |
datetime | Date and time | 2024-01-15T10:30:00 |
datetime-tz | With timezone | 2024-01-15T10:30:00 America/New_York |
duration | Time duration | P1Y2M3D, PT4H30M |
Note: 0dec is not valid syntax in some versions of TypeDB. Always use 0.0dec.
Duration Format (ISO 8601)
P[n]Y[n]M[n]DT[n]H[n]M[n]S
P1Y2M3D = 1 year, 2 months, 3 days
PT4H30M = 4 hours, 30 minutes
P1W = 1 week
PT1H30M45S = 1 hour, 30 minutes, 45 seconds
17. Debugging Queries
Test Match Before Write
# Before running delete:
match
$u isa user, has status "inactive";
fetch { "will_delete": $u.email };
# Then execute:
match
$u isa user, has status "inactive";
delete $u;
Check Schema
# In read transaction - list entity types
match
$type sub entity;
fetch { "entity_types": $type };
# List relation types
match
$rel sub relation;
fetch { "relation_types": $rel };
# List attribute types
match
$attr sub attribute;
fetch { "attribute_types": $attr };
Verify Cardinality
# Count instances per type
match
$type sub entity;
$instance isa! $type;
reduce $count = count groupby $type;
Debugging match clauses
When a match returns results unexpectedly (say 0, though maybe more than expected), comment out some connected constraints with #, then count:
match
$p isa person, has name $n;
$p has status "Active"; # suspect constraint
# employment (employer: $c, employee: $p); # commented out
# $c has name "Acme"; # commented out
reduce $count = count;
If count > 0, problem is in the commented-out half. If still 0, problem is in the active half. Repeat to isolate the exact constraint.
Debugging sulti-stage Pipelines
When a pipeline (e.g., match → reduce → match → update) writes nothing, run successive prefixes to find where data stops flowing:
# Prefix 1: just the match — does it find data?
match ...;
reduce $count = count;
# Prefix 2: match + reduce — are aggregated values correct?
match ...;
reduce $total = sum($amount) groupby $customer;
# Prefix 3: match + reduce + filter — do any pass the threshold?
match ...;
reduce $total = sum($amount) groupby $customer;
match $total > 20000.0;
reduce $count = count;
18. Complete Operator Reference
Comparison Operators
| Operator | Description | Example |
|---|
== | Equal | $age == 30 |
!= | Not equal | $status != "done" |
< | Less than | $age < 18 |
<= | Less than or equal | $age <= 65 |
> | Greater than | $salary > 50000 |
>= | Greater than or equal | $score >= 90 |
like | Regex match | $name like "^A.*" |
contains | Substring match | $bio contains "dev" |
Math Operators
| Operator | Description | Example |
|---|
+ | Addition | $a + $b |
- | Subtraction | $a - $b |
* | Multiplication | $a * $b |
/ | Division | $a / $b |
% | Modulo | $a % $b |
^ | Power | $a ^ 2 |
Expression Functions
| Function | Description | Example |
|---|
abs($x) | Absolute value | abs($n - 10) |
ceil($x) | Round up (double/decimal only) | ceil($price) |
floor($x) | Round down (double/decimal only) | floor($price) |
round($x) | Round nearest (double/decimal) | round($price) |
len($s) | String length | len($name) |
max($a,$b) | Maximum of two values | max($x, 0) |
min($a,$b) | Minimum of two values | min($x, 100) |
iid($var) | Get internal identifier (3.8+) | iid($p) |
label($t) | Get type label (TYPE var only!) | label($t) |
concat(…) | Concatenate strings | concat($a," ",$b) |
Pattern Keywords
| Keyword | Description |
|---|
isa | Type check (includes subtypes) |
isa! | Exact type check (excludes subtypes) |
has | Attribute ownership |
links | Role player in relation |
is | Identity comparison |
or | Disjunction |
not | Negation |
try | Optional pattern |