Schema Definition
Ballerina ORM uses annotated record types as the schema source of truth. You do not need a separate schema DSL.
Why annotated records
- schema and runtime model stay in one type
- annotations make mapping intent explicit
- compiler-time tooling can validate constraints
Entity and fields
ballerina
import thambaru/bal_orm.orm;
import ballerina/time;
@orm:Entity {tableName: "users"}
@orm:Index {columns: ["email"], unique: true}
public type User record {|
@orm:Id @orm:AutoIncrement
int id;
@orm:Column {length: 255, nullable: false}
string email;
@orm:Column {nullable: false}
string name;
@orm:CreatedAt
time:Utc createdAt;
@orm:UpdatedAt
time:Utc updatedAt;
@orm:Relation {'type: orm:ONE_TO_MANY}
Post[]? posts;
|};Supported field annotations
| Annotation | Purpose |
|---|---|
@orm:Id | Marks primary key fields |
@orm:AutoIncrement | Marks auto-increment behavior for key fields |
@orm:Column { ... } | Column options (name, 'type, length, nullable, unique, 'default) |
@orm:Relation { ... } | Relationship metadata ('type, references, foreignKey, joinTable) |
@orm:CreatedAt | ORM-managed creation timestamp |
@orm:UpdatedAt | ORM-managed update timestamp |
@orm:Ignore | Excludes field from persistence mapping |
Entity-level annotations
| Annotation | Purpose |
|---|---|
@orm:Entity {tableName, schema, engine} | Maps record to table/schema/engine |
@orm:Index {columns, unique, name} | Defines single or composite indexes |
@orm:Index is repeatable, so you can attach multiple indexes to one entity.
Relation example
ballerina
@orm:Entity {tableName: "posts"}
public type Post record {|
@orm:Id @orm:AutoIncrement
int id;
string title;
@orm:Column {nullable: false}
int authorId;
@orm:Relation {
'type: orm:MANY_TO_ONE,
references: ["id"],
foreignKey: ["authorId"]
}
User? author;
|};Next step
Read ORM Client to connect these models to a live database.