common.rs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. use std::sync::Arc;
  2. use std::time::Duration;
  3. use rusqlite::{params, Connection};
  4. use crate::pool::{Pool, ResourceManager};
  5. /// The config need to create a new SQLite connection
  6. #[derive(Debug)]
  7. pub struct Config {
  8. path: Option<String>,
  9. password: Option<String>,
  10. }
  11. /// Sqlite connection manager
  12. #[derive(Debug)]
  13. pub struct SqliteConnectionManager;
  14. impl ResourceManager for SqliteConnectionManager {
  15. type Config = Config;
  16. type Resource = Connection;
  17. type Error = rusqlite::Error;
  18. fn new_resource(
  19. config: &Self::Config,
  20. ) -> Result<Self::Resource, crate::pool::Error<Self::Error>> {
  21. let conn = if let Some(path) = config.path.as_ref() {
  22. Connection::open(path)?
  23. } else {
  24. Connection::open_in_memory()?
  25. };
  26. if let Some(password) = config.password.as_ref() {
  27. conn.execute_batch(&format!("pragma key = '{password}';"))?;
  28. }
  29. conn.execute_batch(
  30. r#"
  31. pragma busy_timeout = 10000;
  32. pragma journal_mode = WAL;
  33. pragma synchronous = normal;
  34. pragma temp_store = memory;
  35. pragma mmap_size = 30000000000;
  36. pragma cache = shared;
  37. "#,
  38. )?;
  39. conn.busy_timeout(Duration::from_secs(10))?;
  40. Ok(conn)
  41. }
  42. }
  43. /// Create a configured rusqlite connection to a SQLite database.
  44. /// For SQLCipher support, enable the "sqlcipher" feature and pass a password.
  45. pub fn create_sqlite_pool(
  46. path: &str,
  47. #[cfg(feature = "sqlcipher")] password: String,
  48. ) -> Arc<Pool<SqliteConnectionManager>> {
  49. #[cfg(feature = "sqlcipher")]
  50. let password = Some(password);
  51. #[cfg(not(feature = "sqlcipher"))]
  52. let password = None;
  53. let (config, max_size) = if path.contains(":memory:") {
  54. (
  55. Config {
  56. path: None,
  57. password,
  58. },
  59. 1,
  60. )
  61. } else {
  62. (
  63. Config {
  64. path: Some(path.to_owned()),
  65. password,
  66. },
  67. 20,
  68. )
  69. };
  70. Pool::new(config, max_size, Duration::from_secs(10))
  71. }
  72. /// Migrates the migration generated by `build.rs`
  73. pub fn migrate(conn: &mut Connection, migrations: &[(&str, &str)]) -> Result<(), rusqlite::Error> {
  74. let tx = conn.transaction()?;
  75. tx.execute(
  76. r#"
  77. CREATE TABLE IF NOT EXISTS migrations (
  78. name TEXT PRIMARY KEY,
  79. applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  80. )
  81. "#,
  82. [],
  83. )?;
  84. if tx.query_row(
  85. r#"select count(*) from sqlite_master where name = '_sqlx_migrations'"#,
  86. [],
  87. |row| row.get::<_, i32>(0),
  88. )? == 1
  89. {
  90. tx.execute_batch(
  91. r#"
  92. INSERT INTO migrations
  93. SELECT
  94. version || '_' || REPLACE(description, ' ', '_') || '.sql',
  95. execution_time
  96. FROM _sqlx_migrations;
  97. DROP TABLE _sqlx_migrations;
  98. "#,
  99. )?;
  100. }
  101. // Apply each migration if it hasn’t been applied yet
  102. for (name, sql) in migrations {
  103. let already_applied: bool = tx.query_row(
  104. "SELECT EXISTS(SELECT 1 FROM migrations WHERE name = ?1)",
  105. params![name],
  106. |row| row.get(0),
  107. )?;
  108. if !already_applied {
  109. tx.execute_batch(sql)?;
  110. tx.execute("INSERT INTO migrations (name) VALUES (?1)", params![name])?;
  111. }
  112. }
  113. tx.commit()?;
  114. Ok(())
  115. }