use std::sync::Arc;
use spacedb_store::{Collection, Durability, KeyProvider, KvEngine, WriteTx};
use crate::{CrdtDoc, CrdtResult};
pub const CRDT_DOCS_COLLECTION: &str = "crdt_docs";
const SCHEMA_VERSION: u32 = 1;
pub struct CrdtStore {
docs: Collection<String, Vec<u8>>,
}
impl CrdtStore {
pub fn open<E: KvEngine>(engine: &E, key_provider: Arc<dyn KeyProvider>) -> CrdtResult<Self> {
let docs =
Collection::open_or_create(engine, key_provider, CRDT_DOCS_COLLECTION, SCHEMA_VERSION)?;
Ok(Self { docs })
}
pub fn save<E: KvEngine>(&self, engine: &E, doc_id: &str, doc: &CrdtDoc) -> CrdtResult<()> {
let state = doc.encode_full();
let mut w = engine.begin_write(Durability::Immediate)?;
self.docs.put(&mut w, &doc_id.to_string(), &state)?;
w.commit()?;
Ok(())
}
pub fn load<E: KvEngine>(
&self,
engine: &E,
doc_id: &str,
actor_id: u64,
) -> CrdtResult<CrdtDoc> {
let stored = {
let r = engine.begin_read()?;
self.docs.get(&r, &doc_id.to_string())?
};
let doc = CrdtDoc::new(actor_id);
if let Some(state) = stored {
doc.apply_update(&state)?;
}
Ok(doc)
}
pub fn apply_remote<E: KvEngine>(
&self,
engine: &E,
doc_id: &str,
actor_id: u64,
update: &[u8],
) -> CrdtResult<CrdtDoc> {
let doc = self.load(engine, doc_id, actor_id)?;
doc.apply_update(update)?;
self.save(engine, doc_id, &doc)?;
Ok(doc)
}
pub fn contains<E: KvEngine>(&self, engine: &E, doc_id: &str) -> CrdtResult<bool> {
let r = engine.begin_read()?;
Ok(self.docs.get(&r, &doc_id.to_string())?.is_some())
}
}