use std::io;
use std::path::Path;
use yog_data::Schema;
use yog_sync::{Arc, Mutex};
use crate::Scope;
use crate::shelf::{self, Shelf};
#[derive(Clone)]
pub struct Store {
shelf: Arc<Mutex<Shelf>>,
}
impl Store {
pub fn open(root: &Path, mod_id: &str, scope: Scope<'_>) -> Self {
Store {
shelf: shelf::file(scope.path(root, mod_id)),
}
}
pub fn session(mod_id: &str) -> Self {
Store {
shelf: shelf::session(mod_id),
}
}
pub fn get<T: Schema>(&self, key: &str) -> Option<T> {
yog_data::read_value(self.shelf.lock().values.get(key)?).ok()
}
pub fn get_or_default<T: Schema + Default>(&self, key: &str) -> T {
self.get(key).unwrap_or_default()
}
pub fn set<T: Schema>(&self, key: &str, value: &T) {
let mut shelf = self.shelf.lock();
shelf.values.insert(key, value.write());
shelf.dirty = true;
}
pub fn record(&self, key: &str) -> Option<Vec<u8>> {
match self.shelf.lock().values.get(key)? {
yog_data::Value::Bytes(bytes) => Some(bytes.clone()),
_ => None,
}
}
pub fn set_record(&self, key: &str, bytes: &[u8]) {
let mut shelf = self.shelf.lock();
shelf.dirty = true;
if let Some(yog_data::Value::Bytes(old)) = shelf.values.get_mut(key) {
old.clear();
old.extend_from_slice(bytes);
return;
}
shelf
.values
.insert(key, yog_data::Value::Bytes(bytes.to_vec()));
}
pub fn remove_under(&self, prefix: &str) -> usize {
let mut shelf = self.shelf.lock();
let before = shelf.values.len();
shelf.values.retain(|k, _| !k.starts_with(prefix));
let removed = before - shelf.values.len();
shelf.dirty |= removed > 0;
removed
}
pub fn update<T: Schema + Default, R>(&self, key: &str, change: impl FnOnce(&mut T) -> R) -> R {
let mut value = self.get_or_default(key);
let out = change(&mut value);
self.set(key, &value);
out
}
pub fn remove(&self, key: &str) -> bool {
let mut shelf = self.shelf.lock();
let removed = shelf.values.remove(key).is_some();
shelf.dirty |= removed;
removed
}
pub fn contains(&self, key: &str) -> bool {
self.shelf.lock().values.get(key).is_some()
}
pub fn keys(&self) -> Vec<String> {
self.shelf.lock().values.keys().map(str::to_owned).collect()
}
pub fn flush(&self) -> io::Result<()> {
self.shelf.lock().flush()
}
}