soar_core/database/
connection.rs

1use std::{
2    path::Path,
3    sync::{Arc, Mutex},
4};
5
6use rusqlite::Connection;
7
8use crate::error::SoarError;
9
10use super::{models::RemotePackage, repository::PackageRepository, statements::DbStatements};
11
12type Result<T> = std::result::Result<T, SoarError>;
13
14pub struct Database {
15    pub conn: Arc<Mutex<Connection>>,
16}
17
18impl Database {
19    pub fn new<P: AsRef<Path>>(path: P) -> Result<Self> {
20        let path = path.as_ref();
21        let conn = Connection::open(path)?;
22        let conn = Arc::new(Mutex::new(conn));
23        Ok(Database { conn })
24    }
25
26    pub fn new_multi<P: AsRef<Path>>(paths: &[P]) -> Result<Self> {
27        let conn = Connection::open(&paths[0])?;
28        conn.execute("PRAGMA case_sensitive_like = ON;", [])?;
29
30        for (idx, path) in paths.iter().enumerate().skip(1) {
31            let path = path.as_ref();
32            conn.execute(
33                &format!("ATTACH DATABASE '{}' AS shard{}", path.display(), idx),
34                [],
35            )?;
36            conn.execute(&format!("PRAGMA shard{idx}.case_sensitive_like = ON;"), [])?;
37        }
38        let conn = Arc::new(Mutex::new(conn));
39        Ok(Database { conn })
40    }
41
42    pub fn from_remote_metadata(&self, metadata: &[RemotePackage], repo_name: &str) -> Result<()> {
43        let mut guard = self.conn.lock().unwrap();
44        let _: String = guard.query_row("PRAGMA journal_mode = WAL", [], |row| row.get(0))?;
45
46        let tx = guard.transaction()?;
47        {
48            let statements = DbStatements::new(&tx)?;
49            let mut repo = PackageRepository::new(&tx, statements, repo_name);
50            repo.import_packages(metadata)?;
51        }
52        tx.commit()?;
53        Ok(())
54    }
55}