5. Defining models (the ORM DSL)
Models are defined with a fluent, type-safe DSL from
@damatjs/orm-model. model(table, columns)
returns a definition you can refine with .indexes(), .constrain(),
.timestamps(), and .softDelete().
import { model, columns } from "@damatjs/orm-model";
export const UserModel = model("users", {
id: columns.id({ prefix: "usr" }).primaryKey(),
email: columns.text().unique(),
emailVerified: columns.boolean().default(false),
name: columns.text().nullable(),
image: columns.text().nullable(),
// relations reference the target table name
accounts: columns.hasMany("accounts"),
sessions: columns.hasMany("sessions"),
}).indexes([
columns.indexes().columns(["email"]).unique(),
]);
export default UserModel;
Columns
The DSL covers the PostgreSQL type system. Common builders:
| Group | Builders |
|---|---|
| Identity | id({ prefix? }), uuid() |
| Strings | text(), varchar(length?), char(length?) |
| Numbers | integer(), numeric(precision?, scale?), real(), doublePrecision(), money() |
| Boolean | boolean() |
| Temporal | timestamp({ withTimezone? }), date(), time(), interval() |
| JSON | json(), jsonb() |
| Binary | bytea() |
| Enum | enum(values) |
| Vector | vector(dimensions) — pgvector |
| Relations | belongsTo(target), hasMany(target), hasOne(target) |
Modifiers chain: .primaryKey(), .unique(), .nullable(),
.default(value), .defaultNow(), .length(n), .name("col_name"),
.autoincrement(). See the
orm-model column reference for the
complete list and exact semantics.
Relations, indexes, constraints
export const AccountModel = model("accounts", {
id: columns.id({ prefix: "acc" }).primaryKey(),
userId: columns.text(),
provider: columns.text(),
user: columns.belongsTo("users"), // FK -> users
})
.indexes([columns.indexes().columns(["userId"])])
.timestamps(); // adds createdAt / updatedAt
Relations like belongsTo/hasMany are for tables within one module. To
relate models that live in different modules, use a cross-module link
instead (src/links/, with defineLink/collectLinkModels/defineLinkModule)
so neither module depends on the other — see
Concepts → How modules compose,
the default backend, and the full
@damatjs/link reference.
Once models change, generate and apply a migration.