mvsep_api_tester/db/
tasks_db.rs1use rusqlite::Connection;
25use std::sync::Mutex;
26
27pub struct TasksDatabase {
28 pub conn: Mutex<Connection>,
29}
30
31impl TasksDatabase {
32 pub fn new(db_path: Option<&str>) -> anyhow::Result<Self> {
33 let path = db_path.map(|p| p.to_string()).unwrap_or_else(|| {
34 crate::utils::paths::tasks_db_path()
35 .to_string_lossy()
36 .to_string()
37 });
38
39 let conn = Connection::open(&path)?;
40 conn.execute_batch("PRAGMA journal_mode=WAL")?;
41 conn.execute_batch("PRAGMA foreign_keys=ON")?;
42 conn.execute_batch("PRAGMA busy_timeout=5000")?;
43
44 let db = Self {
45 conn: Mutex::new(conn),
46 };
47
48 {
49 let locked = db
50 .conn
51 .lock()
52 .map_err(|e| anyhow::anyhow!("Poison error: {}", e))?;
53 run_migrations(&locked)?;
54 }
55
56 Ok(db)
57 }
58
59 pub fn with_conn<F, T>(&self, f: F) -> anyhow::Result<T>
60 where
61 F: FnOnce(&Connection) -> anyhow::Result<T>,
62 {
63 let conn = self
64 .conn
65 .lock()
66 .map_err(|e| anyhow::anyhow!("TasksDatabase lock poisoned: {}", e))?;
67 f(&conn)
68 }
69}
70
71fn run_migrations(conn: &Connection) -> anyhow::Result<()> {
72 conn.execute_batch(
73 "
74 CREATE TABLE IF NOT EXISTS tasks (
75 hash TEXT PRIMARY KEY,
76 file_name TEXT NOT NULL,
77 algorithm_id INTEGER NOT NULL,
78 algorithm_name TEXT NOT NULL,
79 model_id INTEGER,
80 model_name TEXT,
81 model2_id INTEGER,
82 model2_name TEXT,
83 model3_id INTEGER,
84 model3_name TEXT,
85 format INTEGER NOT NULL DEFAULT 1,
86 status TEXT NOT NULL DEFAULT 'uploaded',
87 progress REAL DEFAULT 0,
88 created_at INTEGER NOT NULL,
89 output_files TEXT DEFAULT '[]',
90 error TEXT,
91 message TEXT,
92 queue_count INTEGER,
93 current_order INTEGER,
94 phase TEXT DEFAULT 'uploaded',
95 download_file_name TEXT,
96 download_bytes INTEGER DEFAULT 0,
97 download_total_bytes INTEGER,
98 download_speed_bps REAL DEFAULT 0,
99 download_percent REAL DEFAULT 0
100 );
101
102 CREATE TABLE IF NOT EXISTS task_history (
103 id TEXT PRIMARY KEY,
104 file_name TEXT NOT NULL,
105 algorithm_id INTEGER NOT NULL,
106 algorithm_name TEXT NOT NULL,
107 model_id INTEGER,
108 model_name TEXT,
109 model2_id INTEGER,
110 model2_name TEXT,
111 model3_id INTEGER,
112 model3_name TEXT,
113 format_id INTEGER NOT NULL,
114 format_name TEXT NOT NULL,
115 status TEXT NOT NULL CHECK(status IN ('done', 'failed')),
116 created_at INTEGER NOT NULL,
117 completed_at INTEGER,
118 output_files TEXT DEFAULT '[]',
119 output_path TEXT,
120 error TEXT
121 );
122
123 CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);
124 CREATE INDEX IF NOT EXISTS idx_tasks_created_at ON tasks(created_at);
125 CREATE INDEX IF NOT EXISTS idx_task_history_completed_at ON task_history(completed_at);
126 CREATE INDEX IF NOT EXISTS idx_task_history_algorithm_id ON task_history(algorithm_id);
127 ",
128 )?;
129 Ok(())
130}