inline_postgres_impl/
schema.rs

1use tokio_postgres::{types, Client};
2use tokio_postgres as  postgres;
3
4#[derive(Clone)]
5pub struct MigrationAction<'a> {
6    pub code: &'static str,
7    pub vals: &'a [&'a (dyn types::ToSql + Sync)],
8}
9
10impl<'a> MigrationAction<'a> {
11    pub const fn new(code: &'static str, vals: &'a [&'a (dyn types::ToSql + Sync)]) -> Self {
12        Self { code, vals }
13    }
14}
15
16#[derive(Clone)]
17pub struct Migration<'a> {
18    pub name: &'a str,
19    pub actions: &'a [MigrationAction<'a>],
20}
21
22#[derive(Clone)]
23pub struct Schema<'a> {
24    pub versions: &'a [Migration<'a>],
25}
26
27impl<'a> Schema<'a> {
28    pub async fn migrate(&self, client: &mut Client) -> Result<(), postgres::Error> {
29        let transaction = client.transaction().await?;
30
31        transaction
32            .execute("create table if not exists __paaradox_meta__(key varchar(1000) primary key, val varchar(1000))", &[])
33            .await?;
34        let version = transaction
35            .query("select val from __paaradox_meta__ where key='version'", &[])
36            .await?
37            .into_iter()
38            .map(|r| r.get::<usize, String>(0))
39            .next();
40
41        if version.is_none() {
42            transaction
43                .execute("insert into __paaradox_meta__(key, val) values('version', '--------------- dummy ----------')", &[])
44                .await?;
45        }
46
47        let needed_migrations: Vec<Migration<'a>> = if let Some(version) = version {
48            let mut migration_queue = vec![];
49            let mut migrate = false;
50            for migration in self.versions.iter() {
51                if migrate {
52                    migration_queue.push(migration.clone());
53                }
54                if migration.name == version {
55                    migrate = true;
56                }
57            }
58            migration_queue
59        } else {
60            self.versions.iter().cloned().collect()
61        };
62
63        for migration in needed_migrations.into_iter() {
64            for action in migration.actions.iter() {
65                transaction.execute(action.code, action.vals).await?;
66            }
67            transaction.execute(
68                "update __paaradox_meta__ set val = $1 where key = 'version'",
69                &[&migration.name],
70            ).await?;
71        }
72
73        transaction.commit().await
74    }
75}