use std::collections::{BTreeMap, HashMap};
use crate::persist::adaptor::{Query, QueryRange, Record, StorageAdaptor, StorageAdaptorWrapper};
#[derive(Debug, Default)]
pub struct MemoryStorageAdaptor {
partitions: HashMap<u8, BTreeMap<Vec<u8>, Record>>,
}
impl MemoryStorageAdaptor {
pub fn new() -> Self {
Self::default()
}
pub fn partitions(&self) -> &HashMap<u8, BTreeMap<Vec<u8>, Record>> {
&self.partitions
}
}
impl StorageAdaptorWrapper<MemoryStorageAdaptor> {
pub fn new_memory() -> Self {
Self::new(MemoryStorageAdaptor::new())
}
}
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
impl StorageAdaptor for MemoryStorageAdaptor {
async fn put(&mut self, record: Record) -> anyhow::Result<()> {
let partition = self.partitions.entry(record.partition).or_default();
partition.insert(record.pk.clone(), record);
Ok(())
}
async fn get(&self, partition: u8, pk: &[u8]) -> anyhow::Result<Option<Record>> {
if let Some(partition) = self.partitions.get(&partition) {
if let Some(record) = partition.get(pk) {
return Ok(Some(record.clone()));
}
}
Ok(None)
}
async fn delete(&mut self, partition: u8, pk: &[u8]) -> anyhow::Result<Option<Record>> {
if let Some(partition) = self.partitions.get_mut(&partition) {
return Ok(partition.remove(pk))
}
Ok(None)
}
async fn query_sorted<R: QueryRange>(&self, query: Query<R>) -> anyhow::Result<Vec<Record>> {
let Some(partition) = self.partitions.get(&query.partition) else {
return Ok(Vec::new());
};
let mut results: Vec<_> = partition
.values()
.filter(|r| {
let Some(sort_key) = &r.sort_key else {
return false;
};
query.range.contains(sort_key)
})
.cloned()
.collect();
results.sort_by(|a, b| {
match (&a.sort_key, &b.sort_key) {
(Some(ka), Some(kb)) => ka.cmp(kb),
_ => unreachable!("all records should have sort keys after filtering"),
}
});
if let Some(limit) = query.limit {
results.truncate(limit);
}
Ok(results)
}
async fn get_all(&self, partition: u8) -> anyhow::Result<Vec<Record>> {
let Some(partition_map) = self.partitions.get(&partition) else {
return Ok(Vec::new());
};
Ok(partition_map.values().cloned().collect())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::persist::adaptor::test_suite;
#[cfg_attr(not(target_arch = "wasm32"), tokio::test)]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
async fn memory_adaptor_full_test_suite() {
let mut storage = MemoryStorageAdaptor::new();
test_suite::run_all(&mut storage).await;
}
}