Skip to main content

kanban_persistence_sqlite/
lib.rs

1pub mod sqlite_store;
2
3pub use sqlite_store::SqliteStore;
4
5use kanban_persistence::{PersistenceError, PersistenceStore, StoreFactory};
6use std::sync::Arc;
7
8pub struct SqliteStoreFactory;
9
10impl StoreFactory for SqliteStoreFactory {
11    fn name(&self) -> &str {
12        "sqlite"
13    }
14
15    fn matches_content(&self, header: &[u8]) -> bool {
16        header.starts_with(b"SQLite format 3\0")
17    }
18
19    fn create(
20        &self,
21        locator: &str,
22    ) -> Result<Arc<dyn PersistenceStore + Send + Sync>, PersistenceError> {
23        let handle = tokio::runtime::Handle::current();
24        if handle.runtime_flavor() == tokio::runtime::RuntimeFlavor::CurrentThread {
25            return Err(PersistenceError::Database(
26                "SqliteStoreFactory::create requires a multi-thread Tokio runtime; \
27                 block_in_place is unavailable on a current_thread runtime. \
28                 Use #[tokio::test(flavor = \"multi_thread\")] in tests."
29                    .to_string(),
30            ));
31        }
32        let store = tokio::task::block_in_place(|| handle.block_on(SqliteStore::open(locator)))
33            .map_err(|e| PersistenceError::Database(e.to_string()))?;
34        Ok(Arc::new(store))
35    }
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41    use kanban_persistence::StoreFactory;
42
43    #[test]
44    fn test_sqlite_factory_matches_content_sqlite_magic_bytes() {
45        let header = b"SQLite format 3\0extra";
46        assert!(SqliteStoreFactory.matches_content(header));
47    }
48
49    #[test]
50    fn test_sqlite_factory_matches_content_rejects_json() {
51        let header = b"{\"boards\": []}";
52        assert!(!SqliteStoreFactory.matches_content(header));
53    }
54
55    #[test]
56    fn test_sqlite_factory_matches_content_rejects_empty() {
57        assert!(!SqliteStoreFactory.matches_content(b""));
58    }
59
60    #[test]
61    fn test_sqlite_factory_name_is_sqlite() {
62        assert_eq!(SqliteStoreFactory.name(), "sqlite");
63    }
64
65    #[tokio::test(flavor = "multi_thread")]
66    async fn test_sqlite_factory_create_returns_persistence_store() {
67        let dir = tempfile::tempdir().unwrap();
68        let path = dir.path().join("test.db");
69        let store = SqliteStoreFactory.create(path.to_str().unwrap()).unwrap();
70        assert!(store.exists().await);
71    }
72}