common.rs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. use std::path::PathBuf;
  2. use std::sync::atomic::AtomicBool;
  3. use std::sync::Arc;
  4. use std::time::Duration;
  5. use cdk_sql_common::pool::{self, DatabasePool};
  6. use cdk_sql_common::value::Value;
  7. use rusqlite::Connection;
  8. use crate::async_sqlite;
  9. /// The config need to create a new SQLite connection
  10. #[derive(Clone, Debug)]
  11. pub struct Config {
  12. path: Option<String>,
  13. password: Option<String>,
  14. }
  15. impl pool::DatabaseConfig for Config {
  16. fn default_timeout(&self) -> Duration {
  17. Duration::from_secs(5)
  18. }
  19. fn max_size(&self) -> usize {
  20. if self.password.is_none() {
  21. 1
  22. } else {
  23. 20
  24. }
  25. }
  26. }
  27. /// Sqlite connection manager
  28. #[derive(Debug)]
  29. pub struct SqliteConnectionManager;
  30. impl DatabasePool for SqliteConnectionManager {
  31. type Config = Config;
  32. type Connection = async_sqlite::AsyncSqlite;
  33. type Error = rusqlite::Error;
  34. fn new_resource(
  35. config: &Self::Config,
  36. _stale: Arc<AtomicBool>,
  37. _timeout: Duration,
  38. ) -> Result<Self::Connection, pool::Error<Self::Error>> {
  39. let conn = if let Some(path) = config.path.as_ref() {
  40. // Check if parent directory exists before attempting to open database
  41. let path_buf = PathBuf::from(path);
  42. if let Some(parent) = path_buf.parent() {
  43. if !parent.exists() {
  44. return Err(pool::Error::Resource(rusqlite::Error::InvalidPath(
  45. path_buf.clone(),
  46. )));
  47. }
  48. }
  49. Connection::open(path)?
  50. } else {
  51. Connection::open_in_memory()?
  52. };
  53. if let Some(password) = config.password.as_ref() {
  54. conn.execute_batch(&format!("pragma key = '{password}';"))?;
  55. }
  56. conn.execute_batch(
  57. r#"
  58. pragma busy_timeout = 10000;
  59. pragma journal_mode = WAL;
  60. pragma synchronous = normal;
  61. pragma temp_store = memory;
  62. pragma mmap_size = 5242880;
  63. pragma cache = shared;
  64. "#,
  65. )?;
  66. conn.busy_timeout(Duration::from_secs(10))?;
  67. Ok(async_sqlite::AsyncSqlite::new(conn))
  68. }
  69. }
  70. impl From<PathBuf> for Config {
  71. fn from(path: PathBuf) -> Self {
  72. path.to_str().unwrap_or_default().into()
  73. }
  74. }
  75. impl From<(PathBuf, String)> for Config {
  76. fn from((path, password): (PathBuf, String)) -> Self {
  77. (path.to_str().unwrap_or_default(), password.as_str()).into()
  78. }
  79. }
  80. impl From<&PathBuf> for Config {
  81. fn from(path: &PathBuf) -> Self {
  82. path.to_str().unwrap_or_default().into()
  83. }
  84. }
  85. impl From<&str> for Config {
  86. fn from(path: &str) -> Self {
  87. if path.contains(":memory:") {
  88. Config {
  89. path: None,
  90. password: None,
  91. }
  92. } else {
  93. Config {
  94. path: Some(path.to_owned()),
  95. password: None,
  96. }
  97. }
  98. }
  99. }
  100. impl From<(&str, &str)> for Config {
  101. fn from((path, pass): (&str, &str)) -> Self {
  102. if path.contains(":memory:") {
  103. Config {
  104. path: None,
  105. password: Some(pass.to_owned()),
  106. }
  107. } else {
  108. Config {
  109. path: Some(path.to_owned()),
  110. password: Some(pass.to_owned()),
  111. }
  112. }
  113. }
  114. }
  115. /// Convert cdk_sql_common::value::Value to rusqlite Value
  116. #[inline(always)]
  117. pub fn to_sqlite(v: Value) -> rusqlite::types::Value {
  118. match v {
  119. Value::Blob(blob) => rusqlite::types::Value::Blob(blob),
  120. Value::Integer(i) => rusqlite::types::Value::Integer(i),
  121. Value::Null => rusqlite::types::Value::Null,
  122. Value::Text(t) => rusqlite::types::Value::Text(t),
  123. Value::Real(r) => rusqlite::types::Value::Real(r),
  124. }
  125. }
  126. /// Convert from rusqlite Valute to cdk_sql_common::value::Value
  127. #[inline(always)]
  128. pub fn from_sqlite(v: rusqlite::types::Value) -> Value {
  129. match v {
  130. rusqlite::types::Value::Blob(blob) => Value::Blob(blob),
  131. rusqlite::types::Value::Integer(i) => Value::Integer(i),
  132. rusqlite::types::Value::Null => Value::Null,
  133. rusqlite::types::Value::Text(t) => Value::Text(t),
  134. rusqlite::types::Value::Real(r) => Value::Real(r),
  135. }
  136. }