1pub mod schema;
2pub mod memory;
3pub mod metrics;
4pub mod session;
5pub mod scope;
6pub mod dedup;
7pub mod privacy;
8pub mod relations;
9
10use rusqlite::Connection;
11
12use crate::config::Config;
13use crate::Error;
14
15pub struct Store {
16 conn: Connection,
17 config: Config,
18}
19
20impl Store {
21 pub fn open(path: &str, config: Config) -> crate::Result<Self> {
22 let mut conn = Connection::open(path)?;
23 configure_connection(&conn, &config)?;
24 schema::check_version(&conn)?;
25 run_migrations(&mut conn)?;
26 Ok(Self { conn, config })
27 }
28
29 pub fn open_in_memory() -> crate::Result<Self> {
30 Self::open_in_memory_with_config(Config::default())
31 }
32
33 pub fn open_in_memory_with_config(config: Config) -> crate::Result<Self> {
34 let mut conn = Connection::open_in_memory()?;
35 configure_connection(&conn, &config)?;
36 run_migrations(&mut conn)?;
37 Ok(Self { conn, config })
38 }
39
40 pub fn config(&self) -> &Config {
41 &self.config
42 }
43
44 pub(crate) fn conn(&self) -> &Connection {
45 &self.conn
46 }
47
48 pub fn get_metadata(&self, key: &str) -> crate::Result<Option<String>> {
49 match self.conn.query_row(
50 "SELECT value FROM _metadata WHERE key = ?1",
51 rusqlite::params![key],
52 |row| row.get::<_, String>(0),
53 ) {
54 Ok(val) => Ok(Some(val)),
55 Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None),
56 Err(e) => Err(e.into()),
57 }
58 }
59
60 pub fn set_metadata(&self, key: &str, value: &str) -> crate::Result<()> {
61 self.conn.execute(
62 "INSERT INTO _metadata (key, value) VALUES (?1, ?2)
63 ON CONFLICT(key) DO UPDATE SET value = excluded.value",
64 rusqlite::params![key, value],
65 )?;
66 Ok(())
67 }
68
69 pub fn schema_version(&self) -> crate::Result<i64> {
70 Ok(self
71 .conn
72 .pragma_query_value(None, "user_version", |r| r.get(0))?)
73 }
74}
75
76fn configure_connection(conn: &Connection, config: &Config) -> rusqlite::Result<()> {
77 conn.execute_batch(&format!(
78 "PRAGMA journal_mode = WAL;
79 PRAGMA busy_timeout = {};
80 PRAGMA synchronous = NORMAL;
81 PRAGMA foreign_keys = ON;
82 PRAGMA cache_size = -{};",
83 config.storage.busy_timeout_ms,
84 config.storage.cache_size_kb
85 ))?;
86 Ok(())
87}
88
89fn run_migrations(conn: &mut Connection) -> crate::Result<()> {
90 let migrations = schema::migrations();
91 migrations
92 .to_latest(conn)
93 .map_err(|e| Error::Migration(e.to_string()))?;
94 Ok(())
95}