Lifecycle Directives
Lifecycle directives live inside { } blocks. They communicate intent to the compiler for operations that cannot be expressed as a simple CREATE or ALTER.
RENAMED FROM — object renames
Schema rename
SCHEMA reporting {
RENAMED FROM old_reporting;
}
-- emits
ALTER SCHEMA "old_reporting" RENAME TO "reporting";
Table rename
TABLE user_accounts ( ... )
{
RENAMED FROM users;
}
-- emits
ALTER TABLE "public"."users" RENAME TO "user_accounts";
Column rename
The new name goes in both the ( ) list and the COLUMN block. The old name appears only in RENAMED FROM.
TABLE users (
email_address TEXT NOT NULL,
CONSTRAINT uq_users_email UNIQUE (email_address) -- use new name
)
{
COLUMN email_address {
RENAMED FROM email;
}
}
-- emits
ALTER TABLE "public"."users" RENAME COLUMN "email" TO "email_address";
Compiler algorithm:
- Sees
email_addressin( )andRENAMED FROM emailin theCOLUMNblock. - Looks up
emailin the snapshot. Ifemailexists andemail_addressdoes not → rename. - Emits
ALTER TABLE RENAME COLUMN. - Validates all index and constraint references use the new name — errors on mismatch.
- If
emaildoes not exist in the snapshot → compiler error. RemoveRENAMED FROMfor genuinely new columns.
After the migration: remove RENAMED FROM from source. It applies only to the single migration cycle where the rename occurs.
DEPRECATED
Marks an object as deprecated. The linter warns at compile time. The compiler stores the message as a COMMENT ON prefixed with [DEPRECATED].
TABLE legacy_sessions ( ... )
{
DEPRECATED "Use the sessions table instead. Remove after 2026-01-01.";
}
-- emits
COMMENT ON TABLE "public"."legacy_sessions"
IS '[DEPRECATED] Use the sessions table instead. Remove after 2026-01-01.';
TABLE users ( ... )
{
COLUMN old_username {
DEPRECATED "Use email field instead.";
}
}
-- emits
COMMENT ON COLUMN "public"."users"."old_username"
IS '[DEPRECATED] Use email field instead.';
Applies to: tables, columns, views, functions.
PROTECTED
Prevents the compiler from emitting DROP for this object even if it is removed from source.
TABLE audit_trail ( ... )
{
PROTECTED;
}
-- emits nothing on removal
-- (compiler errors if audit_trail is removed from source while PROTECTED is set)
Applies to: tables. To drop a protected table, remove PROTECTED first and apply, then remove the table declaration and apply again.
DROP CASCADE
Overrides the global default_drop_behavior for a specific object. When the object is removed from source, DROP ... CASCADE is emitted instead of DROP ... RESTRICT.
TABLE scratch_data ( ... )
{
DROP CASCADE;
}
-- emits when scratch_data is removed from source (DESTRUCTIVE)
DROP TABLE "public"."scratch_data" CASCADE;
MIGRATE REMOVE — ENUM value removal
PostgreSQL has no ALTER TYPE DROP VALUE. DPG triggers a safe six-step migration. See ENUM for the complete procedure and output.
TYPE order_status AS ENUM ('pending', 'confirmed', 'shipped', 'delivered') {
MIGRATE REMOVE ('cancelled') {
UPDATE orders SET status = 'delivered' WHERE status = 'cancelled';
}
}
After the migration: remove the MIGRATE REMOVE block from source.
NOT VALID — deferred constraint validation
NOT VALID is a PostgreSQL option tracked across migrations. See Constraints for the full DPG→SQL pair.
-- Migration 1: add without scanning rows
TABLE orders ( ... )
{ CONSTRAINT ck_amount_positive CHECK (amount > 0) NOT VALID; }
-- emits
ALTER TABLE "public"."orders"
ADD CONSTRAINT "ck_amount_positive" CHECK (amount > 0) NOT VALID;
-- Migration 2: validate (remove NOT VALID)
TABLE orders ( ... )
{ CONSTRAINT ck_amount_positive CHECK (amount > 0); }
-- emits
ALTER TABLE "public"."orders" VALIDATE CONSTRAINT "ck_amount_positive";