1 parent
96a32ea8fb
commit
a643e7e3ab
106 files changed
+2223
-4669
No files matched your search
+1
-25
@@ -3,7 +3,6 @@ use std::path::Path;
|
||||
|
||||
use rusqlite::Connection;
|
||||
|
||||
/// Owned database context for short blocking jobs. Never hold SQLite on a Tokio worker.
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct UserDb {
|
||||
data_dir: String,
|
||||
@@ -32,7 +31,6 @@ impl UserDb {
|
||||
}
|
||||
}
|
||||
|
||||
/// All migration scripts in order. Each entry is (version, sql).
|
||||
const MIGRATIONS: &[(u32, &str)] = &[
|
||||
(1, include_str!("../../migrations/V001__initial_schema.sql")),
|
||||
(
|
||||
@@ -199,20 +197,11 @@ const MIGRATIONS: &[(u32, &str)] = &[
|
||||
),
|
||||
];
|
||||
|
||||
/// Run any pending migrations based on SQLite's `user_version` PRAGMA.
|
||||
///
|
||||
/// If refinery has previously run migrations (indicated by the presence of
|
||||
/// `refinery_schema_history`), we sync `user_version` to match the highest
|
||||
/// refinery version before checking for new migrations. This avoids re-running
|
||||
/// migrations that refinery already applied.
|
||||
fn run_migrations(conn: &Connection) -> Result<(), String> {
|
||||
let mut current: u32 = conn
|
||||
.query_row("PRAGMA user_version", [], |row| row.get(0))
|
||||
.map_err(|e| format!("Failed to read user_version: {e}"))?;
|
||||
|
||||
// Sync with refinery's migration state so we never re-apply migrations
|
||||
// that refinery already applied (refinery updates its own history table
|
||||
// but doesn't touch the user_version pragma).
|
||||
let refinery_max: Option<u32> = conn
|
||||
.query_row(
|
||||
"SELECT MAX(version) FROM refinery_schema_history",
|
||||
@@ -241,10 +230,6 @@ fn run_migrations(conn: &Connection) -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Opens the per-user SQLite database at `{data_dir}/{user_hash}/db.sqlite`.
|
||||
///
|
||||
/// Creates the directory tree if it doesn't exist, enables WAL journal mode
|
||||
/// and foreign key enforcement, then runs any pending migrations.
|
||||
pub fn open_user_db(data_dir: &str, user_hash: &str) -> Result<Connection, String> {
|
||||
let dir = Path::new(data_dir).join(user_hash);
|
||||
fs::create_dir_all(&dir).map_err(|e| format!("Failed to create db dir: {e}"))?;
|
||||
@@ -252,23 +237,17 @@ pub fn open_user_db(data_dir: &str, user_hash: &str) -> Result<Connection, Strin
|
||||
let db_path = dir.join("db.sqlite");
|
||||
let conn = Connection::open(&db_path).map_err(|e| format!("Failed to open SQLite: {e}"))?;
|
||||
|
||||
// Enable WAL mode for better concurrent read performance.
|
||||
conn.execute_batch("PRAGMA journal_mode=WAL;")
|
||||
.map_err(|e| format!("Failed to set WAL mode: {e}"))?;
|
||||
|
||||
// Enable foreign key constraint enforcement.
|
||||
conn.execute_batch("PRAGMA foreign_keys=ON;")
|
||||
.map_err(|e| format!("Failed to enable foreign keys: {e}"))?;
|
||||
|
||||
// Run any pending schema migrations.
|
||||
run_migrations(&conn)?;
|
||||
|
||||
Ok(conn)
|
||||
}
|
||||
|
||||
/// Opens an in-memory SQLite database with all migration scripts applied.
|
||||
/// Used exclusively by tests so every test starts with a clean, fully-migrated
|
||||
/// schema without touching the filesystem.
|
||||
#[cfg(test)]
|
||||
pub fn open_test_db() -> Connection {
|
||||
let conn = Connection::open_in_memory().expect("Failed to open in-memory SQLite");
|
||||
@@ -289,7 +268,6 @@ mod tests {
|
||||
fn test_open_test_db_has_tables() {
|
||||
let conn = open_test_db();
|
||||
|
||||
// Verify the three expected tables exist.
|
||||
let tables: Vec<String> = conn
|
||||
.prepare("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name")
|
||||
.unwrap()
|
||||
@@ -312,11 +290,9 @@ mod tests {
|
||||
|
||||
let conn = open_user_db(data_dir, "abc123").unwrap();
|
||||
|
||||
// The file should exist on disk.
|
||||
let db_file = tmp.path().join("abc123").join("db.sqlite");
|
||||
assert!(db_file.exists());
|
||||
|
||||
// Foreign keys should be enabled.
|
||||
let fk: i32 = conn
|
||||
.query_row("PRAGMA foreign_keys", [], |row| row.get(0))
|
||||
.unwrap();
|
||||
@@ -347,7 +323,7 @@ mod async_tests {
|
||||
.await
|
||||
});
|
||||
ready.await.unwrap();
|
||||
// On a current-thread runtime, an inline DB job prevents this send.
|
||||
|
||||
release.send(()).unwrap();
|
||||
job.await.unwrap().unwrap();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user