extern crate schemamama;
extern crate postgres;
use schemamama::{Adapter, Migration, Version};
use std::collections::BTreeSet;
pub trait PostgresMigration : Migration {
#[allow(unused_variables)]
fn up(&self, transaction: &postgres::Transaction) { }
#[allow(unused_variables)]
fn down(&self, transaction: &postgres::Transaction) { }
}
pub struct PostgresAdapter<'a> {
connection: &'a postgres::Connection
}
impl<'a> PostgresAdapter<'a> {
pub fn new(connection: &'a postgres::Connection) -> PostgresAdapter {
PostgresAdapter { connection: connection }
}
pub fn setup_schema(&self) {
let query = "CREATE TABLE IF NOT EXISTS schemamama (version BIGINT PRIMARY KEY);";
if let Err(e) = self.connection.execute(query, &[]) {
panic!("Schema setup failed: {:?}", e);
}
}
fn record_version(&self, version: Version) {
let query = "INSERT INTO schemamama (version) VALUES ($1);";
if let Err(e) = self.connection.execute(query, &[&version]) {
panic!("Failed to delete version {:?}: {:?}", version, e);
}
}
fn erase_version(&self, version: Version) {
let query = "DELETE FROM schemamama WHERE version = $1;";
if let Err(e) = self.connection.execute(query, &[&version]) {
panic!("Failed to delete version {:?}: {:?}", version, e);
}
}
fn execute_transaction<F>(&self, block: F) where F: Fn(&postgres::Transaction) {
let transaction = self.connection.transaction().unwrap();
block(&transaction);
transaction.commit().unwrap();
}
}
impl<'a> Adapter for PostgresAdapter<'a> {
type MigrationType = PostgresMigration;
fn current_version(&self) -> Option<Version> {
let query = "SELECT version FROM schemamama ORDER BY version DESC LIMIT 1;";
let statement = match self.connection.prepare(query) {
Ok(s) => s,
Err(e) => panic!("Schema query preperation failed: {:?}", e)
};
let row = match statement.query(&[]) {
Ok(r) => r,
Err(e) => panic!("Schema query failed: {:?}", e)
};
row.iter().next().map(|r| r.get(0))
}
fn migrated_versions(&self) -> BTreeSet<Version> {
let query = "SELECT version FROM schemamama;";
let statement = match self.connection.prepare(query) {
Ok(s) => s,
Err(e) => panic!("Schema query preperation failed: {:?}", e)
};
let row = match statement.query(&[]) {
Ok(r) => r,
Err(e) => panic!("Schema query failed: {:?}", e)
};
row.iter().map(|r| r.get(0)).collect()
}
fn apply_migration(&self, migration: &PostgresMigration) {
self.execute_transaction(|transaction| {
migration.up(&transaction);
self.record_version(migration.version());
});
}
fn revert_migration(&self, migration: &PostgresMigration) {
self.execute_transaction(|transaction| {
migration.down(&transaction);
self.erase_version(migration.version());
});
}
}