Going somewhere.

This commit is contained in:
didier amyot committed 2022-12-05 09:12:49 -05:00
1 parent ded31da7a3
commit fc13cf7f99
6 files changed
+244 -26

No files matched your search

+115 -17
View File
@@ -1,4 +1,13 @@
use rusqlite::Connection;
use rusqlite::{Connection, Transaction};
use sha2::{Digest, Sha256, Sha512};
const INITIAL_MIGRATION: &str = "
CREATE TABLE IF NOT EXISTS shitty_migrations (
id INTEGER PRIMARY KEY,
sha256 BLOB(2)
);
";
const MIGRATION_SCRIPT: &str = "
@@ -20,24 +29,113 @@ CREATE TABLE IF NOT EXISTS securities (
symbol TEXT NOT NULL UNIQUE,
FOREIGN KEY(security_type) REFERENCES security_types(id)
);
CREATE TABLE IF NOT EXISTS account(
id INTEGER PRIMARY KEY AUTOINCREMENT,
security INTEGER NOT NULL,
owner INTEGER NOT NULL,
FOREIGN KEY(security) REFERENCES securities(id)
);
CREATE TABLE IF NOT EXISTS account_values(
id INTEGER PRIMARY KEY AUTOINCREMENT
);
//
// CREATE TABLE IF NOT EXISTS account(
// id INTEGER PRIMARY KEY AUTOINCREMENT,
// security INTEGER NOT NULL,
// owner INTEGER NOT NULL,
//
// FOREIGN KEY(security) REFERENCES securities(id)
// );
//
// CREATE TABLE IF NOT EXISTS account_values(
// id INTEGER PRIMARY KEY AUTOINCREMENT
// );
";
pub fn migrate(conn: & Connection) {
conn.execute(MIGRATION_SCRIPT, ()).unwrap();
fn get_id_of_new_migration(tx: &Transaction) -> usize {
let q = "SELECT COALESCE(MAX(id) + 1, 0) FROM shitty_migrations";
return tx.query_row(q, (), |row| row.get::<usize, usize>(0)).unwrap();
}
pub fn migrate(conn: &mut Connection, migrations: &Vec<String>) {
let tx = conn.transaction().unwrap();
tx.execute(INITIAL_MIGRATION, ()).unwrap();
let id = get_id_of_new_migration(&tx);
for (i, migration) in migrations.iter().enumerate() {
if i < id {
check_migration(&tx, i, migration);
} else {
apply_migration(&tx, i, migration);
}
}
tx.commit().unwrap();
}
fn apply_migration(tx: &Transaction, id: usize, migration: &String) {
let hash = compute_migration_sha256(migration);
tx.execute(migration, ()).unwrap();
let q = "INSERT INTO shitty_migrations(id, sha256) VALUES (?1, ?2)";
tx.execute(q, (&id, &hash)).unwrap();
}
fn compute_migration_sha256(migration: &String) -> String {
let mut hasher = Sha256::new();
hasher.update(migration);
let ret = hasher.finalize();
return format!("{:x}", ret);
}
fn check_migration(tx: &Transaction, id: usize, migration: &String) -> Result<String, io::Error> {
let q = "SELECT sha256 FROM shitty_migrations WHERE id = ?1";
let res = tx.query_row(q, (&id, ), |row| row.get::<usize, String>(0)).unwrap();
let expected = compute_migration_sha256(migration);
assert_eq!(&res, &expected);
}
#[cfg(test)]
mod test {
use super::*;
fn create_basic_migrations() -> Vec<String> {
let migration1 = "CREATE TABLE people(name TEXT, age INTEGER);".to_string();
let migration2 = "INSERT INTO people(name, age) VALUES (\"didier\", 37);".to_string();
return vec![migration1, migration2];
}
fn create_basic_migrations_2() -> Vec<String> {
let migration1 = "CREATE TABLE people(name TEXT, age INTEGER);".to_string();
let migration2 = "INSERT INTO people(name, age) VALUES (\"stephanie\", 38);".to_string();
return vec![migration1, migration2];
}
#[test]
fn basic() {
let mut conn = Connection::open_in_memory().unwrap();
migrate(&mut conn, &create_basic_migrations());
let tx = conn.transaction().unwrap();
assert_eq!(get_id_of_new_migration(&tx), 2);
let q = "SELECT COUNT(*) FROM people;";
let c = tx.query_row(q, (), |x| x.get::<usize, usize>(0)).unwrap();
assert_eq!(c, c);
}
#[test]
fn idempotency() {
let mut conn = Connection::open_in_memory().unwrap();
migrate(&mut conn, &create_basic_migrations());
migrate(&mut conn, &create_basic_migrations());
let tx = conn.transaction().unwrap();
assert_eq!(get_id_of_new_migration(&tx), 2);
let q = "SELECT COUNT(*) FROM people;";
let c = tx.query_row(q, (), |x| x.get::<usize, usize>(0)).unwrap();
assert_eq!(c, c);
}
#[test]
fn broken_migration() {
let mut conn = Connection::open_in_memory().unwrap();
migrate(&mut conn, &create_basic_migrations());
migrate(&mut conn, &create_basic_migrations_2());
}
}