inline_postgres_impl/
schema.rs1use 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}