1mod actions;
8mod annotations;
9mod auth_blobs;
10mod marks;
11mod pages;
12mod refs;
13mod sessions;
14mod skill_cache;
15
16#[cfg(test)]
17mod tests;
18
19use std::path::Path;
20use std::time::{SystemTime, UNIX_EPOCH};
21
22use rusqlite::{Connection, OpenFlags};
23
24use crate::error::Result;
25use crate::migrate;
26
27pub const IDEMPOTENCY_TTL_SECS: i64 = 30;
30
31pub struct Store {
33 conn: Connection,
34}
35
36impl Store {
37 pub fn open(path: impl AsRef<Path>) -> Result<Self> {
40 let conn = Connection::open(path.as_ref())?;
41 configure(&conn)?;
42 migrate::apply(&conn)?;
43 Ok(Self { conn })
44 }
45
46 pub fn open_in_memory() -> Result<Self> {
49 let conn = Connection::open_in_memory()?;
50 configure(&conn)?;
51 migrate::apply(&conn)?;
52 Ok(Self { conn })
53 }
54
55 pub fn open_read_only(path: impl AsRef<Path>) -> Result<Self> {
58 let conn = Connection::open_with_flags(
59 path.as_ref(),
60 OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_NO_MUTEX,
61 )?;
62 Ok(Self { conn })
63 }
64
65 #[must_use]
68 pub fn conn(&self) -> &Connection {
69 &self.conn
70 }
71}
72
73fn configure(conn: &Connection) -> Result<()> {
74 conn.pragma_update(None, "journal_mode", "WAL")?;
75 conn.pragma_update(None, "synchronous", "NORMAL")?;
76 conn.pragma_update(None, "foreign_keys", "ON")?;
77 Ok(())
78}
79
80#[must_use]
83pub fn epoch_secs() -> i64 {
84 SystemTime::now()
85 .duration_since(UNIX_EPOCH)
86 .map_or(0, |d| i64::try_from(d.as_secs()).unwrap_or(i64::MAX))
87}