-
Notifications
You must be signed in to change notification settings - Fork 6
feat: add types to show API shape and design #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| //! Configuration for SQLite database connection pools | ||
|
|
||
| use std::time::Duration; | ||
|
|
||
| /// Configuration for SqliteDatabase connection pools | ||
| /// | ||
| /// # Examples | ||
| /// | ||
| /// ``` | ||
| /// use sqlx_sqlite_conn_mgr::SqliteDatabaseConfig; | ||
| /// use std::time::Duration; | ||
| /// | ||
| /// // Use defaults | ||
| /// let config = SqliteDatabaseConfig::default(); | ||
| /// | ||
| /// // Customize specific fields | ||
| /// let config = SqliteDatabaseConfig { | ||
| /// max_read_connections: 3, | ||
| /// idle_timeout: Duration::from_secs(60), | ||
| /// }; | ||
| /// | ||
| /// // Override just one field | ||
| /// let config = SqliteDatabaseConfig { | ||
| /// max_read_connections: 3, | ||
| /// ..Default::default() | ||
| /// }; | ||
| /// ``` | ||
| #[derive(Debug, Clone)] | ||
| pub struct SqliteDatabaseConfig { | ||
| /// Maximum number of concurrent read connections | ||
| /// | ||
| /// This controls the size of the read-only connection pool. | ||
| /// Higher values allow more concurrent read queries but consume more resources. | ||
| /// | ||
| /// Default: 6 | ||
| pub max_read_connections: u32, | ||
|
|
||
| /// Idle timeout for both read and write connections | ||
| /// | ||
| /// Connections that remain idle for this duration will be closed automatically. | ||
| /// This helps prevent resource exhaustion from idle threads. | ||
| /// | ||
| /// Default: 30 seconds | ||
| pub idle_timeout: Duration, | ||
| } | ||
|
|
||
| impl Default for SqliteDatabaseConfig { | ||
| fn default() -> Self { | ||
| Self { | ||
| max_read_connections: 6, | ||
| idle_timeout: Duration::from_secs(30), | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| //! SQLite database with connection pooling and optional write access | ||
|
|
||
| use sqlx::{Pool, Sqlite}; | ||
| use std::path::PathBuf; | ||
| use std::sync::atomic::AtomicBool; | ||
|
|
||
| /// SQLite database with connection pooling for concurrent reads and optional exclusive writes. | ||
| /// | ||
| /// ## Architecture | ||
| /// | ||
| /// The database maintains two connection pools: | ||
| /// - **`read_pool`**: Pool of read-only connections for concurrent reads | ||
| /// - **`write_conn`**: Single-connection pool for exclusive write access (enforced by max_connections=1) | ||
| /// | ||
| /// ## State Management | ||
| /// | ||
| /// - **`wal_initialized`**: Tracks whether WAL journal mode has been enabled (lazy initialization) | ||
| /// - **`closed`**: Prevents use after the database has been closed | ||
| /// - **`path`**: Database file path for cleanup operations | ||
| /// | ||
| /// ## Usage Pattern | ||
| /// | ||
| /// ```text | ||
| /// 1. Connect to database (creates/reuses connection pools) | ||
| /// 2. Read operations: Access read_pool for concurrent reads | ||
| /// 3. Write operations: Acquire writer (lazily enables WAL on first call) | ||
| /// 4. Close database when done | ||
| /// ``` | ||
| #[derive(Debug)] | ||
| pub struct SqliteDatabase { | ||
|
pmorris-dev marked this conversation as resolved.
|
||
| /// Pool of read-only connections (defaults to max_connections=6) for concurrent reads | ||
| read_pool: Pool<Sqlite>, | ||
|
|
||
| /// Single read-write connection pool (max_connections=1) for serialized writes | ||
| write_conn: Pool<Sqlite>, | ||
|
|
||
| /// Tracks if WAL mode has been initialized (set on first write) | ||
| wal_initialized: AtomicBool, | ||
|
pmorris-dev marked this conversation as resolved.
|
||
|
|
||
| /// Marks database as closed to prevent further operations | ||
| closed: AtomicBool, | ||
|
|
||
| /// Path to database file (used for cleanup and registry lookups) | ||
| path: PathBuf, | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| //! Error types for sqlx-sqlite-conn-mgr | ||
|
|
||
| use thiserror::Error; | ||
|
|
||
| /// Errors that may occur when working with sqlx-sqlite-conn-mgr | ||
| #[derive(Error, Debug)] | ||
| pub enum Error { | ||
| /// IO error when accessing database files. Standard library IO errors | ||
| /// are converted to this variant. | ||
| #[error("IO error: {0}")] | ||
| Io(#[from] std::io::Error), | ||
|
|
||
| /// Error from the sqlx library. Standard sqlx errors are converted to this variant | ||
| #[error("Sqlx error: {0}")] | ||
| Sqlx(#[from] sqlx::Error), | ||
|
|
||
| /// Database has been closed and cannot be used | ||
| #[error("Database has been closed")] | ||
| DatabaseClosed, | ||
| } | ||
|
|
||
| /// A type alias for Results with our Error type | ||
| pub type Result<T> = std::result::Result<T, Error>; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,33 @@ | ||
| //! # SQLx Connection Pool Manager | ||
| //! # sqlx-sqlite-conn-mgr | ||
| //! | ||
| //! A minimal wrapper around SQLx that enforces pragmatic SQLite connection policies | ||
| //! for mobile and desktop applications. | ||
| //! | ||
| //! ## Core Types | ||
| //! | ||
| //! - **[`SqliteDatabase`]**: Main database type with separate read and write connection pools | ||
| //! - **[`SqliteDatabaseConfig`]**: Configuration for connection pool settings | ||
| //! - **[`WriteGuard`]**: RAII guard ensuring exclusive write access | ||
| //! - **[`Error`]**: Error type for database operations | ||
| //! | ||
| //! ## Architecture | ||
| //! | ||
| //! - **Dual pools**: Separate read-only pool (max 6 connections) and write pool (max 1 connection) | ||
| //! - **Lazy WAL mode**: Write-Ahead Logging enabled automatically on first write | ||
| //! - **Exclusive writes**: Single-connection write pool enforces serialized write access | ||
| //! - **Concurrent reads**: Multiple readers can query simultaneously via the read pool | ||
|
|
||
| // TODO: Remove these allows once implementation is complete | ||
| #![allow(dead_code)] | ||
| #![allow(unused)] | ||
|
|
||
| mod config; | ||
| mod database; | ||
| mod error; | ||
| mod write_guard; | ||
|
|
||
| // Re-export public types | ||
| pub use config::SqliteDatabaseConfig; | ||
| pub use database::SqliteDatabase; | ||
| pub use error::{Error, Result}; | ||
| pub use write_guard::WriteGuard; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| //! WriteGuard for exclusive write access to the database | ||
|
|
||
| use sqlx::Sqlite; | ||
| use sqlx::pool::PoolConnection; | ||
| use sqlx::sqlite::SqliteConnection; | ||
| use std::ops::{Deref, DerefMut}; | ||
|
|
||
| /// RAII guard for exclusive write access to a database connection | ||
| /// | ||
| /// This guard wraps a pool connection and returns it to the pool on drop. | ||
| /// Only one `WriteGuard` can exist at a time (enforced by max_connections=1), | ||
| /// ensuring serialized write access. | ||
| /// | ||
| /// The guard derefs to `SqliteConnection` allowing direct use with sqlx queries. | ||
| /// | ||
| /// # Example | ||
| /// TODO: Remove ignore once implementation is complete | ||
| /// ```ignore | ||
| /// use sqlx_sqlite_conn_mgr::SqliteDatabase; | ||
| /// use sqlx::query; | ||
| /// | ||
| /// # async fn example() -> Result<(), sqlx_sqlite_conn_mgr::Error> { | ||
| /// let db = SqliteDatabase::connect("test.db").await?; | ||
| /// let mut writer = db.acquire_writer().await?; | ||
| /// // Use &mut *writer for write queries (e.g. INSERT/UPDATE/DELETE) | ||
| /// query("INSERT INTO users (name) VALUES (?)") | ||
| /// .bind("Alice") | ||
| /// .execute(&mut *writer) | ||
| /// .await?; | ||
| /// // Writer is automatically returned when dropped | ||
| /// # Ok(()) | ||
| /// # } | ||
| /// ``` | ||
| #[derive(Debug)] | ||
| pub struct WriteGuard { | ||
| conn: PoolConnection<Sqlite>, | ||
| } | ||
|
|
||
| impl WriteGuard { | ||
| /// Create a new WriteGuard by taking ownership of a pool connection | ||
| pub(crate) fn new(conn: PoolConnection<Sqlite>) -> Self { | ||
| Self { conn } | ||
| } | ||
| } | ||
|
|
||
| impl Deref for WriteGuard { | ||
| type Target = SqliteConnection; | ||
|
|
||
| fn deref(&self) -> &Self::Target { | ||
| &*self.conn | ||
| } | ||
| } | ||
|
|
||
| impl DerefMut for WriteGuard { | ||
| fn deref_mut(&mut self) -> &mut Self::Target { | ||
| &mut *self.conn | ||
| } | ||
| } | ||
|
|
||
| // Drop is automatically implemented - PoolConnection returns itself to the pool | ||
|
|
||
| // WriteGuard is automatically Send because PoolConnection<Sqlite> is Send |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.