Sign in

    migrate

    Database migrations for MoonBit with SQLite and PostgreSQL support.

    migration
    sqlite
    postgresql
    Download zip
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    2 days ago
    Downloads
    32

    #migrate

    A database migration library for MoonBit, with SQLite and PostgreSQL support. Write upgrade and downgrade functions to change your database schema or data. The library tracks applied migrations, runs pending ones, and reverts changes when requested.

    #Usage

    Import moonbit-community/migrate as migrate and moonbit-community/sqlite3 as sqlite3 in moon.pkg.

    ///|
    async test "SQLite quick start" {
    let db = @sqlite3.Connection::open_async(":memory:")
    defer db.close()
    let migrator : @migrate.Migrator[@sqlite3.Connection] = @migrate.Migrator({
    "create_users": {
    upgrade: db => {
    let statement = db.prepare_async(
    "CREATE TABLE users(id INTEGER PRIMARY KEY)",
    )
    defer statement.finalize()
    statement.step_async() |> ignore
    },
    downgrade: db => {
    let statement = db.prepare_async("DROP TABLE users")
    defer statement.finalize()
    statement.step_async() |> ignore
    },
    },
    })
    migrator.run(db)
    assert_eq(
    @migrate.Migrate::list_migrations(db, table="_moonbit_migrations"),
    ["create_users"],
    )
    migrator.revert(db)
    assert_eq(
    @migrate.Migrate::list_migrations(db, table="_moonbit_migrations"),
    [],
    )
    }

    Map keys are migration IDs. Migrations run in map insertion order. Use Migrator(migrations, table="app_migrations") to choose a migrations table. The default is _moonbit_migrations. The name is a single table identifier.

    run(db) applies pending migrations. revert(db, version="id") reverses later migrations and keeps the target applied. Omit version to revert everything. An optional value can be forwarded with revert(db, version?), where None also means revert everything. An empty string is an ordinary ID.

    Callbacks return Unit. Errors stop execution without updating that step's applied state. A migrator snapshots its definitions and can be reused with other database handles of the same type.

    #Migration history

    The library maintains a migrations table containing only currently applied migrations, in execution order. Successful upgrades append records, and successful downgrades remove them.

    Applied migrations must remain an unchanged prefix of your definitions. Do not delete, rename, reorder, or edit them. Reverted migrations can be replaced or removed once no other database still has them applied. Keeping them in the map makes the next run apply them again. Validation checks IDs and order.

    The caller manages transactions and locks. Run callbacks and bookkeeping in the same transaction, and serialize migration runs.

    #Testing

    moon test --target native sh scripts/test-postgres.sh

    The first command runs core, SQLite, and example tests. PostgreSQL tests require MIGRATOR_POSTGRES_TEST_PORT. The script starts a disposable PostgreSQL container, runs the full suite, and removes the container. Pass wasm to test that target.

    CI checks formatting, interfaces, and both targets with SQLite and PostgreSQL. To publish, update the version in moon.mod and run publish-package on main. It runs the checks, publishes using MOONCAKES_MOONBIT_COMMUNITY_TOKEN, and tags the published commit with v<version>.

    Migrate

    pub(open) trait Migrate {
    async fn ensure_migration_table(Self, table~ : String) -> Unit
    async fn list_migrations(Self, table~ : String) -> Array[String]
    async fn record_migration(Self, String, Bool, table~ : String) -> Unit
    }

    Database operations used by the migrator.

    Ensure storage exists before listing or recording migrations. The migrator calls ensure_migration_table at the start of each valid-target run.

    Only applied migrations are stored, in execution order. Recording true appends an ID, and false deletes it after a successful downgrade. Operations receive the same table name, which adapters treat as a single identifier.

    Callers must serialize migration runs. To make callbacks and their records atomic, run the migrator on the same connection inside a caller-owned transaction. This trait does not start transactions or acquire locks.
    impl Migrate for Client

    MigrationError

    pub(all) suberror MigrationError {
    MissingMigration(String)
    HistoryMismatch(String, String)
    UnknownVersion(String)
    TargetNotApplied(String)
    } derive(Eq,
    Debug
    )

    Invalid migration history or downgrade targets. Database errors and errors raised by callbacks propagate to the caller.

    MigrationError::equal

    MigrationError::not_equal

    fn MigrationError::not_equal(x : MigrationError, y : MigrationError) -> Bool

    Migration

    pub(all) struct Migration[T] {
    upgrade : async (T) -> Unit
    downgrade : async (T) -> Unit
    }

    A migration's two callbacks. Normal completion indicates success. Raised errors stop the run and propagate without marking success. The ID and execution order are supplied by the constructor's Map.

    Migrator

    type Migrator[T]

    A snapshot of a migration map's insertion order and callbacks. Database handles are supplied separately for each migration run.

    Migrator::Migrator

    fn[T] Migrator::Migrator(migrations : Map[String, Migration[T]], table? : String) -> Migrator[T]

    Construct a migrator. Later mutations of the input map do not change it. IDs are opaque strings, including the empty string. table selects the migrations table, not the tables changed by callbacks.

    Migrator::revert

    async fn[T : Migrate] Migrator::revert(self : Migrator[T], db : T, version? : String) -> Unit

    Revert applied migrations after the target ID, in reverse insertion order. The target remains applied. Omit version or pass None to revert everything. An unknown or currently unapplied target is rejected before callbacks or changes to migration records. The adapter may initialize an empty table.

    Migrator::run

    async fn[T : Migrate] Migrator::run(self : Migrator[T], db : T) -> Unit

    Validate applied history and apply all pending migrations in map insertion order. Already applied migrations are skipped.

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io