Skip to main content

MigrationAction

Enum MigrationAction 

Source
#[non_exhaustive]
pub enum MigrationAction {
Show 16 variants CreateTable { table: TableName, columns: Vec<ColumnDef>, constraints: Vec<TableConstraint>, }, DeleteTable { table: TableName, }, AddColumn { table: TableName, column: Box<ColumnDef>, fill_with: Option<String>, }, RenameColumn { table: TableName, from: ColumnName, to: ColumnName, }, DeleteColumn { table: TableName, column: ColumnName, }, ModifyColumnType { table: TableName, column: ColumnName, new_type: ColumnType, fill_with: Option<BTreeMap<String, String>>, narrowing_strategy: Option<NarrowingStrategy>, timezone: Option<String>, }, ModifyColumnNullable { table: TableName, column: ColumnName, nullable: bool, fill_with: Option<String>, delete_null_rows: Option<bool>, }, ModifyColumnDefault { table: TableName, column: ColumnName, new_default: Option<String>, backfill: Option<String>, }, ModifyColumnComment { table: TableName, column: ColumnName, new_comment: Option<String>, }, AddConstraint { table: TableName, constraint: TableConstraint, }, RemoveConstraint { table: TableName, constraint: TableConstraint, }, ReplaceConstraint { table: TableName, from: TableConstraint, to: TableConstraint, }, RemapEnumValues { table: TableName, column: ColumnName, mapping: BTreeMap<i64, i64>, }, RenameTable { from: TableName, to: TableName, }, RawSql { sql: String, }, DataMigration { sql: DataMigrationSql, description: Option<String>, },
}
Expand description

A single schema change produced by the planner and consumed by the SQL generator.

The planner emits a Vec<MigrationAction> when diffing two schemas. The SQL generator (vespertide-query) translates each action into backend-specific DDL statements.

Prefer typed actions over MigrationAction::RawSql. Raw SQL is an emergency escape hatch: it is not portable across backends and is skipped during baseline replay, which means the planner cannot reason about it. For SQL that only changes data, use MigrationAction::DataMigration instead: it is skipped by replay too, but by contract rather than by ignorance.

This enum is #[non_exhaustive]: new variants may be added in future releases. Downstream match expressions should include a wildcard arm.

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

CreateTable

Create a new table with the given columns and constraints (CREATE TABLE).

Fields

§columns: Vec<ColumnDef>
§constraints: Vec<TableConstraint>
§

DeleteTable

Drop an existing table and all its data (DROP TABLE).

Fields

§

AddColumn

Add a new column to an existing table (ALTER TABLE ... ADD COLUMN).

Fields

§column: Box<ColumnDef>
§fill_with: Option<String>

Optional fill value to backfill existing rows when adding NOT NULL without default.

§

RenameColumn

Rename a column in an existing table (ALTER TABLE ... RENAME COLUMN).

§

DeleteColumn

Remove a column from an existing table (ALTER TABLE ... DROP COLUMN).

Fields

§column: ColumnName
§

ModifyColumnType

Change the SQL type of an existing column (ALTER TABLE ... ALTER COLUMN ... TYPE).

Fields

§column: ColumnName
§new_type: ColumnType
§fill_with: Option<BTreeMap<String, String>>

Mapping of removed enum values to replacement values for safe enum value removal. Both sides are bare enum labels — write them exactly as they appear in the enum values list, with no surrounding SQL quotes. The SQL generator binds them as data values and adds the quoting itself. e.g., {"cancelled": "pending"} generates an UPDATE before the type change. A legacy pre-quoted replacement ("'pending'") still works: one outer quote layer is stripped with a warning.

§narrowing_strategy: Option<NarrowingStrategy>

Strategy for transforming existing rows that would violate a narrowed new type (smaller VARCHAR length, lower NUMERIC scale, smaller integer size, etc.) so the ALTER COLUMN TYPE cannot fail. When None, the SQL generator emits a plain ALTER — safe only when the user has independently verified no row violates the new type (typically prompted by the vespertide revision type-narrowing select UI).

§timezone: Option<String>

IANA timezone name (e.g. "Asia/Seoul") or numeric UTC offset (e.g. "+09:00") used when converting between timestamp and timestamptz. Required for safe migration on PostgreSQL where the conversion is non-trivial; ignored on MySQL and SQLite where vespertide maps both timestamp and timestamptz to the same underlying type. Validated by the CLI revision prompt against a 30-name whitelist plus numeric offset format ±HH:MM.

§

ModifyColumnNullable

Change whether a column accepts NULL values.

Fields

§column: ColumnName
§nullable: bool
§fill_with: Option<String>

Required when changing from nullable to non-nullable to backfill existing NULL values.

§delete_null_rows: Option<bool>

When true, rows with NULL values in the column are deleted instead of backfilled. Mutually exclusive with fill_with. Useful for FK columns where a valid fill value may not exist.

§

ModifyColumnDefault

Change or remove the default value of a column.

Fields

§column: ColumnName
§new_default: Option<String>

The new default value, or None to remove the default.

§backfill: Option<String>

F15 fault gate — backfill existing rows.

ALTER TABLE ... SET DEFAULT ... only affects new rows. When the user wants every existing row updated to the new default in the same migration (the common “I want consistency right now” intent), the CLI’s revision prompt captures that choice and stores the desired value here. The SQL generator then emits an UPDATE table SET col = <value> immediately after the ALTER.

