use rusqlite::Connection;
use crate::db::DbError;
const DUC_SCHEMA: &str = include_str!(concat!(env!("OUT_DIR"), "/duc.sql"));
const VERSION_CONTROL_SCHEMA: &str = include_str!(concat!(env!("OUT_DIR"), "/version_control.sql"));
const SEARCH_SCHEMA: &str = include_str!(concat!(env!("OUT_DIR"), "/search.sql"));
const APP_ID: i64 = 1_146_569_567;
const CURRENT_VERSION: i64 = {
let bytes = env!("DUC_SCHEMA_USER_VERSION").as_bytes();
let mut val: i64 = 0;
let mut i = 0;
while i < bytes.len() {
val = val * 10 + (bytes[i] - b'0') as i64;
i += 1;
}
val
};
include!(concat!(env!("OUT_DIR"), "/migrations_registry.rs"));
#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
const CONN_PRAGMAS: &str = "
PRAGMA journal_mode = WAL;
PRAGMA foreign_keys = ON;
";
#[cfg(all(target_family = "wasm", target_os = "unknown"))]
const CONN_PRAGMAS: &str = "
PRAGMA journal_mode = MEMORY;
PRAGMA foreign_keys = ON;
";
pub(crate) fn bootstrap(conn: &Connection) -> Result<(), DbError> {
let user_version: i64 = conn.pragma_query_value(None, "user_version", |r| r.get(0))?;
if user_version == 0 {
conn.execute_batch(DUC_SCHEMA)
.map_err(|e| DbError::Bootstrap(format!("duc.sql apply failed: {e}")))?;
conn.execute_batch(VERSION_CONTROL_SCHEMA)
.map_err(|e| DbError::Bootstrap(format!("version_control.sql apply failed: {e}")))?;
conn.execute_batch(SEARCH_SCHEMA)
.map_err(|e| DbError::Bootstrap(format!("search.sql apply failed: {e}")))?;
let app_id: i64 = conn.pragma_query_value(None, "application_id", |r| r.get(0))?;
if app_id != APP_ID {
return Err(DbError::Bootstrap(format!(
"unexpected application_id after bootstrap: {app_id} (expected {APP_ID})"
)));
}
} else if user_version == CURRENT_VERSION {
conn.execute_batch(CONN_PRAGMAS)
.map_err(|e| DbError::Bootstrap(format!("pragma apply failed: {e}")))?;
} else {
let mut current = user_version;
loop {
match MIGRATIONS.iter().find(|(from, _, _)| *from == current) {
Some((from, to, sql)) => {
conn.execute_batch(sql).map_err(|e| {
DbError::Bootstrap(format!("migration {from}\u{2192}{to} failed: {e}"))
})?;
current =
conn.pragma_query_value(None, "user_version", |r| r.get(0))?;
if current == CURRENT_VERSION {
break;
}
}
None => {
return Err(DbError::Bootstrap(format!(
"unsupported schema version {user_version}; expected 0 or {CURRENT_VERSION}"
)));
}
}
}
conn.execute_batch(CONN_PRAGMAS)
.map_err(|e| DbError::Bootstrap(format!("pragma apply failed: {e}")))?;
}
Ok(())
}