use anyhow::Result;
use rusqlite::{Connection, OptionalExtension};
use tracing::*;
pub trait Migration: Sync {
fn run(&self, connection: &Connection) -> Result<()>;
}
impl Migration for &str {
fn run(&self, connection: &Connection) -> Result<()> {
connection.execute_batch(self)?;
Ok(())
}
}
pub static MIGRATIONS: &[&dyn Migration] = &[&include_str!("migrations/v1.sql")];
fn migration_version(connection: &Connection) -> Result<u64> {
let result = connection
.query_row(
"SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?",
("migrations",),
|_row| Ok(()),
)
.optional()?;
if result.is_none() {
return Ok(0);
}
let result = connection.query_row("SELECT MAX(version) FROM migrations", (), |row| {
row.get::<_, u64>(0)
})?;
Ok(result)
}
pub fn migrate(connection: &Connection) -> Result<()> {
connection.pragma_update(None, "optimize", "0x10002")?;
let version = migration_version(connection)? as usize;
for migration in &MIGRATIONS[version..] {
info!("Running migration");
migration.run(connection)?;
connection.pragma_update(None, "optimize", "")?;
}
Ok(())
}
#[test]
fn migrate_once() {
let connection = Connection::open_in_memory().unwrap();
super::functions::register_all(&connection).unwrap();
migrate(&connection).unwrap();
}
#[test]
fn migrate_twice() {
let connection = Connection::open_in_memory().unwrap();
super::functions::register_all(&connection).unwrap();
migrate(&connection).unwrap();
migrate(&connection).unwrap();
}