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
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.
queryruns aSELECTand returns the first column of every row.transactionruns 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 withsplit_statementsfirst, 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)"]