@damatjs/orm-model
v1.0.6
Published
Damatjs orm model definition
Readme
@damatjs/orm-model
The fluent, type-safe schema-definition DSL for the Damat ORM.
@damatjs/orm-model is the layer where you describe your database: tables,
columns, enums, indexes, constraints, and relationships, all through a small
fluent builder API (model(...) + columns.*). A model definition is pure
metadata — it produces a serializable TableSchema (and, grouped, a
ModuleSchema) that the rest of the stack turns into migrations, queries, and
generated TypeScript row types. It carries no SQL execution of its own. This is
the package you interact with most when modelling a domain; everything downstream
(registry, query builder, migration engine, and schema generators) consumes its
output.
Part of the Damat monorepo · Full guide · Internals
Install
bun add @damatjs/orm-modelInside the monorepo it is referenced as a workspace dependency:
// package.json
{
"dependencies": {
"@damatjs/orm-model": "*",
},
}When to use
Use this package when you are:
- Defining tables / entities for a Damat module (
model(...)+columns.*). - Declaring named PostgreSQL enums (
EnumBuilder). - Adding indexes and table-level constraints (
indexBuilder/constrainBuilder, orcolumns.indexes()/columns.constrains()). - Wiring relationships (
columns.belongsTo/hasMany/hasOne). - Grouping models into a module snapshot (
toModuleSchema) or validating that relations are wired consistently (validateRelations/assertValidRelations).
You would not use this package directly to:
- Run SQL or build queries — that is the driver layer (
@damatjs/orm-pg). - Register/look up models at runtime or log queries — that is
@damatjs/orm-core. - Generate migrations or DDL — that is the migration package.
Quick start
import {
model,
columns,
EnumBuilder,
toModuleSchema,
assertValidRelations,
} from "@damatjs/orm-model";
// A named enum (CREATE TYPE ... AS ENUM)
const OrderStatus = new EnumBuilder(["pending", "shipped", "delivered"]).name(
"order_status",
);
const User = model(
"user",
{
id: columns.id({ prefix: "usr" }).primaryKey(),
email: columns.text().unique(),
name: columns.text(),
age: columns.integer().nullable(),
verified: columns.boolean().default(false),
metadata: columns.jsonb().nullable(),
// inverse side — no FK column; FK lives on `order.user`
orders: columns.hasMany("order").mappedBy("user"),
},
{ schema: "store" },
).indexes([columns.indexes("uniq_users_email").columns(["email"]).unique()]);
const Order = model("order", {
id: columns.id({ prefix: "ord" }).primaryKey(),
total: columns.numeric(12, 2),
status: columns.enum(OrderStatus),
placedAt: columns.timestamp({ withTimezone: true }).defaultNow(),
// owning side — creates the `user_id` FK column on `order`
user: columns.belongsTo("user").onDelete("CASCADE").indexed(),
}).constrain([columns.constrains("orders_total_pos").check("total > 0")]);
// Catch broken relation wiring early
assertValidRelations([User, Order]);
// Produce the serializable snapshot
const schema = toModuleSchema("store", [User, Order], { enums: [OrderStatus] });
// schema.tables, schema.enums, schema.relationshipsEach model(...) is also a ModelDefinition with .toTableSchema() (the
serialized table) and .toTsType() (a generated TS interface string).
API
Single entry point (.). The package re-exports everything under properties,
schema, types, and utils.
Definition entry points
| Export | Kind | Summary |
| ---------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| model(tableName, properties, options?) | function | Define a table. Returns a ModelDefinition. |
| ModelDefinition | class | A model: holds properties, fluent .indexes() / .constrain() / .timestamps() / .softDelete(), and .toTableSchema() / .toTsType(). |
| columns | object | The builder factory — one method per column type plus belongsTo/hasMany/hasOne/indexes/constrains. |
| toModuleSchema(name, models, options?) | function | Group models into a ModuleSchema, hoisting relations. |
Column builders (columns.* and classes)
| Export | Kind | Summary |
| ------------------------------------------------------------------------------------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| ColumnBuilder | class | Base builder: .primaryKey(), .nullable(), .unique(), .default(), .defaultRaw(), .array(), .fieldName(), .toSchema(), .toTsType(). |
| IdColumnBuilder | class | columns.id({prefix}) — text PK with generate_id('<prefix>') default. |
| BooleanColumnBuilder | class | columns.boolean(). |
| IntegerColumnBuilder | class | columns.integer() → .bigInt() / .smallInt() / .serial() / .bigSerial() / .smallSerial(). |
| NumericColumnBuilder | class | columns.numeric(p?, s?) with .precision(), .scale(), and codegen-only .representation("number" | "string"). |
| RealColumnBuilder, DoublePrecisionColumnBuilder, MoneyColumnBuilder | class | columns.real(), columns.doublePrecision(), columns.money(). |
| TextColumnBuilder, CharacterVaryingColumnBuilder, CharacterColumnBuilder | class | columns.text(), columns.varchar(n?), columns.char(n?). |
| TimestampColumnBuilder, DateColumnBuilder, TimeColumnBuilder, IntervalColumnBuilder | class | columns.timestamp({withTimezone?}), columns.date(), columns.time(), columns.interval(). |
| JsonColumnBuilder | class | columns.json({binary?}) / columns.jsonb(). |
| UuidColumnBuilder | class | columns.uuid() with .defaultGenerate(). |
| ByteaColumnBuilder | class | columns.bytea(). |
| EnumColumnBuilder | class | columns.enum(EnumBuilder). |
| VectorColumnBuilder / HalfVectorColumnBuilder | class | columns.vector(dims) / columns.halfVector(dims) — native VECTOR(dims) / HALFVEC(dims) values represented as number[]. |
Enums, indexes, constraints
| Export | Kind | Summary |
| ---------------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| EnumBuilder | class | Named PG enum. .name(), .toSchema(), .toTsTypeName(), .toTsTypeDeclaration(). |
| IndexBuilder / indexBuilder(name) | class/function | Index: .columns() (named or SQL expression), .unique(), .type(), .where(), .with(), .concurrently(). |
| ConstraintBuilder / constrainBuilder(name) | class/function | Table constraint: .columns(), .unique(), .primaryKey(), .check(), .exclude(), .indexType(), .where(), .deferrable(). |
Relations
| Export | Kind | Summary |
| ------------------------------------------------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| BelongsTo / BelongsToBuilder / belongsTo(target, opts?) | class/function | Owning side; creates the FK column(s). .link(), .onDelete(), .onUpdate(), .nullable(), .unique(), .indexed(), .deferrable(), .match(), .constraint(). |
| HasMany / HasManyBuilder / hasMany(target, opts?) | class/function | Inverse 1:N; no DB artifact. .mappedBy(). |
| HasOne / HasOneBuilder / hasOne(target, opts?) | class/function | Inverse 1:1; no DB artifact. .mappedBy(). |
| Relation | class | Abstract base for the three relation builders. |
| ModelTarget / LazyModel | type | A relation target: ModelDefinition | () => ModelDefinition | string table name. |
Relation validation
| Export | Kind | Summary |
| -------------------------------------------------------------------- | -------- | --------------------------------------------------------------------- |
| validateRelations(models) | function | Cross-check live ModelDefinitions; returns { valid, violations }. |
| assertValidRelations(models) | function | Throws RelationValidationError listing all violations. |
| validateRelationSchemas(rels) / assertValidRelationSchemas(rels) | function | Same, but against a serialized RelationSchema[]. |
| RelationValidationError | class | Aggregated error carrying violations + a formatted message. |
| ValidationResult, RelationViolation, ViolationKind | type | Validation result shapes. |
Utilities & re-exports
| Export | Kind | Summary |
| ----------------------------------------------------------- | -------- | ------------------------------------------------------------------------------- |
| toPascalCase, toCamelCase, toEnumTypeName | function | String-case helpers used by codegen/type emission. |
| pgTypeToTsBase, enumTypeToTsBase | function | Map a ColumnType / enum values to a TypeScript type string. |
| cleanupIndexSchema | function | Normalise a user index into an IndexSchema (auto-name, column normalisation). |
| assertVectorValue, assertColumnVectorValue, isVectorColumn | functions | Shared finite-number and exact-dimension validation for native vector/halfvec values. |
| registerModel, getRegisteredModel, hasRegisteredModel | function | The global table-name → model registry that backs string relation targets. |
| resolveModuleTarget, removeLastS | function | Target resolution + table→singular helper. |
| PropertyValue, ModelProperties | type | The allowed property value union and the model property map. |
Everything from @damatjs/orm-type (e.g. ColumnType, TableSchema,
ModuleSchema, RelationSchema) is re-exported from this package's root, so
model code rarely needs to import @damatjs/orm-type directly.
Models include timestamps and soft delete unless explicitly disabled with
.timestamps(false) or .softDelete(false). Numeric representation defaults to
the existing generated number; "string" emits lossless row/input strings and
finite decimal-string Zod validation without producing a migration diff.
Note: the package's
exportsmap only has.. There is nocodegensubpath export. Use@damatjs/schema-codegenfor completeModuleSchemato TypeScript/Zod source generation; row-type emission from this package itself is limited toModelDefinition.toTsType().
How it fits
Runtime dependencies (package.json):
@damatjs/orm-type— shared schema/query types (re-exported here).@damatjs/deps— bundled third-party deps.
Notable in-repo dependents:
@damatjs/orm-core— registersModelDefinitions.@damatjs/orm-pg— builds queries fromModelDefinitionand relation builders.@damatjs/orm-processor,@damatjs/orm-migration,@damatjs/schema-codegen,@damatjs/module-generator,@damatjs/orm-cli,@damatjs/orm-main.@damatjs/module,@damatjs/service.
Documentation
- Internals — architecture, module map, and split deep-dives (column builders, relations, indexes/constraints, schema/model, type inference).
- Full guide — the Damat monorepo guide.
License
MIT
