repos
/ finance-rust master

finance-rust

mirror archived upstream

Single-binary self-hosted market watcher for stocks, ETFs, indexes, and futures: live charts, key stats, fundamentals, SEC filings, and SSE streaming.

axumdockerfinancerustself-hostedsqlitestocksvite

2.0 KB · 61 lines · Rust Raw History
 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}