refrakt/migrate

Migration runner for Refrakt applications.

Reads SQL files from a migrations directory, tracks applied migrations in a _migrations table, and runs pending ones in order. Each migration runs in its own transaction together with its _migrations row, so a failing migration leaves no partial schema changes and is not recorded.

Usage from CLI

refrakt migrate

The CLI generates src/<app>/migrate.gleam, which connects to the database and calls run with two small callbacks.

Usage from code

import refrakt/migrate

migrate.run(
  "src/my_app/data/migrations",
  query: query_strings,
  transaction: transaction,
)

Types

A migration file with its number and name.

pub type Migration {
  Migration(
    number: Int,
    name: String,
    filename: String,
    sql: String,
  )
}

Constructors

  • Migration(
      number: Int,
      name: String,
      filename: String,
      sql: String,
    )

Values

pub fn run(
  in migrations_dir: String,
  query query_strings: fn(String) -> Result(List(String), String),
  transaction transaction: fn(List(String)) -> Result(Nil, String),
) -> Result(Int, String)

Run all pending migrations in a directory. Returns the number of migrations applied.

  • query runs a SELECT and returns the first column of every row.
  • transaction runs SQL scripts in order inside one transaction: it commits when all of them succeed and rolls back otherwise. Each script may hold several statements. On Postgres, split them with split_statements first, since a Postgres query runs one statement.

Each migration file and the INSERT into _migrations that records it go through one transaction call. Migrations stop at the first failure, and the error names the failing file.

pub fn run_from_directory(
  db_execute: fn(String) -> Result(Nil, String),
  db_query_strings: fn(String) -> Result(List(String), String),
  migrations_dir: String,
) -> Result(Int, String)

Deprecated: Use `run`, which applies each migration in a transaction. Delete src/<app>/migrate.gleam and run `refrakt migrate` to regenerate it.

Run all pending migrations in a directory, one SQL string per file, without a transaction. Returns the number of migrations applied.

pub fn split_statements(sql: String) -> List(String)

Split a SQL script into its statements, for databases that run one statement per query (Postgres through pog).

Splits on ; but not inside single-quoted strings (including E'...' with backslash escapes), double-quoted identifiers, -- and /* */ comments, dollar-quoted bodies ($$ ... $$, $tag$ ... $tag$), or BEGIN ATOMIC ... END function bodies. Statements are trimmed and lose their terminating ;. Empty statements and statements holding only comments are dropped.

split_statements("CREATE TABLE a (id INT); CREATE INDEX a_id ON a (id);")
// -> ["CREATE TABLE a (id INT)", "CREATE INDEX a_id ON a (id)"]
✨ Search Document