Skip to main content

mail4agent_store_sqlite/
lib.rs

1//! A [`mail4agent_core::MailStore`] backed by plain SQLite (`rusqlite`,
2//! bundled): versioned migrations, WAL, one transaction per mutating
3//! method. This crate owns its own connection ([`db`]) -- everything it
4//! adds on top is the schema ([`migrations`]) and [`SqliteMailStore`], the
5//! [`mail4agent_core::MailStore`] implementation laid over it.
6//!
7//! `MailStore`'s methods are synchronous and fallible -- see
8//! `mail4agent-core`'s own module doc comment on why a persistent store
9//! cannot satisfy that trait any other way -- so every method here goes
10//! through [`Db::read_blocking`] / [`Db::write_blocking`], never an async
11//! helper: those would need a tokio runtime this trait has no way to
12//! require of its caller.
13//!
14//! **Never call a [`SqliteMailStore`] method from inside an async task
15//! running on a tokio runtime.** `read_blocking`/`write_blocking` block
16//! the calling thread on `Db`'s own mutex and panic if that thread is
17//! itself inside a tokio task. A daemon wiring this store into async
18//! request handling reaches it through `tokio::task::spawn_blocking`,
19//! exactly as `Db::read`/`Db::write` would if this crate exposed them.
20
21mod db;
22mod migrations;
23mod store;
24
25pub use db::{Db, DbConfig, DbError, Migration, MigrationRunner};
26pub use migrations::migrations;
27pub use store::SqliteMailStore;
28
29// rusqlite re-export so a consumer (this crate's own tests included) needs
30// no second direct dependency on it just to build `rusqlite::params!` calls
31// or match on `rusqlite::Error`.
32pub use rusqlite;
33
34#[cfg(test)]
35mod engine_tests;
36#[cfg(test)]
37mod tests;