Crate promad

source ·
Expand description

Promad

Promad logo

Migration tool for SQLx that allows for arbitrary SQL/Rust execution within a transaction on the write connection.

Features

  • Rust code mixed with SQL in migrations.
  • Scan migrations across a table with blob data using Rust.
  • Embeddable CLI.

Example

use std::borrow::Cow;
use async_trait::async_trait;
use promad::{file_basename, Migration, Migrator, error::{Error, Result}};
use sqlx::{postgres::PgPoolOptions, PgPool, Postgres, Executor, Row};
use testcontainers::{clients, Container};

pub struct FirstMigration;

#[async_trait]
impl Migration<Postgres> for FirstMigration {
    fn name(&self) -> &'static str {
        file_basename!()
    }

    async fn up(
        &self,
        _read: &mut sqlx::PgConnection,
        write: &mut sqlx::PgConnection,
    ) -> Result<()> {
        sqlx::query("CREATE TABLE test (id INT PRIMARY KEY)")
            .execute(write)
            .await?;
        Ok(())
    }

    async fn down(
        &self,
        _read: &mut sqlx::PgConnection,
        write: &mut sqlx::PgConnection,
    ) -> Result<()> {
        sqlx::query("DROP TABLE test")
            .execute(write)
            .await?;
        Ok(())
    }
}

let docker = clients::Cli::default();
let pgsql = docker.run(testcontainers::images::postgres::Postgres::default());
let port = pgsql.get_host_port_ipv4(5432);
let pool = PgPoolOptions::new()
    .connect(&format!(
        "postgres://postgres:postgres@localhost:{}/postgres",
        port
    ))
    .await.unwrap();

let mut migrator = Migrator::create(pool.clone());
migrator.add_migration(Box::new(FirstMigration));
migrator.apply_all().await.unwrap();

// Check that the table exists.
let mut conn = pool.acquire().await.unwrap();

let row = sqlx::query("SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'test')")
    .fetch_one(conn.as_mut())
    .await.unwrap();

assert!(row.get::<bool, _>(0));

migrator.revert_all().await.unwrap();

let row = sqlx::query("SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'test')")
    .fetch_one(conn.as_mut())
    .await.unwrap();

assert!(!row.get::<bool, _>(0));

Modules

Macros

Structs

  • Interactive UI that uses indicatif to show pretty progress bars. This also redirects stdout to a buffer so that the progress bars aren’t broken by stdout output. It’s later printed to the screen when migrations are complete.
  • Contains the migrations and logic for managing the migrations table, handling txn, and ensuring integrity of the migrations.
  • Used for representing the status of a migration to the CLI frontend.

Enums

  • Used to indicate whether we’re running the up or down migrations.

Traits

  • Trait representing a migration. Up/Down each get separate connections for read/write. The idea behind this is that users can stream data from the read connection and write it to the write connection. This is useful for migrating data in blob columns whose schemas aren’t managed by SQL.
  • Manage the UI for migrations. This is used to show progress bars and other information to the user.