inline-postgres-impl 0.1.0

Implementation of the inline-postgres crate - do not use on its own
Documentation
use tokio_postgres::{types, Client};
use tokio_postgres as  postgres;

#[derive(Clone)]
pub struct MigrationAction<'a> {
    pub code: &'static str,
    pub vals: &'a [&'a (dyn types::ToSql + Sync)],
}

impl<'a> MigrationAction<'a> {
    pub const fn new(code: &'static str, vals: &'a [&'a (dyn types::ToSql + Sync)]) -> Self {
        Self { code, vals }
    }
}

#[derive(Clone)]
pub struct Migration<'a> {
    pub name: &'a str,
    pub actions: &'a [MigrationAction<'a>],
}

#[derive(Clone)]
pub struct Schema<'a> {
    pub versions: &'a [Migration<'a>],
}

impl<'a> Schema<'a> {
    pub async fn migrate(&self, client: &mut Client) -> Result<(), postgres::Error> {
        let transaction = client.transaction().await?;

        transaction
            .execute("create table if not exists __paaradox_meta__(key varchar(1000) primary key, val varchar(1000))", &[])
            .await?;
        let version = transaction
            .query("select val from __paaradox_meta__ where key='version'", &[])
            .await?
            .into_iter()
            .map(|r| r.get::<usize, String>(0))
            .next();

        if version.is_none() {
            transaction
                .execute("insert into __paaradox_meta__(key, val) values('version', '--------------- dummy ----------')", &[])
                .await?;
        }

        let needed_migrations: Vec<Migration<'a>> = if let Some(version) = version {
            let mut migration_queue = vec![];
            let mut migrate = false;
            for migration in self.versions.iter() {
                if migrate {
                    migration_queue.push(migration.clone());
                }
                if migration.name == version {
                    migrate = true;
                }
            }
            migration_queue
        } else {
            self.versions.iter().cloned().collect()
        };

        for migration in needed_migrations.into_iter() {
            for action in migration.actions.iter() {
                transaction.execute(action.code, action.vals).await?;
            }
            transaction.execute(
                "update __paaradox_meta__ set val = $1 where key = 'version'",
                &[&migration.name],
            ).await?;
        }

        transaction.commit().await
    }
}