use serde::de::DeserializeOwned;
use serde::Serialize;
use std::io::Seek;
use std::io::Write;
use std::marker::PhantomData;
use std::path::Path;
use crate::{Batch, BatchCommit, JSStore, Ref};
pub trait Index<K, V>
where
K: Eq + Ord + Serialize + DeserializeOwned,
V: Serialize + DeserializeOwned,
{
fn insert(&mut self, key: K, value: V);
fn remove(&mut self, key: K, value: V);
}
pub struct JSStoreWithIndex<K, V, I>(JSStore<K, V>, I);
impl<
K: DeserializeOwned + Eq + Ord + Serialize + Clone,
V: DeserializeOwned + Serialize + Clone,
I: Index<K, V>,
> JSStoreWithIndex<K, V, I>
{
pub fn new<P: AsRef<Path>>(
filename: P,
mut index: I,
) -> Result<JSStoreWithIndex<K, V, I>, std::io::Error> {
let store = JSStore::new(filename)?;
for (key, value) in store.iter() {
index.insert(key, value)
}
Ok(JSStoreWithIndex(store, index))
}
pub fn insert<Key: Into<K>>(&mut self, k: Key, v: V) -> Result<(), std::io::Error> {
let k = k.into();
self.0.insert(k.clone(), v.clone())?;
self.1.insert(k, v);
Ok(())
}
pub fn remove<Key: Into<K>>(&mut self, k: Key) -> Result<(), std::io::Error> {
let k = k.into();
let v = self.0.get(k.clone())?;
match v {
Some(v) => {
self.0.remove(k.clone())?;
self.1.remove(k, v);
Ok(())
}
None => Ok(()),
}
}
pub fn basedb(&self) -> &JSStore<K, V> {
&self.0
}
pub fn batch(&mut self) -> Batch<JSStoreWithIndex<K, V, I>, K, V> {
Batch::new(self)
}
pub fn index(&self) -> &I {
&self.1
}
}
impl<K, V, I> BatchCommit<K, V> for JSStoreWithIndex<K, V, I>
where
K: Eq + Ord + Serialize + DeserializeOwned + Clone,
V: Serialize + DeserializeOwned,
I: Index<K, V>,
{
fn commit(&mut self, oplist: Vec<(K, Option<V>)>) -> Result<(), std::io::Error> {
let mut file = &self.0 .1;
let v: Vec<(K, Option<V>)> = oplist;
file.seek(std::io::SeekFrom::End(0))?;
let offset = file.stream_position()?;
file.write_all(b"\n")?;
let buf = serde_json::to_vec(&v).unwrap();
file.write_all(&buf)?;
for (key, value) in v {
match value {
Some(value) => {
self.0 .0.insert(
key.clone(),
Ref {
start: offset as usize,
length: buf.len() + 1,
p: PhantomData,
},
);
self.1.insert(key, value);
}
None => {
let value = self.0.get(key.clone())?;
if let Some(value) = value {
self.0 .0.remove(&key);
self.1.remove(key, value);
}
}
}
}
Ok(())
}
}