use crate::relational::error::Result;
use async_trait::async_trait;
use serde_json::Value as Json;
use std::collections::BTreeMap;
use std::sync::RwLock;
pub const CATALOG_COLLECTION: &str = "__gdb_sql_catalog";
#[async_trait]
pub trait RelationalStorage: Send + Sync {
async fn scan(&self, collection: &str) -> Result<Vec<(String, Json)>>;
async fn get(&self, collection: &str, row_id: &str) -> Result<Option<Json>>;
async fn put(&self, collection: &str, row_id: &str, doc: &Json) -> Result<()>;
async fn delete(&self, collection: &str, row_id: &str) -> Result<()>;
async fn truncate(&self, collection: &str) -> Result<()>;
async fn load_catalog(&self) -> Result<Option<Json>>;
async fn save_catalog(&self, catalog: &Json) -> Result<()>;
}
#[derive(Debug, Default)]
pub struct MemoryStorage {
collections: RwLock<BTreeMap<String, BTreeMap<String, Json>>>,
catalog: RwLock<Option<Json>>,
}
impl MemoryStorage {
pub fn new() -> Self {
Self::default()
}
pub fn count(&self, collection: &str) -> usize {
self.collections
.read()
.unwrap()
.get(collection)
.map(|c| c.len())
.unwrap_or(0)
}
}
#[async_trait]
impl RelationalStorage for MemoryStorage {
async fn scan(&self, collection: &str) -> Result<Vec<(String, Json)>> {
Ok(self
.collections
.read()
.unwrap()
.get(collection)
.map(|c| c.iter().map(|(k, v)| (k.clone(), v.clone())).collect())
.unwrap_or_default())
}
async fn get(&self, collection: &str, row_id: &str) -> Result<Option<Json>> {
Ok(self
.collections
.read()
.unwrap()
.get(collection)
.and_then(|c| c.get(row_id).cloned()))
}
async fn put(&self, collection: &str, row_id: &str, doc: &Json) -> Result<()> {
self.collections
.write()
.unwrap()
.entry(collection.to_string())
.or_default()
.insert(row_id.to_string(), doc.clone());
Ok(())
}
async fn delete(&self, collection: &str, row_id: &str) -> Result<()> {
if let Some(c) = self.collections.write().unwrap().get_mut(collection) {
c.remove(row_id);
}
Ok(())
}
async fn truncate(&self, collection: &str) -> Result<()> {
if let Some(c) = self.collections.write().unwrap().get_mut(collection) {
c.clear();
}
Ok(())
}
async fn load_catalog(&self) -> Result<Option<Json>> {
Ok(self.catalog.read().unwrap().clone())
}
async fn save_catalog(&self, catalog: &Json) -> Result<()> {
*self.catalog.write().unwrap() = Some(catalog.clone());
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[tokio::test]
async fn memory_storage_crud() {
let s = MemoryStorage::new();
s.put("c", "1", &json!({"a": 1})).await.unwrap();
s.put("c", "2", &json!({"a": 2})).await.unwrap();
assert_eq!(s.scan("c").await.unwrap().len(), 2);
assert_eq!(s.get("c", "1").await.unwrap(), Some(json!({"a": 1})));
s.delete("c", "1").await.unwrap();
assert_eq!(s.scan("c").await.unwrap().len(), 1);
s.truncate("c").await.unwrap();
assert_eq!(s.scan("c").await.unwrap().len(), 0);
}
#[tokio::test]
async fn memory_storage_catalog() {
let s = MemoryStorage::new();
assert!(s.load_catalog().await.unwrap().is_none());
s.save_catalog(&json!({"v": 1})).await.unwrap();
assert_eq!(s.load_catalog().await.unwrap(), Some(json!({"v": 1})));
}
}