Skip to main content

codlet_sqlx/
lib.rs

1//! SQLite storage adapters for codlet (RFC-011).
2//!
3//! `SqliteStore` wraps a [`sqlx::SqlitePool`] and implements all three
4//! core store traits plus the admin extension:
5//!
6//! - [`codlet_core::store::code::CodeStore`] — code issue, lookup, claim, revoke
7//! - [`codlet_core::store::session::SessionStore`] — session issue, validate, revoke
8//! - [`codlet_core::store::token::FormTokenStore`] — form-token issue, consume, replay
9//! - [`codlet_core::admin::CodeAdminStore`] — metadata listing and lookup (RFC-030)
10//!
11//! ## Backend options
12//!
13//! SQLx supports three SQLite connection strings:
14//!
15//! ```text
16//! "sqlite::memory:"          — ephemeral, in-process only (tests / local dev)
17//! "sqlite:path/to/codlet.db" — persistent file on disk (single-server production)
18//! "sqlite::memory:?cache=shared&uri=true" — named shared memory (advanced)
19//! ```
20//!
21//! For production use a file-backed database and set WAL mode (applied
22//! automatically by [`run_migrations`]).
23//!
24//! ## Atomicity guarantee
25//!
26//! Every one-time transition (code claim, form-token consume) uses a single
27//! `UPDATE … WHERE … AND <guard condition>` followed by an affected-row count
28//! check. SQLite's serialised write mode ensures these are atomic under
29//! concurrent access from multiple threads within the same process. For
30//! multi-process deployments, WAL mode and an appropriate busy-timeout are
31//! recommended.
32//!
33//! ## Conformance
34//!
35//! All stores pass the full `codlet-conformance` suite, including the
36//! concurrent-claim race test (RFC-022, RFC-023).
37
38#![forbid(unsafe_code)]
39
40pub mod admin;
41pub mod code;
42pub mod migration;
43pub mod session;
44pub mod token;
45
46pub use migration::run_migrations;
47
48/// A handle wrapping a [`sqlx::SqlitePool`] that implements all three
49/// codlet store traits.
50///
51/// Clone is cheap (the pool is reference-counted internally).
52#[derive(Debug, Clone)]
53pub struct SqliteStore {
54    pool: sqlx::SqlitePool,
55}
56
57impl SqliteStore {
58    /// Construct from an existing pool. The caller must have already run
59    /// [`run_migrations`] on the pool before issuing any store operations.
60    #[must_use]
61    pub fn new(pool: sqlx::SqlitePool) -> Self {
62        Self { pool }
63    }
64
65    /// Borrow the underlying pool (e.g. to run custom queries alongside codlet).
66    #[must_use]
67    pub fn pool(&self) -> &sqlx::SqlitePool {
68        &self.pool
69    }
70}