glimr/db/gen/migrate/snapshot

Migration Snapshot

The migration system needs to know what the schema looked like last time to figure out what changed. This module saves the current schema as a JSON snapshot after each migration run, then loads it back on the next run for diffing. Without it, every run would think the entire schema is new and try to CREATE TABLE on tables that already exist.

Types

Stores just enough about a column to detect changes worth migrating: type, nullability, and whether a default exists. The actual default value isn’t stored because changing a default doesn’t require a migration — it only affects new rows, not the table structure.

pub type ColumnSnapshot {
  ColumnSnapshot(
    name: String,
    column_type: String,
    nullable: Bool,
    has_default: Bool,
  )
}

Constructors

  • ColumnSnapshot(
      name: String,
      column_type: String,
      nullable: Bool,
      has_default: Bool,
    )

Captures an index’s state at snapshot time so the next migration run can detect whether indexes were added, removed, or changed. The optional name preserves custom names through the snapshot so they survive across migration generations.

pub type IndexSnapshot {
  IndexSnapshot(
    columns: List(String),
    unique: Bool,
    name: option.Option(String),
  )
}

Constructors

  • IndexSnapshot(
      columns: List(String),
      unique: Bool,
      name: option.Option(String),
    )

The top-level container saved to .glimr_schema_snapshot.json. It’s a dictionary keyed by table name so the diff algorithm can look up any table’s previous state in O(1) instead of scanning a list.

pub type Snapshot {
  Snapshot(tables: dict.Dict(String, TableSnapshot))
}

Constructors

Columns are kept in definition order (not sorted) so the diff can detect position changes if needed in the future. Indexes live alongside columns because they’re part of the same table definition and need to be diffed together.

pub type TableSnapshot {
  TableSnapshot(
    columns: List(ColumnSnapshot),
    indexes: List(IndexSnapshot),
  )
}

Constructors

Values

pub fn build(tables: List(schema_parser.Table)) -> Snapshot

Converts live Table definitions into a snapshot that can be saved to JSON. Strips out information the diff doesn’t need (like the actual default value — only whether one exists matters) to keep the snapshot file small and the diff logic simple.

pub fn column_type_to_string(
  col_type: schema_parser.ColumnType,
) -> String

Column types are stored as strings in the JSON snapshot because Gleam’s custom types can’t be directly serialized. The string format is stable across versions — changing it would make every existing snapshot look like a type change, generating spurious ALTER COLUMN migrations.

pub fn load(path: String) -> Snapshot

Reads the snapshot file from disk. Returns an empty snapshot if the file doesn’t exist (first run) or can’t be parsed (corrupted file). Falling back to empty means the differ will treat every table as new and generate full CREATE TABLE statements — which is the right thing on a fresh project.

pub fn merge(old: Snapshot, new: Snapshot) -> Snapshot

When generating a migration for just one model, we only have a snapshot of that model’s tables. Without merging, saving would wipe out all other tables from the snapshot file, and the next full run would think those tables are new. This overlays the filtered snapshot onto the existing one so unrelated tables are preserved.

pub fn save(path: String, snapshot: Snapshot) -> Result(Nil, Nil)

Writes the snapshot to disk after migration generation. The JSON is human-readable (indented, one column per line) so developers can inspect it when debugging why a migration was or wasn’t generated. Returns Error only if the file write fails.

Search Document