@damatjs/orm-migration
v1.0.6
Published
Damatjs orm utils definition
Readme
@damatjs/orm-migration
Module-based PostgreSQL migration system: discover, generate, run, and track.
@damatjs/orm-migration is the migration runtime for the Damat ORM. Each application module owns its own migrations/ folder of timestamped .sql files; this package discovers those files, generates new ones from your models (via @damatjs/orm-processor), runs pending migrations transactionally against a pg pool, and records what has been applied in the qualified damat._damat_migration_logs table. It sits between the pure schema engine (processor) and the database, and is driven by the ORM CLI and the framework's module system.
Part of the Damat monorepo · Full guide · Internals
Install
bun add @damatjs/orm-migrationInside this monorepo it is referenced as a workspace dependency with "@damatjs/orm-migration": "*".
When to use
Use this package to:
- Generate a migration for a module from its current models (
createMigration/createInitialMigration/createDiffMigration). - Discover the migration files declared by one or more modules (
discoverModuleMigrations,discoverAllMigrations). - Apply pending migrations transactionally (
runMigrations). - Apply ordered inline system migrations before module migrations.
- Report which migrations are applied vs pending (
getMigrationStatus,getModuleMigrationStatus). - Inspect or maintain the migration log table directly (
MigrationTracker). - Audit and adopt a committed pending non-transactional migration after exact
checksum verification (
damat-orm migrate:adopt).
Do not use it to:
- Compute diffs or emit SQL — that is
@damatjs/orm-processor(this package re-uses it). - Define models — that is
@damatjs/orm-model. - Open or pool connections — you pass an already-created
pgPoolin.
Quick start
import { Pool } from "@damatjs/deps/pg";
import {
collectSystemMigrations,
durabilitySystemMigrations,
} from "@damatjs/durability";
import {
createMigration,
runMigrations,
getMigrationStatus,
} from "@damatjs/orm-migration";
// 1. Generate a migration for the "user" module.
// Initial run → baseline; subsequent runs → diff vs the saved snapshot.
// The second argument is the module's own directory (its resolver), which
// is import()ed for its `models` export.
await createMigration("user", "src/modules/user");
// 2. Apply pending migrations. Pass a pg Pool and a module container.
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const modules = {
user: {
id: "user",
name: "user",
path: "src/modules/user",
resolve: "src/modules/user",
},
};
const systemMigrations = collectSystemMigrations([durabilitySystemMigrations]);
const results = await runMigrations(pool, modules, {
systemMigrations,
});
results.forEach((r) => console.log(r.success, r.applied));
// 3. Check system and module status with the same catalog.
const status = await getMigrationStatus(pool, modules, { systemMigrations });
console.log(status.modules);API
| Export | Kind | Summary |
| ----------------------------------------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------- |
| createMigration(moduleName, modulesDir?, opts?) | function | Auto-picks initial vs diff based on whether a snapshot exists; returns a path or DiffMigrationResult. |
| createInitialMigration(moduleName, moduleResolver, opts?) | function | Baseline migration: full CREATE SQL from all models, saves first snapshot. Returns the file path. |
| createDiffMigration(moduleName, moduleResolver, opts?, layout?) | function | Diff migration vs the saved snapshot; an optional layout selects a separate migrations directory. |
| discoverModuleMigrations(moduleResolver) | function | Scan <resolver>/migrations/ or an explicit resolved migrations directory; returns sorted files. |
| discoverAllMigrations(resolvers[]) | function | Discover across roots or resolved descriptors, sorted by timestamp. |
| discoverModels(moduleResolver, logger?) | function | Load an aggregate models export or scan a models-provider directory. |
| runMigrations(pool, moduleContainer, options?) | function | Run optional system migrations first, then module migrations, under one advisory lock. |
| getMigrationStatus(pool, moduleContainer, options?) | function | Applied/pending counts for system owners and modules. |
| getModuleMigrationStatus(pool, moduleDescriptor) | function | Same, for one module (throws if it has no migrations). |
| MigrationTracker | class | CRUD over damat._damat_migration_logs (ensureTable, getApplied, recordApplied, recordReverted). |
| bootstrapDatabase(pool) | function | Idempotent DB setup: pgcrypto + generate_id(prefix) function. |
| log, separator, successBanner, errorBanner | functions | Migration logging helpers (re-exported from @damatjs/logger). |
| MigrationTracker, AppliedMigration | class / type | The tracker and its applied-row type. |
| runSystemMigrations, getSystemMigrationStatus | functions | Execute and inspect ordered inline system migrations through the shared tracker. |
MigrationInfo, ModuleMigrationResult, ModuleMigrationStatus, MigrationStatus, and DatabaseConfig are internal types: they describe the shapes returned by the functions above (so you get them through inference) but are not re-exported as named types from the package root. executeMigration is likewise internal — runMigrations is the entry point for applying migrations.
createMigration and both direct builders take the module's own model resolver,
not the parent modules directory. createDiffMigration additionally accepts
{ migrationsDir } as its fourth argument when manifest-declared models and
migrations live in separate directories.
The migration role must own or inherit the owner of the damat schema and have
USAGE, CREATE; runtime roles need USAGE plus the required table and sequence
privileges. ensureTable() moves a legacy public tracker transactionally and
reports incompatible schema contents or a conflict if both tracker locations
exist.
Migration SQL, its SHA-256 source checksum, and tracker insertion use one
checked-out client. Transactional tracker failure rolls back the SQL. If
non-transactional SQL commits but tracking fails, execution reports
CommittedMigrationUntrackedError. Recover only after inspection:
damat-orm migrate:adopt <module> <migration> \
--checksum <sha256> --actor <actor> --reason <reason>Generation carries each table's schema through snapshots, diffs, indexes,
constraints, and foreign keys. An explicit generator schema overrides table
schema, then module schema, then public. Unsupported or invalid schema changes
fail before either migration SQL or schema-snapshot.json is written.
Models with native vector/halfvec columns automatically persist a vector
extension requirement and generate CREATE EXTENSION IF NOT EXISTS vector before
dependent tables. Processor statement APIs omit terminators, but generated SQL
files append one semicolon per statement. Native vector type or dimension changes
produce a warning and manual-review comment while still advancing the snapshot.
Subpath exports: none — everything is under ..
How it fits
Depends on:
@damatjs/orm-processor—diffSchemas,generateFromDiff/generateFromSnapshot,loadSnapshot/saveSnapshot,snapshotExist, and the*MigrationOptions/DiffMigrationResulttypes.@damatjs/orm-model—toModuleSchema,ModelDefinition.@damatjs/orm-type—OrmModule/OrmModuleContainer(the module-resolver shape) andPooltyping via@damatjs/deps/pg.@damatjs/logger— colored, structured migration output.@damatjs/deps(pg),@damatjs/types.
Depended on by (in-repo): @damatjs/orm-cli, @damatjs/orm-main, @damatjs/module.
Documentation
License
MIT
