Schema

DDL emission

Preview deterministic SQL from a migration plan without confusing preview policy with a sealed executable program.

The @qubu/migrate/ddl entrypoint accepts only a MigrationPlan and a SchemaDialect. It does not read a catalog, open a connection, start a transaction, or write a migration journal. Preflight runs before rendering, so a blocked or incompatible plan returns diagnostics and no SQL.

import { emitMigrationPlan } from "@qubu/migrate/ddl"
import { postgresSchemaDialect } from "qubu/snapshot/postgres"

const result = emitMigrationPlan(plan, postgresSchemaDialect)
if (!result.ok) {
  // Review result.diagnostics. result.sql is an empty string.
  throw new Error(result.diagnostics.map((item) => item.message).join("\n"))
}

for (const statement of result.statements) {
  console.log(statement.operationId, statement.sql, statement.parameters)
}

statements is a deterministic preview surface. Each statement carries its operation ID, topological position, SQL text, and an ordered parameter list. Schema literals and expressions are parameter-free by contract. sql joins the statements with a newline and adds a semicolon for migration-file writers.

Review gates

The emitter rejects a plan with ready: false, decision-required operations, unknown or lossy facts, unsupported safety, or destructive changes unless the caller supplies the matching explicit option. allowUnsafe is available for preview integrations, but it is not accepted as an artifact approval and does not make an opaque object renderable. Opaque and deferred catalog records need an explicit tagged custom-sql operation for preview and an operation-scoped custom program for sealed execution.

Lock and transaction requirements describe what a later executor must provide. Pass lock or transaction to preflight those requirements against the executor's context. A required transaction with transaction: 'autocommit' produces transaction-conflict; no transaction is opened by the emitter.

const result = emitMigrationPlan(plan, postgresSchemaDialect, {
  transaction: "managed",
  lock: "exclusive",
  serverVersion: "16",
})

First-party support

Object or operation PostgreSQL SQLite MySQL
Tables, columns, constraints, indexes yes tables, columns, and indexes; constraints require an inline/rebuild path yes
Views yes yes yes
Materialized views yes no no
Sequences, enums, domains, policies, extensions yes no no
Routines functions and procedures no functions and procedures
Partitions yes no add/drop partition forms
Triggers yes yes yes
Comments and ownership yes no table comments only
Explicit custom SQL dialect tag must match dialect tag must match dialect tag must match

The support table describes syntax Qubu can render from modeled snapshot facts. Server-version checks still apply, such as SQLite column rename and drop-column limits and MySQL check-constraint support. An unsupported operation is reported as a diagnostic rather than silently omitted. SQLite table constraints are not emitted as ALTER TABLE ... ADD CONSTRAINT; use a schema snapshot that carries an inline constraint declaration or an explicit rebuild/custom-SQL operation.

Custom SQL stays opaque and appears at its plan position. The emitter does not inspect it for object names or infer SQL from an opaque catalog record.

For execution, lower the plan with compileMigrationProgram() from @qubu/migrate/artifact. The versioned program—not the aggregate sql string—is authoritative. See Artifacts and approval policy.