|
|
|
@ -6,13 +6,346 @@ |
|
|
|
|
// notice may not be copied, modified, or distributed except
|
|
|
|
|
// according to those terms.
|
|
|
|
|
|
|
|
|
|
//! KeyColumnValue Store abstraction
|
|
|
|
|
//! KeyColumnValue Storage abstraction
|
|
|
|
|
|
|
|
|
|
use std::collections::HashMap; |
|
|
|
|
use std::{collections::HashSet, marker::PhantomData}; |
|
|
|
|
|
|
|
|
|
use crate::errors::StorageError; |
|
|
|
|
use serde::{Deserialize, Serialize}; |
|
|
|
|
use serde_bare::{from_slice, to_vec}; |
|
|
|
|
|
|
|
|
|
// TODO:remove mut on self for trait WriteTransaction methods
|
|
|
|
|
pub fn prop<A>(prop: u8, props: &HashMap<u8, Vec<u8>>) -> Result<A, StorageError> |
|
|
|
|
where |
|
|
|
|
A: for<'a> Deserialize<'a>, |
|
|
|
|
{ |
|
|
|
|
Ok(from_slice( |
|
|
|
|
&props.get(&prop).ok_or(StorageError::PropertyNotFound)?, |
|
|
|
|
)?) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub struct Class<'a> { |
|
|
|
|
columns: Vec<&'a dyn ISingleValueColumn>, |
|
|
|
|
multi_value_columns: Vec<&'a dyn IMultiValueColumn>, |
|
|
|
|
existential_column: &'a dyn ISingleValueColumn, |
|
|
|
|
prefix: u8, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl<'a> Class<'a> { |
|
|
|
|
pub fn new( |
|
|
|
|
prefix: u8, |
|
|
|
|
existential_column: &'a dyn ISingleValueColumn, |
|
|
|
|
columns: Vec<&'a dyn ISingleValueColumn>, |
|
|
|
|
multi_value_columns: Vec<&'a dyn IMultiValueColumn>, |
|
|
|
|
) -> Self { |
|
|
|
|
// check unicity of prefixes and suffixes
|
|
|
|
|
#[cfg(test)] |
|
|
|
|
{ |
|
|
|
|
let mut prefixes = HashSet::from([prefix]); |
|
|
|
|
let mut suffixes = HashSet::from([existential_column.suffix()]); |
|
|
|
|
for column in columns.iter() { |
|
|
|
|
if !suffixes.insert(column.suffix()) { |
|
|
|
|
panic!("duplicate suffix {} !!! check the code", column.suffix()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
for mvc in multi_value_columns.iter() { |
|
|
|
|
if !prefixes.insert(mvc.prefix()) { |
|
|
|
|
panic!("duplicate prefix {} !!! check the code", mvc.prefix()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Self { |
|
|
|
|
columns, |
|
|
|
|
multi_value_columns, |
|
|
|
|
prefix, |
|
|
|
|
existential_column, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
fn suffices(&self) -> Vec<u8> { |
|
|
|
|
let mut res: Vec<u8> = self.columns.iter().map(|c| c.suffix()).collect(); |
|
|
|
|
res.push(self.existential_column.suffix()); |
|
|
|
|
res |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub trait IModel { |
|
|
|
|
fn key(&self) -> &Vec<u8>; |
|
|
|
|
fn prefix(&self) -> u8 { |
|
|
|
|
self.class().prefix |
|
|
|
|
} |
|
|
|
|
fn check_exists(&mut self) -> Result<(), StorageError> { |
|
|
|
|
if !self.exists() { |
|
|
|
|
return Err(StorageError::NotFound); |
|
|
|
|
} |
|
|
|
|
Ok(()) |
|
|
|
|
} |
|
|
|
|
fn existential(&mut self) -> &mut dyn IExistentialValue; |
|
|
|
|
fn exists(&mut self) -> bool { |
|
|
|
|
if self.existential().exists() { |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
let prefix = self.prefix(); |
|
|
|
|
let key = self.key(); |
|
|
|
|
let suffix = self.class().existential_column.suffix(); |
|
|
|
|
match self.storage().get(prefix, key, Some(suffix), &None) { |
|
|
|
|
Ok(res) => { |
|
|
|
|
self.existential().process_exists(res); |
|
|
|
|
true |
|
|
|
|
} |
|
|
|
|
Err(e) => false, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
fn storage(&self) -> &dyn KCVStorage; |
|
|
|
|
fn load_props(&self) -> Result<HashMap<u8, Vec<u8>>, StorageError> { |
|
|
|
|
self.storage().get_all_properties_of_key( |
|
|
|
|
self.prefix(), |
|
|
|
|
self.key().to_vec(), |
|
|
|
|
self.class().suffices(), |
|
|
|
|
&None, |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
fn class(&self) -> &Class; |
|
|
|
|
fn del(&self) -> Result<(), StorageError> { |
|
|
|
|
self.storage().write_transaction(&mut |tx| { |
|
|
|
|
tx.del_all(self.prefix(), self.key(), &self.class().suffices(), &None)?; |
|
|
|
|
for mvc in self.class().multi_value_columns.iter() { |
|
|
|
|
let size = mvc.value_size()?; |
|
|
|
|
tx.del_all_values(self.prefix(), self.key(), size, None, &None)?; |
|
|
|
|
} |
|
|
|
|
Ok(()) |
|
|
|
|
})?; |
|
|
|
|
Ok(()) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
use std::hash::Hash; |
|
|
|
|
pub struct MultiValueColumn< |
|
|
|
|
Model: IModel, |
|
|
|
|
Column: Eq + PartialEq + Hash + Serialize + Default + for<'a> Deserialize<'a>, |
|
|
|
|
> { |
|
|
|
|
prefix: u8, |
|
|
|
|
phantom: PhantomData<Column>, |
|
|
|
|
model: PhantomData<Model>, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl< |
|
|
|
|
Model: IModel, |
|
|
|
|
Column: Eq + PartialEq + Hash + Serialize + Default + for<'d> Deserialize<'d>, |
|
|
|
|
> MultiValueColumn<Model, Column> |
|
|
|
|
{ |
|
|
|
|
pub fn new(prefix: u8) -> Self { |
|
|
|
|
MultiValueColumn { |
|
|
|
|
prefix, |
|
|
|
|
phantom: PhantomData, |
|
|
|
|
model: PhantomData, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
pub fn add(&self, model: &mut Model, column: &Column) -> Result<(), StorageError> { |
|
|
|
|
model.check_exists()?; |
|
|
|
|
model |
|
|
|
|
.storage() |
|
|
|
|
.put(self.prefix, model.key(), None, &to_vec(column)?, &None) |
|
|
|
|
} |
|
|
|
|
pub fn remove(&self, model: &mut Model, column: &Column) -> Result<(), StorageError> { |
|
|
|
|
model.check_exists()?; |
|
|
|
|
model |
|
|
|
|
.storage() |
|
|
|
|
.del_property_value(self.prefix, model.key(), None, &to_vec(column)?, &None) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn has(&self, model: &mut Model, column: &Column) -> Result<(), StorageError> { |
|
|
|
|
model.check_exists()?; |
|
|
|
|
model |
|
|
|
|
.storage() |
|
|
|
|
.has_property_value(self.prefix, model.key(), None, &to_vec(column)?, &None) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn get_all(&self, model: &mut Model) -> Result<HashSet<Column>, StorageError> { |
|
|
|
|
model.check_exists()?; |
|
|
|
|
let key_prefix = model.key(); |
|
|
|
|
let value_size = to_vec(&Column::default())?.len(); |
|
|
|
|
|
|
|
|
|
let mut res: HashSet<Column> = HashSet::new(); |
|
|
|
|
let total_size = key_prefix.len() + value_size; |
|
|
|
|
for user in model.storage().get_all_keys_and_values( |
|
|
|
|
self.prefix, |
|
|
|
|
total_size, |
|
|
|
|
key_prefix.to_vec(), |
|
|
|
|
None, |
|
|
|
|
&None, |
|
|
|
|
)? { |
|
|
|
|
if user.0.len() == total_size + 1 { |
|
|
|
|
let user: Column = from_slice(&user.0[1..user.0.len()])?; |
|
|
|
|
res.insert(user); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Ok(res) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
impl< |
|
|
|
|
Model: IModel, |
|
|
|
|
Column: Eq + PartialEq + Hash + Serialize + Default + for<'d> Deserialize<'d>, |
|
|
|
|
> IMultiValueColumn for MultiValueColumn<Model, Column> |
|
|
|
|
{ |
|
|
|
|
fn value_size(&self) -> Result<usize, StorageError> { |
|
|
|
|
Ok(to_vec(&Column::default())?.len()) |
|
|
|
|
} |
|
|
|
|
fn prefix(&self) -> u8 { |
|
|
|
|
self.prefix |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub trait ISingleValueColumn { |
|
|
|
|
fn suffix(&self) -> u8; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub trait IMultiValueColumn { |
|
|
|
|
fn prefix(&self) -> u8; |
|
|
|
|
fn value_size(&self) -> Result<usize, StorageError>; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub struct SingleValueColumn<Model: IModel, Column: Serialize + for<'a> Deserialize<'a>> { |
|
|
|
|
suffix: u8, |
|
|
|
|
phantom: PhantomData<Column>, |
|
|
|
|
model: PhantomData<Model>, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl<Model: IModel, Column: Serialize + for<'d> Deserialize<'d>> ISingleValueColumn |
|
|
|
|
for SingleValueColumn<Model, Column> |
|
|
|
|
{ |
|
|
|
|
fn suffix(&self) -> u8 { |
|
|
|
|
self.suffix |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub struct ExistentialValueColumn { |
|
|
|
|
suffix: u8, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl ISingleValueColumn for ExistentialValueColumn { |
|
|
|
|
fn suffix(&self) -> u8 { |
|
|
|
|
self.suffix |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl ExistentialValueColumn { |
|
|
|
|
pub fn new(suffix: u8) -> Self { |
|
|
|
|
ExistentialValueColumn { suffix } |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl<Model: IModel, Column: Serialize + for<'d> Deserialize<'d>> SingleValueColumn<Model, Column> { |
|
|
|
|
pub fn new(suffix: u8) -> Self { |
|
|
|
|
SingleValueColumn { |
|
|
|
|
suffix, |
|
|
|
|
phantom: PhantomData, |
|
|
|
|
model: PhantomData, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn set(&self, model: &mut Model, column: &Column) -> Result<(), StorageError> { |
|
|
|
|
model.check_exists()?; |
|
|
|
|
model.storage().replace( |
|
|
|
|
model.prefix(), |
|
|
|
|
model.key(), |
|
|
|
|
Some(self.suffix), |
|
|
|
|
&to_vec(column)?, |
|
|
|
|
&None, |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
pub fn get(&self, model: &mut Model) -> Result<Column, StorageError> { |
|
|
|
|
model.check_exists()?; |
|
|
|
|
match model |
|
|
|
|
.storage() |
|
|
|
|
.get(model.prefix(), model.key(), Some(self.suffix), &None) |
|
|
|
|
{ |
|
|
|
|
Ok(res) => Ok(from_slice::<Column>(&res)?), |
|
|
|
|
Err(e) => Err(e), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn has(&self, model: &mut Model, column: &Column) -> Result<(), StorageError> { |
|
|
|
|
model.check_exists()?; |
|
|
|
|
model.storage().has_property_value( |
|
|
|
|
model.prefix(), |
|
|
|
|
model.key(), |
|
|
|
|
Some(self.suffix), |
|
|
|
|
&to_vec(column)?, |
|
|
|
|
&None, |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn del( |
|
|
|
|
&self, |
|
|
|
|
model: &mut Model, |
|
|
|
|
tx: &mut dyn WriteTransaction, |
|
|
|
|
) -> Result<(), StorageError> { |
|
|
|
|
tx.del(model.prefix(), model.key(), Some(self.suffix), &None) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub struct ExistentialValue<Column: Serialize + for<'d> Deserialize<'d>> { |
|
|
|
|
value: Option<Column>, |
|
|
|
|
value_ser: Vec<u8>, |
|
|
|
|
} |
|
|
|
|
pub trait IExistentialValue { |
|
|
|
|
fn process_exists(&mut self, value_ser: Vec<u8>); |
|
|
|
|
|
|
|
|
|
fn exists(&self) -> bool; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl<Column: Serialize + for<'d> Deserialize<'d>> IExistentialValue for ExistentialValue<Column> { |
|
|
|
|
fn exists(&self) -> bool { |
|
|
|
|
self.value.is_some() || self.value_ser.len() > 0 |
|
|
|
|
} |
|
|
|
|
fn process_exists(&mut self, value_ser: Vec<u8>) { |
|
|
|
|
self.value_ser = value_ser; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl<Column: Clone + Serialize + for<'d> Deserialize<'d>> ExistentialValue<Column> { |
|
|
|
|
pub fn new() -> Self { |
|
|
|
|
ExistentialValue { |
|
|
|
|
value: None, |
|
|
|
|
value_ser: vec![], |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn set<Model: IModel>( |
|
|
|
|
&mut self, |
|
|
|
|
value: &Column, |
|
|
|
|
model: &Model, |
|
|
|
|
) -> Result<(), StorageError> { |
|
|
|
|
if self.value.is_some() { |
|
|
|
|
return Err(StorageError::AlreadyExists); |
|
|
|
|
} |
|
|
|
|
model.storage().replace( |
|
|
|
|
model.prefix(), |
|
|
|
|
model.key(), |
|
|
|
|
Some(model.class().existential_column.suffix()), |
|
|
|
|
&to_vec(value)?, |
|
|
|
|
&None, |
|
|
|
|
)?; |
|
|
|
|
self.value = Some(value.clone()); |
|
|
|
|
Ok(()) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn get(&mut self) -> Result<&Column, StorageError> { |
|
|
|
|
if self.value.is_some() { |
|
|
|
|
return Ok(self.value.as_ref().unwrap()); |
|
|
|
|
} |
|
|
|
|
if self.value_ser.len() == 0 { |
|
|
|
|
return Err(StorageError::BackendError); |
|
|
|
|
} |
|
|
|
|
let value = from_slice::<Column>(&self.value_ser); |
|
|
|
|
match value { |
|
|
|
|
Err(_) => return Err(StorageError::InvalidValue), |
|
|
|
|
Ok(val) => { |
|
|
|
|
self.value = Some(val); |
|
|
|
|
return Ok(self.value.as_ref().unwrap()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub trait WriteTransaction: ReadTransaction { |
|
|
|
|
/// Save a property value to the store.
|
|
|
|
|