sos_database/
lib.rs

1#![deny(missing_docs)]
2#![forbid(unsafe_code)]
3#![cfg_attr(all(doc, CHANNEL_NIGHTLY), feature(doc_auto_cfg))]
4//! Database storage layer for the [Save Our Secrets](https://saveoursecrets.com) SDK.
5#[cfg(feature = "archive")]
6pub mod archive;
7#[cfg(feature = "audit")]
8pub mod audit_provider;
9pub mod entity;
10pub mod event_log;
11pub mod migrations;
12#[cfg(feature = "preferences")]
13mod preferences;
14mod server_origins;
15#[cfg(feature = "system-messages")]
16mod system_messages;
17mod vault_writer;
18
19pub use event_log::{
20    AccountEventLog, DatabaseEventLog, DeviceEventLog, EventLogOwner,
21    FolderEventLog,
22};
23
24#[cfg(feature = "preferences")]
25pub use preferences::PreferenceProvider;
26
27#[cfg(feature = "system-messages")]
28pub use system_messages::SystemMessagesProvider;
29
30pub use server_origins::ServerOrigins;
31pub use vault_writer::VaultDatabaseWriter;
32
33#[cfg(feature = "files")]
34pub use event_log::FileEventLog;
35
36mod error;
37pub use async_sqlite;
38pub use error::Error;
39
40/// Result type for the library.
41pub(crate) type Result<T> = std::result::Result<T, Error>;
42
43use async_sqlite::{Client, ClientBuilder, JournalMode};
44use std::path::Path;
45
46/// Open a database file from a path with WAL journal mode enabled.
47pub async fn open_file(path: impl AsRef<Path>) -> Result<Client> {
48    tracing::debug!(
49        path = %path.as_ref().display(),
50        "database::open_file",
51    );
52    let client = ClientBuilder::new()
53        .path(path.as_ref())
54        .journal_mode(JournalMode::Wal)
55        .open()
56        .await?;
57
58    /*
59    let sqlite_version = client
60        .conn(|conn| {
61            conn.execute("PRAGMA foreign_keys = ON", [])?;
62            let version: String =
63                conn.query_row("SELECT sqlite_version()", [], |row| {
64                    row.get(0)
65                })?;
66            Ok(version)
67        })
68        .await?;
69
70    tracing::debug!(
71        version = %sqlite_version,
72        "database::sqlite",
73    );
74    */
75
76    Ok(client)
77}
78
79/// Open a database file from a specific journal mode.
80pub async fn open_file_with_journal_mode(
81    path: impl AsRef<Path>,
82    mode: JournalMode,
83) -> Result<Client> {
84    Ok(ClientBuilder::new()
85        .path(path.as_ref())
86        .journal_mode(mode)
87        .open()
88        .await?)
89}
90
91/// Open an in-memory database and run migrations.
92pub async fn open_memory() -> Result<Client> {
93    let mut client = ClientBuilder::new().open().await?;
94    crate::migrations::migrate_client(&mut client).await?;
95    Ok(client)
96}
97
98#[cfg(debug_assertions)]
99#[allow(dead_code)]
100pub(crate) fn dump_rows<C>(
101    conn: C,
102    table: &str,
103) -> std::result::Result<(), async_sqlite::rusqlite::Error>
104where
105    C: std::ops::Deref<Target = async_sqlite::rusqlite::Connection>,
106{
107    println!("--- BEGIN DUMP ---");
108    let mut stmt = conn.prepare(&format!(
109        r#"
110            SELECT * FROM {}
111        "#,
112        table
113    ))?;
114    let mut rows = stmt.query([])?;
115    while let Ok(Some(row)) = rows.next() {
116        println!("{:#?}", row);
117    }
118    println!("--- END DUMP ---");
119    Ok(())
120}