Single-binary self-hosted market watcher for stocks, ETFs, indexes, and futures: live charts, key stats, fundamentals, SEC filings, and SSE streaming.
axumdockerfinancerustself-hostedsqlitestocksvite
1use sqlx::sqlite::{SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions, SqliteSynchronous};
2use sqlx::SqlitePool;
3use std::path::Path;
4use std::str::FromStr;
5use std::time::Duration;
6
7/// Open (creating if absent) the SQLite database and run migrations.
8/// WAL + synchronous=Normal matches the sibling apps: durable enough for a
9/// single-operator service, fast enough for the scheduler's frequent upserts.
10pub async fn init(data_dir: &Path) -> anyhow::Result<SqlitePool> {
11 let db_path = data_dir.join("db.sqlite3");
12 let url = format!("sqlite://{}", db_path.display());
13
14 if !db_path.exists() {
15 std::fs::File::create(&db_path)?;
16 }
17
18 let opts = SqliteConnectOptions::from_str(&url)?
19 .create_if_missing(true)
20 .journal_mode(SqliteJournalMode::Wal)
21 .synchronous(SqliteSynchronous::Normal)
22 .busy_timeout(Duration::from_secs(5))
23 .foreign_keys(true);
24
25 let pool = SqlitePoolOptions::new()
26 .max_connections(8)
27 .connect_with(opts)
28 .await?;
29
30 sqlx::migrate!("./migrations").run(&pool).await?;
31 Ok(pool)
32}
33
34/// Current time as UTC epoch-milliseconds. Every `*_at` column uses this.
35pub fn now_ms() -> i64 {
36 chrono::Utc::now().timestamp_millis()
37}
38
39/// Upsert a one-off key-value setting into the `meta` table.
40pub async fn set_meta(pool: &SqlitePool, key: &str, value: &str) -> sqlx::Result<()> {
41 sqlx::query(
42 "INSERT INTO meta (key, value) VALUES (?, ?) \
43 ON CONFLICT(key) DO UPDATE SET value = excluded.value",
44 )
45 .bind(key)
46 .bind(value)
47 .execute(pool)
48 .await?;
49 Ok(())
50}
51
52/// Read a `meta` setting, if present. (Paired with `set_meta`; retained as the
53/// generic meta accessor even though Phase A removed its last caller.)
54#[allow(dead_code)]
55pub async fn get_meta(pool: &SqlitePool, key: &str) -> sqlx::Result<Option<String>> {
56 sqlx::query_scalar("SELECT value FROM meta WHERE key = ?")
57 .bind(key)
58 .fetch_optional(pool)
59 .await
60}