schemamama_postgres/
lib.rs1extern crate schemamama;
2extern crate postgres;
3
4use postgres::error::Error as PostgresError;
5use postgres::{Client, Transaction};
6use schemamama::{Adapter, Migration, Version};
7use std::cell::RefCell;
8use std::collections::BTreeSet;
9use std::rc::Rc;
10
11pub trait PostgresMigration : Migration {
13 #[allow(unused_variables)]
16 fn up(&self, transaction: &mut Transaction) -> Result<(), PostgresError> {
17 Ok(())
18 }
19
20 #[allow(unused_variables)]
23 fn down(&self, transaction: &mut Transaction) -> Result<(), PostgresError> {
24 Ok(())
25 }
26}
27
28pub struct PostgresAdapter<'a> {
30 client: Rc<RefCell<&'a mut Client>>,
31 metadata_table: String,
32}
33
34impl<'a> PostgresAdapter<'a> {
35 pub fn new(client: &'a mut Client) -> PostgresAdapter<'a> {
37 PostgresAdapter {
38 client: Rc::new(RefCell::new(client)),
39 metadata_table: "schemamama".into()
40 }
41 }
42
43 pub fn set_metadata_table<S: Into<String>>(&mut self, metadata_table: S) {
46 self.metadata_table = metadata_table.into();
47 }
48
49 pub fn setup_schema(&self) -> Result<(), PostgresError> {
52 let query = format!(
53 "CREATE TABLE IF NOT EXISTS {} (version BIGINT PRIMARY KEY);",
54 self.metadata_table,
55 );
56 self.client.borrow_mut().execute(query.as_str(), &[]).map(|_| ())
57 }
58}
59
60impl<'a> Adapter for PostgresAdapter<'a> {
61 type MigrationType = dyn PostgresMigration;
62 type Error = PostgresError;
63
64 fn current_version(&self) -> Result<Option<Version>, PostgresError> {
65 let query = format!(
66 "SELECT version FROM {} ORDER BY version DESC LIMIT 1;",
67 self.metadata_table,
68 );
69 let row = self.client.borrow_mut().query(query.as_str(), &[])?;
70 Ok(row.iter().next().map(|r| r.get(0)))
71 }
72
73 fn migrated_versions(&self) -> Result<BTreeSet<Version>, PostgresError> {
74 let query = format!("SELECT version FROM {};", self.metadata_table);
75 let row = self.client.borrow_mut().query(query.as_str(), &[])?;
76 Ok(row.iter().map(|r| r.get(0)).collect())
77 }
78
79 fn apply_migration(&self, migration: &dyn PostgresMigration) -> Result<(), PostgresError> {
80 let mut client = self.client.borrow_mut();
81 let mut inner_tx = client.transaction()?;
82 migration.up(&mut inner_tx)?;
83 let query = format!("INSERT INTO {} (version) VALUES ($1);", self.metadata_table);
84 inner_tx.execute(query.as_str(), &[&migration.version()]).map(|_| ())?;
85 inner_tx.commit()?;
86 Ok(())
87 }
88
89 fn revert_migration(&self, migration: &dyn PostgresMigration) -> Result<(), PostgresError> {
90 let mut client = self.client.borrow_mut();
91 let mut inner_tx = client.transaction()?;
92 migration.down(&mut inner_tx)?;
93 let query = format!("DELETE FROM {} WHERE version = $1;", self.metadata_table);
94 inner_tx.execute(query.as_str(), &[&migration.version()]).map(|_| ())?;
95 inner_tx.commit()?;
96 Ok(())
97 }
98}