TOML Schema DSL¶
Author TypeDB schemas in TOML instead of TypeQL.
Overview¶
TypeBridge accepts schemas in two formats: TypeQL (.tql) and a TOML
DSL (.toml). Both formats feed the same parser and code generator — TOML
is an alternative authoring surface, not a separate pipeline.
The TOML DSL is useful when you prefer a data-file syntax over TypeQL prose, want IDE tooling for schema keys, or are generating schema files programmatically.
Routing¶
When generate_models receives a path that ends in .toml, it
automatically routes the file through the TOML transpiler before passing the
result to the generator. No extra flags are required.
from type_bridge.generator import generate_models
# .toml suffix routes automatically through the transpiler
generate_models("schema.toml", "out/models/")
If you hold TOML text in memory (not in a file), pass format="toml" to
force the TOML path:
toml_text = """
[attributes.name]
value = "string"
[entities.person]
owns = ["name"]
"""
generate_models(toml_text, "out/models/", format="toml")
A .tql file or raw TypeQL text continues to work exactly as before.
DSL Reference¶
Attributes¶
[attributes.NAME]
value = "string" # value type (see table below); required unless sub is set
sub = "parent" # inherit from a parent attribute instead of declaring a value type
abstract = true # mark as abstract
bindgen_case = "SnakeCase" # specify class name case explicitly for bindgen
annotations = ["dto_name(MyDTO)"] # specify code generator annotations for bindgen
# Annotation constraints (optional, combine as needed)
regex = "^active|inactive$"
values = ["active", "inactive"]
range = "0..150"
value and sub are mutually exclusive — an attribute either has a value
type or inherits from a parent, not both.
Supported value types:
| TOML value | TypeDB type |
|---|---|
"string" |
string |
"long" |
long |
"integer" |
integer |
"int" |
integer |
"double" |
double |
"boolean" |
boolean |
"bool" |
boolean |
"datetime" |
datetime |
"datetime-tz" |
datetime-tz |
"date" |
date |
"duration" |
duration |
"decimal" |
decimal |
Example — annotation constraints:
[attributes.status]
value = "string"
values = ["active", "inactive", "archived"]
[attributes.age]
value = "integer"
range = "0..150"
[attributes.email]
value = "string"
regex = "^[^@]+@[^@]+\\.[^@]+$"
[attributes.person-id]
sub = "id" # inherits from id; no value key
Entities¶
[entities.NAME]
sub = "parent" # optional; inherit from another entity
abstract = true # optional; mark as abstract
bindgen_case = "PascalCase" # optional; explicitly override class case naming
annotations = ["dto_name(MyDTO)"] # optional; add custom generator annotations
owns = [...] # list of owned attributes (see below)
plays = [...] # list of roles the entity plays (see below)
owns entries accept either a plain string (attribute name) or a table
with options:
owns = [
"name", # optional, no annotation
{ attribute = "email", key = true }, # @key
{ attribute = "tag", unique = true }, # @unique
{ attribute = "score", card = "0..100" }, # @card(0..100)
]
plays entries are tables that name the relation and role:
plays = [
{ relation = "employment", role = "employee" },
{ relation = "friendship", role = "friend", card = "0..5" },
]
Set card on a plays entry to emit plays-side cardinality:
plays relation:role @card(...).
Full entity example:
[attributes.username]
value = "string"
[attributes.score]
value = "integer"
range = "0..10000"
[attributes.tag]
value = "string"
values = ["beginner", "intermediate", "expert"]
[entities.user]
bindgen_case = "PascalCase"
annotations = ["dto_name(UserDto)"]
owns = [
{ attribute = "username", key = true },
"score",
{ attribute = "tag", card = "0..3" },
]
plays = [
{ relation = "membership", role = "member" }
]
Relations¶
[relations.NAME]
sub = "parent" # optional; inherit from another relation
abstract = true # optional; mark as abstract
bindgen_case = "PascalCase" # optional; explicitly override class case naming
annotations = ["dto_name(MyDTO)"] # optional; add custom generator annotations
roles = [...] # list of role definitions (see below)
owns = [...] # list of owned attributes (same syntax as entities)
plays = [...] # roles this relation itself plays
roles entries define the roles a relation relates. Each role is a table:
roles = [
{ name = "employer" }, # no cardinality constraint
{ name = "employee", card = "1..3" }, # @card(1..3)
{ name = "author", as = "contributor" }, # role override
]
card sets the @card annotation on the role. as sets a role override
(as contributor).
Relations can also play roles in other relations, using the same plays
entry syntax as entities:
[relations.publication]
roles = [{ name = "publisher" }]
plays = [
{ relation = "contribution", role = "work" },
{ relation = "review", role = "reviewed", card = "0..5" },
]
Full relation example:
[relations.membership]
roles = [
{ name = "member", card = "1.." },
{ name = "group", card = "1..1" },
]
owns = ["joined-at"]
plays = []
Functions¶
[functions.NAME]
signature = "fun NAME($param: type) -> return-type"
body = """
match
...;
return ...;"""
The signature string is the full TypeQL function signature, without a
trailing colon. The body string is verbatim TypeQL passed through to the
transpiler unchanged.
Stream return (curly-brace form):
[functions.top-scorer]
signature = "fun top-scorer($g: game) -> { player }"
body = """ match
($g, $p) isa participation;
return { $p };"""
Scalar return:
[functions.max-score]
signature = "fun max-score($g: game) -> double"
body = """ match
$g has score $s;
return max($s);"""
Structs¶
[structs.NAME]
fields = [
{ name = "field-name", type = "string" },
{ name = "optional-field", type = "integer", optional = true },
]
Each field entry must have name and type. Set optional = true for
nullable fields (generates field: T | None = None in Python).
[structs.player-stats]
fields = [
{ name = "wins", type = "integer" },
{ name = "losses", type = "integer" },
{ name = "nickname", type = "string", optional = true },
]
Complete Example¶
The following schema combines every TOML family:
# Attributes
[attributes.email]
value = "string"
regex = "^[^@]+@[^@]+\\.[^@]+$"
[attributes.username]
value = "string"
[attributes.score]
value = "integer"
range = "0..10000"
[attributes.tag]
value = "string"
values = ["beginner", "intermediate", "expert"]
[attributes.created-at]
value = "datetime"
# Entities
[entities.user]
owns = [
{ attribute = "username", key = true },
"email",
"score",
{ attribute = "tag", card = "0..5" },
]
plays = [{ relation = "membership", role = "member" }]
[entities.team]
owns = [
{ attribute = "username", key = true },
"created-at",
]
plays = [{ relation = "membership", role = "group" }]
# Relations
[relations.membership]
roles = [
{ name = "member", card = "1.." },
{ name = "group", card = "1..1" },
]
owns = ["created-at"]
# Functions
[functions.team-members]
signature = "fun team-members($t: team) -> { user }"
body = """ match
($t, $u) isa membership;
return { $u };"""
# Structs
[structs.user-profile]
fields = [
{ name = "display-name", type = "string" },
{ name = "bio", type = "string", optional = true },
]
Generate models from this file:
Or from TOML text held in memory:
Error Reporting¶
A malformed TOML schema raises ValueError with a message that identifies
the offending field or type. Common errors:
| Condition | Example error |
|---|---|
Attribute has both value and sub |
"Attribute 'id': cannot set both value and sub" |
| Unknown value type | "Attribute 'score': unknown value type 'uint'" |
Attribute sub references an unknown parent |
"Attribute 'child-id': sub parent 'unknown' not defined" |
| Role player references an unknown type | "Relation 'review': role 'reviewer' player type not found" |
| Struct with no fields | "Struct 'empty-struct': fields list is empty" |
| Malformed function body | "Function 'my-fn': body does not contain a return statement" |
Current Scope¶
The TOML DSL covers attributes, entities, relations, functions, and structs for
the schema forms used by the generator. It supports abstract subtypes,
relation-level plays, and per-plays cardinality. TOML is still a front-end
to TypeQL: emitted TypeQL is parsed by the shared schema parser before model
generation.
See Also¶
- Code Generator — full
generate_modelsAPI reference and CLI usage - Attributes — attribute types and constraints
- Entities — entity inheritance and ownership
- Relations — relations, roles, and role players