Relationships
Relationships define how entities connect to each other. They are declared
inside an entity’s schema block using three types: has-many, has-one, and
belongs-to.
entity "User" {
schema {
pk "id" type="int"
field "name" type="string"
has-many "Post" as="posts"
}
}
entity "Post" {
schema {
pk "id" type="int"
field "title" type="string"
belongs-to "User" as="author" on="id"
}
}
has-many
Defines a one‑to‑many relationship where the current entity is the parent (e.g.,
a User has many Posts).
| Attribute | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | ✓ | – | Target entity name (child) |
as |
string | name |
Relationship name | |
on-delete |
string | "cascade" |
Action when parent is deleted: "cascade", "restrict", "set null", "no action" |
|
on-update |
string | "no action" |
Action when parent’s primary key changes | |
optional |
bool | false |
Whether the relationship can be empty (i.e., no child records) |
Example:
A User has many Posts. The foreign key column in the post table will be
named user_id.
has-one
Defines a one‑to‑one relationship (e.g., a User has one Profile).
| Attribute | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | ✓ | – | Target entity name |
as |
string | name |
Relationship name | |
on-delete |
string | "cascade" |
Action when parent is deleted | |
on-update |
string | "no action" |
Action when parent’s primary key changes | |
optional |
bool | false |
Whether the relationship can be missing (i.e., no child record) |
Example:
A User has one Profile. The foreign key column in the profile table will
be user_id.
belongs-to
Defines the inverse side of a relationship (child belongs to parent). Usually
used with has-many or has-one.
| Attribute | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | ✓ | – | Parent entity name |
as |
string | name |
Relationship name ({as}_id) |
|
on |
string | "id" |
Primary key column name in the parent table | |
optional |
bool | false |
Whether the foreign key can be NULL |
Important: The on attribute refers to the parent’s primary key column, not
the foreign key in the child.
Example:
A Post belongs to a User. The parent User has a primary key column
id.
entity "User" {
schema {
pk "id" type="int" // primary key column name is "id"
}
}
entity "Post" {
schema {
belongs-to "User" as="author" // foreign key column becomes "author_id"
}
}
If the parent’s primary key is named differently:
entity "User" {
schema {
pk "user_id" type="int" // custom primary key name
}
}
entity "Post" {
schema {
belongs-to "User" as="author" on="user_id" // references User(user_id)
}
}
Complete Example
application "BlogApp" version="0.1" {
entity "User" {
schema {
pk "id" type="int"
field "name" type="string"
has-many "Post" as="posts" on-delete="cascade"
has-one "Profile" as="profile"
}
}
entity "Profile" {
schema {
pk "id" type="int"
field "bio" type="string"
belongs-to "User" as="user" optional=false
}
}
entity "Post" {
schema {
pk "id" type="int"
field "title" type="string"
field "content" type="string"
belongs-to "User" as="author" on="id"
has-many "Comment" as="comments"
}
}
entity "Comment" {
schema {
pk "id" type="int"
field "body" type="string"
belongs-to "Post" as="post" on="id"
}
}
profile "dev" default=true {
listen address="127.0.0.1" port=8080
}
}
What Terranova Does With Relationships
- Database schema – Creates foreign key columns in the child table based on the relationship definition.
- Referential actions – The
on-deleteandon-updateattributes influence how the API behaves (and may be passed to SQLite if supported).