// Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers // Licensed under the Apache License, Version 2.0 // // or the MIT license , // at your option. All files in the project carrying such // notice may not be copied, modified, or distributed except // according to those terms. //! KeyColumnValue Storage abstraction use std::{ collections::{HashMap, HashSet}, marker::PhantomData, }; use serde::{Deserialize, Serialize}; use serde_bare::{from_slice, to_vec}; use crate::errors::StorageError; #[allow(unused_imports)] use crate::log::*; pub fn prop(prop: u8, props: &HashMap>) -> Result where A: for<'a> Deserialize<'a>, { Ok(from_slice( &props.get(&prop).ok_or(StorageError::PropertyNotFound)?, )?) } pub fn col( column: &dyn ISingleValueColumn, props: &HashMap>, ) -> Result where A: for<'a> Deserialize<'a>, { Ok(from_slice( &props .get(&column.suffix()) .ok_or(StorageError::PropertyNotFound)?, )?) } pub struct Class<'a> { prefix: Option, pub name: &'static str, existential_column: Option<&'a dyn ISingleValueColumn>, columns: &'a [&'a dyn ISingleValueColumn], multi_value_columns: &'a [&'a dyn IMultiValueColumn], } impl<'a> Class<'a> { pub const fn new( name: &'static str, prefix: Option, existential_column: Option<&'a dyn ISingleValueColumn>, columns: &'a [&'a dyn ISingleValueColumn], multi_value_columns: &'a [&'a dyn IMultiValueColumn], ) -> Self { if prefix.is_none() { if existential_column.is_some() { panic!("cannot have an existential_column without a prefix"); } if columns.len() > 0 { panic!("cannot have some property columns without a prefix"); } } Self { columns, name, multi_value_columns, prefix, existential_column, } } /// check unicity of prefixes and suffixes #[cfg(debug_assertions)] pub fn check(&self) { let mut prefixes = if self.prefix.is_some() { HashSet::from([self.prefix.unwrap()]) } else { HashSet::new() }; let mut suffixes = if self.existential_column.is_some() { HashSet::from([self.existential_column.unwrap().suffix()]) } else { HashSet::new() }; let name = self.name; //log_debug!("CHECKING CLASS {name}"); for column in self.columns.iter() { //log_debug!("INSERTING SUFFIX {}", column.suffix()); if !suffixes.insert(column.suffix()) { panic!( "duplicate suffix {} in {name}!!! check the code", column.suffix() as char ); } } //log_debug!("SUFFIXES {:?}", suffixes); for mvc in self.multi_value_columns.iter() { //log_debug!("INSERTING PREFIX {}", mvc.prefix()); if !prefixes.insert(mvc.prefix()) { panic!( "duplicate prefix {} in {name}!!! check the code", mvc.prefix() as char ); } } //log_debug!("PREFIXES {:?}", prefixes); } pub fn prefixes(&self) -> Vec { let mut res: Vec = self .multi_value_columns .iter() .map(|c| c.prefix()) .collect(); if self.prefix.is_some() { res.push(self.prefix.unwrap()); } res } fn suffices(&self) -> Vec { let mut res: Vec = self.columns.iter().map(|c| c.suffix()).collect(); if self.existential_column.is_some() { res.push(self.existential_column.unwrap().suffix()); } res } } pub fn format_type_of(_: &T) -> String { format!("{}", std::any::type_name::()) } pub trait IModel { fn key(&self) -> &Vec; fn prefix(&self) -> u8 { self.class().prefix.unwrap() } fn check_exists(&mut self) -> Result<(), StorageError> { if !self.exists() { return Err(StorageError::NotFound); } Ok(()) } fn existential(&mut self) -> Option<&mut dyn IExistentialValue>; fn exists(&mut self) -> bool { if self.existential().is_none() || self.class().existential_column.is_none() { return true; } if self.existential().as_mut().unwrap().exists() { return true; } let prefix = self.prefix(); let key = self.key(); let suffix = self.class().existential_column.unwrap().suffix(); // log_info!( // "EXISTENTIAL CHECK {} {} {:?}", // prefix as char, // suffix as char, // key // ); match self.storage().get(prefix, key, Some(suffix), &None) { Ok(res) => { //log_info!("EXISTENTIAL CHECK GOT {:?}", res); self.existential().as_mut().unwrap().process_exists(res); true } Err(_e) => false, } } fn storage(&self) -> &dyn KCVStorage; fn load_props(&self) -> Result>, StorageError> { if self.class().prefix.is_none() { panic!("cannot call load_props on a Class without prefix"); } 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| { if self.class().prefix.is_some() { 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(mvc.prefix(), self.key(), size, None, &None)?; } Ok(()) })?; Ok(()) } } use std::hash::Hash; pub struct MultiValueColumn< Model: IModel, Column: std::fmt::Debug + Eq + PartialEq + Hash + Serialize + Default + for<'a> Deserialize<'a>, > { prefix: u8, phantom: PhantomData, model: PhantomData, //value_size: usize, } impl< Model: IModel, Column: std::fmt::Debug + Eq + PartialEq + Hash + Serialize + Default + for<'d> Deserialize<'d>, > MultiValueColumn { pub const fn new(prefix: u8) -> Self { MultiValueColumn { prefix, phantom: PhantomData, model: PhantomData, } } fn compute_key(model: &Model, column: &Column) -> Result, StorageError> { let model_key = model.key(); let mut column_ser = to_vec(column)?; let mut key = Vec::with_capacity(model_key.len() + column_ser.len()); key.append(&mut model_key.to_vec()); key.append(&mut column_ser); Ok(key) } pub fn add(&self, model: &mut Model, column: &Column) -> Result<(), StorageError> { model.check_exists()?; let key = Self::compute_key(model, column)?; model.storage().put(self.prefix, &key, None, &vec![], &None) } pub fn add_lazy(&self, model: &mut Model, column: &Column) -> Result<(), StorageError> { model.check_exists()?; let key = Self::compute_key(model, column)?; model.storage().write_transaction(&mut |tx| { match tx.has_property_value(self.prefix, &key, None, &vec![], &None) { Ok(_) => {} Err(StorageError::NotFound) => { tx.put(self.prefix, &key, None, &vec![], &None)?; } Err(e) => return Err(e), }; Ok(()) }) } pub fn remove(&self, model: &mut Model, column: &Column) -> Result<(), StorageError> { model.check_exists()?; let key = Self::compute_key(model, column)?; model.storage().del(self.prefix, &key, None, &None) } pub fn has(&self, model: &mut Model, column: &Column) -> Result<(), StorageError> { model.check_exists()?; let key = Self::compute_key(model, column)?; model .storage() .has_property_value(self.prefix, &key, None, &vec![], &None) } pub fn remove_from_set_and_add( &self, model: &mut Model, mut remove_set: HashSet, add_set: HashSet, ) -> Result<(), StorageError> { // if existing_set.len() == 0 { // return Err(StorageError::InvalidValue); // } model.check_exists()?; let key_prefix = model.key(); let key_prefix_len = key_prefix.len(); let total_size = key_prefix_len + self.value_size()?; //log_debug!("REPLACE HEAD {:?} with {:?}", existing_set, replace_with); model.storage().write_transaction(&mut |tx| { for found in tx.get_all_keys_and_values( self.prefix, total_size, key_prefix.to_vec(), None, &None, )? { if found.0.len() == total_size + 1 { let val: Column = from_slice(&found.0[1 + key_prefix_len..total_size + 1])?; if remove_set.remove(&val) { tx.del(self.prefix, &found.0[1..].to_vec(), None, &None)?; } } } for add in add_set.iter() { let mut new = Vec::with_capacity(total_size); new.extend(key_prefix); let mut val = to_vec(add)?; new.append(&mut val); //log_debug!("PUTTING HEAD {} {:?}", self.prefix as char, new); tx.put(self.prefix, &new, None, &vec![], &None)?; } return Ok(()); }) } pub fn replace_with_new_set_if_old_set_exists( &self, model: &mut Model, mut existing_set: HashSet, replace_with: HashSet, ) -> Result<(), StorageError> { // if existing_set.len() == 0 { // return Err(StorageError::InvalidValue); // } model.check_exists()?; let key_prefix = model.key(); let key_prefix_len = key_prefix.len(); let total_size = key_prefix_len + self.value_size()?; let empty_existing = existing_set.is_empty(); //log_debug!("REPLACE HEAD {:?} with {:?}", existing_set, replace_with); model.storage().write_transaction(&mut |tx| { for found in tx.get_all_keys_and_values( self.prefix, total_size, key_prefix.to_vec(), None, &None, )? { if found.0.len() == total_size + 1 { let val: Column = from_slice(&found.0[1 + key_prefix_len..total_size + 1])?; if empty_existing { return Err(StorageError::NotEmpty); } if existing_set.remove(&val) { tx.del(self.prefix, &found.0[1..].to_vec(), None, &None)?; } } } if existing_set.is_empty() { for add in replace_with.iter() { let mut new = Vec::with_capacity(total_size); new.extend(key_prefix); let mut val = to_vec(add)?; new.append(&mut val); //log_debug!("PUTTING HEAD {} {:?}", self.prefix as char, new); tx.put(self.prefix, &new, None, &vec![], &None)?; } return Ok(()); } Err(StorageError::Abort) }) } pub fn get_all(&self, model: &mut Model) -> Result, StorageError> { model.check_exists()?; let key_prefix = model.key(); let key_prefix_len = key_prefix.len(); let mut res: HashSet = HashSet::new(); let total_size = key_prefix_len + self.value_size()?; for val in model.storage().get_all_keys_and_values( self.prefix, total_size, key_prefix.to_vec(), None, &None, )? { if val.0.len() == total_size + 1 { let val: Column = from_slice(&val.0[1 + key_prefix_len..total_size + 1])?; res.insert(val); } } Ok(res) } } impl< Model: IModel, Column: std::fmt::Debug + Eq + PartialEq + Hash + Serialize + Default + for<'d> Deserialize<'d>, > IMultiValueColumn for MultiValueColumn { fn value_size(&self) -> Result { Ok(to_vec(&Column::default())?.len()) } fn prefix(&self) -> u8 { self.prefix } } pub struct MultiMapColumn< Model: IModel, Column: std::fmt::Debug + Eq + PartialEq + Hash + Serialize + Default + for<'a> Deserialize<'a>, Value: Serialize + for<'a> Deserialize<'a> + Clone + PartialEq, > { prefix: u8, phantom_column: PhantomData, phantom_model: PhantomData, phantom_value: PhantomData, //value_size: usize, } impl< Model: IModel, Column: std::fmt::Debug + Eq + PartialEq + Hash + Serialize + Default + for<'d> Deserialize<'d>, Value: Serialize + for<'a> Deserialize<'a> + Clone + PartialEq, > MultiMapColumn { pub const fn new(prefix: u8) -> Self { MultiMapColumn { prefix, phantom_column: PhantomData, phantom_model: PhantomData, phantom_value: PhantomData, } } pub fn add( &self, model: &mut Model, column: &Column, value: &Value, ) -> Result<(), StorageError> { model.check_exists()?; let key = MultiValueColumn::compute_key(model, column)?; model .storage() .put(self.prefix, &key, None, &to_vec(value)?, &None) } pub fn remove( &self, model: &mut Model, column: &Column, value: &Value, ) -> Result<(), StorageError> { model.check_exists()?; let key = MultiValueColumn::compute_key(model, column)?; model .storage() .del_property_value(self.prefix, &key, None, &to_vec(value)?, &None) } pub fn remove_regardless_value( &self, model: &mut Model, column: &Column, ) -> Result<(), StorageError> { model.check_exists()?; let key = MultiValueColumn::compute_key(model, column)?; model.storage().del(self.prefix, &key, None, &None) } pub fn has( &self, model: &mut Model, column: &Column, value: &Value, ) -> Result<(), StorageError> { model.check_exists()?; let key = MultiValueColumn::compute_key(model, column)?; model .storage() .has_property_value(self.prefix, &key, None, &to_vec(value)?, &None) } pub fn get(&self, model: &mut Model, column: &Column) -> Result { model.check_exists()?; let key = MultiValueColumn::compute_key(model, column)?; let val_ser = model.storage().get(self.prefix, &key, None, &None)?; Ok(from_slice(&val_ser)?) } pub fn get_or_add( &self, model: &mut Model, column: &Column, value: &Value, ) -> Result { model.check_exists()?; let key = MultiValueColumn::compute_key(model, column)?; let mut found: Option = None; model.storage().write_transaction(&mut |tx| { found = match tx.get(self.prefix, &key, None, &None) { Ok(val_ser) => Some(from_slice(&val_ser)?), Err(StorageError::NotFound) => { tx.put(self.prefix, &key, None, &to_vec(value)?, &None)?; None } Err(e) => return Err(e), }; Ok(()) })?; Ok(found.unwrap_or(value.clone())) } pub fn add_or_change( &self, model: &mut Model, column: &Column, value: &Value, ) -> Result<(), StorageError> { model.check_exists()?; let key = MultiValueColumn::compute_key(model, column)?; let mut found: Option = None; model.storage().write_transaction(&mut |tx| { found = match tx.get(self.prefix, &key, None, &None) { Ok(val_ser) => Some(from_slice(&val_ser)?), Err(StorageError::NotFound) => { tx.put(self.prefix, &key, None, &to_vec(value)?, &None)?; None } Err(e) => return Err(e), }; if found.is_some() && found.as_ref().unwrap() != value { // we change it tx.put(self.prefix, &key, None, &to_vec(value)?, &None)?; } Ok(()) })?; Ok(()) } pub fn get_all(&self, model: &mut Model) -> Result, StorageError> { model.check_exists()?; let key_prefix = model.key(); let key_prefix_len = key_prefix.len(); let mut res: HashMap = HashMap::new(); let total_size = key_prefix_len + self.value_size()?; for val in model.storage().get_all_keys_and_values( self.prefix, total_size, key_prefix.to_vec(), None, &None, )? { if val.0.len() == total_size + 1 { let col: Column = from_slice(&val.0[1 + key_prefix_len..total_size + 1])?; let val = from_slice(&val.1)?; res.insert(col, val); } } Ok(res) } } impl< Model: IModel, Column: std::fmt::Debug + Eq + PartialEq + Hash + Serialize + Default + for<'d> Deserialize<'d>, Value: Serialize + for<'a> Deserialize<'a> + Clone + PartialEq, > IMultiValueColumn for MultiMapColumn { fn value_size(&self) -> Result { Ok(to_vec(&Column::default())?.len()) } fn prefix(&self) -> u8 { self.prefix } } pub struct MultiCounterColumn< Model: IModel, Column: std::fmt::Debug + Eq + PartialEq + Hash + Serialize + Default + for<'a> Deserialize<'a>, > { prefix: u8, phantom_column: PhantomData, phantom_model: PhantomData, } impl< Model: IModel, Column: std::fmt::Debug + Eq + PartialEq + Hash + Serialize + Default + for<'d> Deserialize<'d>, > MultiCounterColumn { pub const fn new(prefix: u8) -> Self { MultiCounterColumn { prefix, phantom_column: PhantomData, phantom_model: PhantomData, } } pub fn increment(&self, model: &mut Model, column: &Column) -> Result<(), StorageError> { let key = MultiValueColumn::compute_key(model, column)?; model.storage().write_transaction(&mut |tx| { let mut val: u64 = match tx.get(self.prefix, &key, None, &None) { Ok(val_ser) => from_slice(&val_ser)?, Err(StorageError::NotFound) => 0, Err(e) => return Err(e), }; val += 1; let val_ser = to_vec(&val)?; tx.put(self.prefix, &key, None, &val_ser, &None)?; Ok(()) }) } /// returns true if the counter reached zero (and the key was removed from KVC store) pub fn decrement(&self, model: &mut Model, column: &Column) -> Result { let key = MultiValueColumn::compute_key(model, column)?; let mut ret: bool = false; model.storage().write_transaction(&mut |tx| { let val_ser = tx.get(self.prefix, &key, None, &None)?; let mut val: u64 = from_slice(&val_ser)?; val -= 1; ret = val == 0; if ret { tx.del(self.prefix, &key, None, &None)?; } else { let val_ser = to_vec(&val)?; tx.put(self.prefix, &key, None, &val_ser, &None)?; } Ok(()) })?; Ok(ret) } pub fn get(&self, model: &mut Model, column: &Column) -> Result { let key = MultiValueColumn::compute_key(model, column)?; let val_ser = model.storage().get(self.prefix, &key, None, &None)?; let val: u64 = from_slice(&val_ser)?; Ok(val) } pub fn get_all(&self, model: &mut Model) -> Result, StorageError> { model.check_exists()?; let key_prefix = model.key(); let key_prefix_len = key_prefix.len(); let mut res: HashMap = HashMap::new(); let total_size = key_prefix_len + self.value_size()?; for val in model.storage().get_all_keys_and_values( self.prefix, total_size, key_prefix.to_vec(), None, &None, )? { if val.0.len() == total_size + 1 { let col: Column = from_slice(&val.0[1 + key_prefix_len..total_size + 1])?; let val = from_slice(&val.1)?; res.insert(col, val); } } Ok(res) } } impl< Model: IModel, Column: std::fmt::Debug + Eq + PartialEq + Hash + Serialize + Default + for<'d> Deserialize<'d>, > IMultiValueColumn for MultiCounterColumn { fn value_size(&self) -> Result { Ok(to_vec(&(0 as u64))?.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; } pub struct SingleValueColumn Deserialize<'a>> { suffix: u8, phantom_value: PhantomData, phantom_model: PhantomData, } impl Deserialize<'d>> ISingleValueColumn for SingleValueColumn { fn suffix(&self) -> u8 { self.suffix } } impl Deserialize<'d>> SingleValueColumn { pub const fn new(suffix: u8) -> Self { SingleValueColumn { suffix, phantom_value: PhantomData, phantom_model: PhantomData, } } pub fn set(&self, model: &mut Model, value: &Value) -> Result<(), StorageError> { model.check_exists()?; model.storage().replace( model.prefix(), model.key(), Some(self.suffix), &to_vec(value)?, &None, ) } pub fn get(&self, model: &mut Model) -> Result { model.check_exists()?; match model .storage() .get(model.prefix(), model.key(), Some(self.suffix), &None) { Ok(res) => Ok(from_slice::(&res)?), Err(e) => Err(e), } } pub fn get_or_set(&self, model: &mut Model, value: &Value) -> Result { model.check_exists()?; let mut found: Option = None; model.storage().write_transaction(&mut |tx| { found = match tx.get(model.prefix(), model.key(), Some(self.suffix), &None) { Ok(val_ser) => Some(from_slice(&val_ser)?), Err(StorageError::NotFound) => { tx.put( model.prefix(), model.key(), Some(self.suffix), &to_vec(value)?, &None, )?; None } Err(e) => return Err(e), }; Ok(()) })?; Ok(found.unwrap_or(value.clone())) } pub fn has(&self, model: &mut Model, value: &Value) -> Result<(), StorageError> { model.check_exists()?; model.storage().has_property_value( model.prefix(), model.key(), Some(self.suffix), &to_vec(value)?, &None, ) } pub fn del(&self, model: &mut Model) -> Result<(), StorageError> { model.check_exists()?; model .storage() .del(model.prefix(), model.key(), Some(self.suffix), &None) } } ///////////// Counter Value pub struct CounterValue { suffix: u8, phantom_model: PhantomData, } impl ISingleValueColumn for CounterValue { fn suffix(&self) -> u8 { self.suffix } } impl CounterValue { pub const fn new(suffix: u8) -> Self { CounterValue { suffix, phantom_model: PhantomData, } } pub fn increment(&self, model: &mut Model) -> Result<(), StorageError> { model.storage().write_transaction(&mut |tx| { let mut val: u64 = match tx.get(model.prefix(), model.key(), Some(self.suffix), &None) { Ok(val_ser) => from_slice(&val_ser)?, Err(StorageError::NotFound) => 0, Err(e) => return Err(e), }; val += 1; let val_ser = to_vec(&val)?; tx.put( model.prefix(), model.key(), Some(self.suffix), &val_ser, &None, )?; Ok(()) }) } /// returns true if the counter reached zero, and the property was removed pub fn decrement(&self, model: &mut Model) -> Result { let mut ret: bool = false; model.storage().write_transaction(&mut |tx| { let val_ser = tx.get(model.prefix(), model.key(), Some(self.suffix), &None)?; let mut val: u64 = from_slice(&val_ser)?; val -= 1; ret = val == 0; if ret { tx.del(model.prefix(), model.key(), Some(self.suffix), &None)?; } else { let val_ser = to_vec(&val)?; tx.put( model.prefix(), model.key(), Some(self.suffix), &val_ser, &None, )?; } Ok(()) })?; Ok(ret) } pub fn get(&self, model: &mut Model) -> Result { let val_res = model .storage() .get(model.prefix(), model.key(), Some(self.suffix), &None); match val_res { Ok(val_ser) => Ok(from_slice(&val_ser)?), Err(StorageError::NotFound) => Ok(0), Err(e) => Err(e), } } pub fn del(&self, model: &mut Model) -> Result<(), StorageError> { model.check_exists()?; model .storage() .del(model.prefix(), model.key(), Some(self.suffix), &None) } } //////////////// pub struct ExistentialValueColumn { suffix: u8, } impl ISingleValueColumn for ExistentialValueColumn { fn suffix(&self) -> u8 { self.suffix } } impl ExistentialValueColumn { pub const fn new(suffix: u8) -> Self { ExistentialValueColumn { suffix } } } pub struct ExistentialValue Deserialize<'d>> { value: Option, value_ser: Vec, } pub trait IExistentialValue { fn process_exists(&mut self, value_ser: Vec); fn exists(&self) -> bool; } impl Deserialize<'d>> IExistentialValue for ExistentialValue { fn exists(&self) -> bool { self.value.is_some() || self.value_ser.len() > 0 } fn process_exists(&mut self, value_ser: Vec) { self.value_ser = value_ser; } } impl Deserialize<'d>> ExistentialValue { pub fn new() -> Self { ExistentialValue { value: None, value_ser: vec![], } } pub fn set(&mut self, value: &Column) -> Result<(), StorageError> { if self.value.is_some() { return Err(StorageError::AlreadyExists); } self.value = Some(value.clone()); Ok(()) } pub fn save(model: &Model, value: &Column) -> Result<(), StorageError> { model.storage().replace( model.prefix(), model.key(), Some(model.class().existential_column.unwrap().suffix()), &to_vec(value)?, &None, )?; 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.is_empty() { return Err(StorageError::BackendError); } let value = from_slice::(&self.value_ser); match value { Err(_) => return Err(StorageError::InvalidValue), Ok(val) => { self.value = Some(val); return Ok(self.value.as_ref().unwrap()); } } } pub fn take(mut self) -> Result { self.get()?; Ok(self.value.take().unwrap()) } } pub trait WriteTransaction: ReadTransaction { /// Save a property value to the store. fn put( &self, prefix: u8, key: &Vec, suffix: Option, value: &Vec, family: &Option, ) -> Result<(), StorageError>; /// Replace the property of a key (single value) to the store. fn replace( &self, prefix: u8, key: &Vec, suffix: Option, value: &Vec, family: &Option, ) -> Result<(), StorageError>; /// Delete a property from the store. fn del( &self, prefix: u8, key: &Vec, suffix: Option, family: &Option, ) -> Result<(), StorageError>; /// Delete all properties of a key from the store. fn del_all( &self, prefix: u8, key: &Vec, all_suffixes: &[u8], family: &Option, ) -> Result<(), StorageError>; /// Delete a specific value for a property from the store. fn del_property_value( &self, prefix: u8, key: &Vec, suffix: Option, value: &Vec, family: &Option, ) -> Result<(), StorageError>; /// Delete all properties' values of a key from the store in case the property is a multi-values one fn del_all_values( &self, prefix: u8, key: &Vec, property_size: usize, suffix: Option, family: &Option, ) -> Result<(), StorageError>; } pub trait ReadTransaction { /// Load a property from the store. fn get( &self, prefix: u8, key: &Vec, suffix: Option, family: &Option, ) -> Result, StorageError>; /// Load all the values of a property from the store. #[deprecated( note = "KVStore has unique values (since switch from lmdb to rocksdb) use get() instead" )] fn get_all( &self, prefix: u8, key: &Vec, suffix: Option, family: &Option, ) -> Result>, StorageError>; fn get_all_properties_of_key( &self, prefix: u8, key: Vec, properties: Vec, family: &Option, ) -> Result>, StorageError>; /// Check if a specific value exists for a property from the store. fn has_property_value( &self, prefix: u8, key: &Vec, suffix: Option, value: &Vec, family: &Option, ) -> Result<(), StorageError>; /// retrieves all the keys and values with the given prefix and key_size. if no suffix is specified, then all (including none) the suffices are returned fn get_all_keys_and_values( &self, prefix: u8, key_size: usize, key_prefix: Vec, suffix: Option, family: &Option, ) -> Result, Vec)>, StorageError>; } pub trait KCVStorage: WriteTransaction { fn write_transaction( &self, method: &mut dyn FnMut(&mut dyn WriteTransaction) -> Result<(), StorageError>, ) -> Result<(), StorageError>; // /// Save a property value to the store. // fn put( // &self, // prefix: u8, // key: &Vec, // suffix: Option, // value: Vec, // ) -> Result<(), StorageError>; // /// Replace the property of a key (single value) to the store. // fn replace( // &self, // prefix: u8, // key: &Vec, // suffix: Option, // value: Vec, // ) -> Result<(), StorageError>; // /// Delete a property from the store. // fn del(&self, prefix: u8, key: &Vec, suffix: Option) -> Result<(), StorageError>; // /// Delete all properties of a key from the store. // fn del_all(&self, prefix: u8, key: &Vec, all_suffixes: &[u8]) -> Result<(), StorageError>; // /// Delete a specific value for a property from the store. // fn del_property_value( // &self, // prefix: u8, // key: &Vec, // suffix: Option, // value: Vec, // ) -> Result<(), StorageError>; }