rust_ef_sqlite/
provider.rs1use crate::pool_strategy::{
2 SqliteConnectionCustomizer, SqliteProviderInner, SQLITE_DEFAULT_POOL_SIZE,
3};
4use crate::sql_generator::SqliteSqlGenerator;
5use async_trait::async_trait;
6use r2d2_sqlite::SqliteConnectionManager;
7use rust_ef::error::{EFError, EFResult};
8use rust_ef::provider::{IDatabaseProvider, ISqlGenerator};
9use std::sync::Arc;
10use tokio::sync::Mutex;
11
12pub struct SqliteProvider {
13 inner: SqliteProviderInner,
14 #[cfg(feature = "tracing")]
15 slow_query_threshold_ms: std::sync::atomic::AtomicU64,
16}
17
18impl SqliteProvider {
19 pub fn new(path: impl AsRef<std::path::Path>) -> EFResult<Self> {
29 let path_ref = path.as_ref();
30 if path_ref == std::path::Path::new(":memory:") {
31 return Self::new_in_memory();
32 }
33 let manager = SqliteConnectionManager::file(path_ref);
34 let pool = r2d2::Pool::builder()
35 .max_size(SQLITE_DEFAULT_POOL_SIZE)
36 .connection_customizer(Box::new(SqliteConnectionCustomizer))
37 .build(manager)
38 .map_err(|e| EFError::connection(format!("SQLite pool creation failed: {}", e)))?;
39 Ok(Self {
40 inner: SqliteProviderInner::Pooled(pool),
41 #[cfg(feature = "tracing")]
42 slow_query_threshold_ms: std::sync::atomic::AtomicU64::new(0),
43 })
44 }
45
46 pub fn new_in_memory() -> EFResult<Self> {
54 let conn = rusqlite::Connection::open_in_memory()
55 .map_err(|e| EFError::connection(format!("SQLite in-memory open failed: {}", e)))?;
56 conn.execute_batch("PRAGMA busy_timeout=5000;")
59 .map_err(|e| EFError::connection(format!("SQLite pragma setup failed: {}", e)))?;
60 Ok(Self {
61 inner: SqliteProviderInner::Single(Arc::new(Mutex::new(conn))),
62 #[cfg(feature = "tracing")]
63 slow_query_threshold_ms: std::sync::atomic::AtomicU64::new(0),
64 })
65 }
66}
67
68#[async_trait]
69impl IDatabaseProvider for SqliteProvider {
70 fn sql_generator(&self) -> &'static dyn ISqlGenerator {
71 &SqliteSqlGenerator
73 }
74
75 async fn get_connection(&self) -> EFResult<Box<dyn rust_ef::provider::IAsyncConnection>> {
76 let _guard = rust_ef::observability::PoolAcquireGuard::new("SQLite");
77 #[cfg_attr(not(feature = "tracing"), allow(unused_mut))]
78 let mut conn = self.inner.get_connection().await?;
79 #[cfg(feature = "tracing")]
80 {
81 let ms = self
82 .slow_query_threshold_ms
83 .load(std::sync::atomic::Ordering::Relaxed);
84 if ms > 0 {
85 conn.set_slow_query_threshold(std::time::Duration::from_millis(ms));
86 }
87 }
88 Ok(conn)
89 }
90
91 async fn execute_migration_command(&self, sql: &str) -> EFResult<()> {
92 self.inner.execute_migration_command(sql).await
93 }
94
95 fn name(&self) -> &str {
96 "SQLite"
97 }
98
99 fn migration_dialect(&self) -> rust_ef::migration::MigrationDialect {
100 rust_ef::migration::MigrationDialect::Sqlite
101 }
102
103 #[cfg(feature = "tracing")]
104 fn set_slow_query_threshold(&self, threshold: std::time::Duration) {
105 self.slow_query_threshold_ms.store(
106 threshold.as_millis() as u64,
107 std::sync::atomic::Ordering::Relaxed,
108 );
109 }
110}
111
112impl std::fmt::Debug for SqliteProvider {
113 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
114 f.debug_struct("SqliteProvider")
115 .field("name", &self.name())
116 .finish()
117 }
118}