//! SQLite through `sqlx` (hub spec §3.1, §17.2): WAL, foreign keys on, //! migrations embedded and applied at start. One module per table group. pub mod repos; use sqlx::sqlite::{SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions, SqliteSynchronous}; use sqlx::SqlitePool; use std::path::Path; pub type Pool = SqlitePool; /// Open (creating if needed) and migrate the database at `path`. /// How long a statement waits for SQLite's write lock. Most writers are /// background clients (runners appending logs, webhook deliveries), and a /// commit can stall for seconds while a build saturates the host's disk, so /// waiting beats failing. const BUSY_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); pub async fn open(path: &Path) -> anyhow::Result { let options = SqliteConnectOptions::new() .filename(path) .create_if_missing(true) .journal_mode(SqliteJournalMode::Wal) .synchronous(SqliteSynchronous::Normal) .foreign_keys(true) .busy_timeout(BUSY_TIMEOUT); let pool = SqlitePoolOptions::new().max_connections(8).connect_with(options).await?; sqlx::migrate!("./migrations").run(&pool).await?; Ok(pool) } /// Milliseconds since the epoch, the hub's timestamp unit (as `oxy`'s). pub fn now_ms() -> i64 { std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).map(|d| d.as_millis() as i64).unwrap_or(0) }