None (default, wire-format identical to v0.2.0) → skip the backfill: existing rows keep their current values. The action behaves exactly as before this field existed.

§

ModifyColumnComment

Change or remove the comment on a column.

Fields

§column: ColumnName
§new_comment: Option<String>

The new comment, or None to remove the comment.

§

AddConstraint

Add a constraint (primary key, unique, foreign key, check, or index) to a table.

F2 duplicate-handling strategy lives on the Unique variant of TableConstraint itself (see TableConstraint::Unique.strategy), not here — the strategy is intrinsic to a particular unique constraint, regardless of whether it is added, replaced, or shipped inside a CreateTable.

Fields

§constraint: TableConstraint
§

RemoveConstraint

Remove a constraint from a table.

Fields

§constraint: TableConstraint
§

ReplaceConstraint

Atomically replace one constraint with another (e.g. when columns in a composite key change).

§

RemapEnumValues

Remap stored integer values of an integer-backed enum column.

Emitted when the user changes the value of an existing integer enum variant in the model (e.g. medium: 5 → 10). Because integer enums are stored as plain INTEGER in the database, the DB itself cannot detect the drift; if Vespertide stayed silent the ORM mapping would silently re-interpret existing rows. The SQL generator turns this action into a single atomic UPDATE table SET col = CASE WHEN col = old THEN new ... END WHERE col IN (...) that re-stamps every affected row before the new ORM mapping takes effect.

mapping is a BTreeMap<i64, i64> keyed on the old value, so the type system guarantees a single replacement per source value. Canonical JSON wire format is {"5": 10, "100": 20} (string keys are how JSON represents map keys; serde transparently parses them back to i64). For backward compatibility the legacy array form [[5, 10], [100, 20]] is still accepted on read — see remap_mapping_serde for the details. The map iterates in old_value order at emit time so snapshots stay deterministic. Variants whose name AND value are unchanged are absent; variants added or removed (no name overlap on either side) are also absent — those need a separate migration action.

Fields

§column: ColumnName
§mapping: BTreeMap<i64, i64>
§

RenameTable

Rename a table (ALTER TABLE ... RENAME TO).

Fields

§

RawSql

Execute a raw SQL statement verbatim.

Emergency escape hatch only. Raw SQL is not portable across backends and is invisible to baseline replay, so the planner cannot reason about schema state after this action. Use typed actions whenever possible.

For SQL that changes data only, use MigrationAction::DataMigration instead. Both are skipped by baseline replay, but raw_sql is skipped because its effect is unknown while data_migration is skipped because changing no schema is its enforced contract. Using raw_sql for DDL silently drops that schema change from the reconstructed baseline, after which vespertide diff reports the same already-applied changes forever.

Fields

§

DataMigration

Execute a data-only statement verbatim (UPDATE / INSERT / DELETE / …).

This is the typed home for backfills that the schema-coupled facilities cannot express: conditional updates of existing columns, correlated-subquery backfills, and data reshaping during a format change. Unlike AddColumn.fill_with (which only fires for a newly added NOT NULL column with no default) or ModifyColumnDefault.backfill (one column, one value, every row), data_migration carries an arbitrary DML statement and is not tied to any schema change.

Contract: this action changes no schema. Baseline replay skips it — not because its effect is unknown, as with MigrationAction::RawSql, but because “no schema change” is guaranteed. The guarantee is enforced: a statement whose first token is CREATE, ALTER, DROP, or TRUNCATE is rejected at load and plan time.

The SQL is emitted byte-for-byte as written — no case folding, cast rewriting, or reformatting. Set sql to a single string for portable SQL, or to an object keyed by postgres / mysql / sqlite when the statement cannot be portable. A description is optional but strongly encouraged: it is what vespertide diff shows for this action.

Fields

§sql: DataMigrationSql

The statement(s) to run, emitted verbatim. See DataMigrationSql.

§description: Option<String>

Why this data change exists, shown in vespertide diff output.

Implementations§

Source§

impl MigrationAction

Source

pub fn with_prefix(self, prefix: &str) -> Self

Apply a prefix to all table names in this action.

Source§

impl MigrationAction

Source

pub fn table_name(&self) -> Option<&str>

Returns the primary table this action affects, if any. Returns None for actions that don’t bind to a single table (e.g. RawSql, DataMigration).

Source

pub fn data_migration_ddl_violation(&self) -> Option<(&'static str, &str)>

The DDL keyword this action’s SQL illegally opens with, if any.

Only MigrationAction::DataMigration carries a schema-neutrality contract, so every other variant returns None. Per-backend statements are all checked; the first offender wins.

Trait Implementations§

Source§

impl Clone for MigrationAction

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for MigrationAction

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for MigrationAction

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Display for MigrationAction

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for MigrationAction

Source§

impl JsonSchema for MigrationAction

Source§

fn schema_name() -> Cow<'static, str>

The name of the generated JSON Schema. Read more
Source§

fn schema_id() -> Cow<'static, str>

Returns a string that uniquely identifies the schema produced by this type. Read more
Source§

fn json_schema(generator: &mut SchemaGenerator) -> Schema

Generates a JSON Schema for this type. Read more
Source§

fn inline_schema() -> bool

Whether JSON Schemas generated for this type should be included directly in parent schemas, rather than being re-used where possible using the $ref keyword. Read more
Source§

impl PartialEq for MigrationAction

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Serialize for MigrationAction

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for MigrationAction

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more