403 lines
16 KiB
Rust
403 lines
16 KiB
Rust
use redb::{ReadableTable};
|
|
use crate::error::DBError;
|
|
use super::*;
|
|
|
|
impl Storage {
|
|
// ✅ ENCRYPTION APPLIED: Elements are encrypted before storage
|
|
pub fn lpush(&self, key: &str, elements: Vec<String>) -> Result<i64, DBError> {
|
|
let write_txn = self.db.begin_write()?;
|
|
let mut _length = 0i64;
|
|
|
|
{
|
|
let mut types_table = write_txn.open_table(TYPES_TABLE)?;
|
|
let mut lists_table = write_txn.open_table(LISTS_TABLE)?;
|
|
|
|
// Set the type to list
|
|
types_table.insert(key, "list")?;
|
|
|
|
// Get current list or create empty one
|
|
let mut list: Vec<String> = match lists_table.get(key)? {
|
|
Some(data) => {
|
|
let decrypted = self.decrypt_if_needed(data.value())?;
|
|
serde_json::from_slice(&decrypted)?
|
|
}
|
|
None => Vec::new(),
|
|
};
|
|
|
|
// Add elements to the front (left)
|
|
for element in elements.into_iter().rev() {
|
|
list.insert(0, element);
|
|
}
|
|
|
|
_length = list.len() as i64;
|
|
|
|
// Encrypt and store the updated list
|
|
let serialized = serde_json::to_vec(&list)?;
|
|
let encrypted = self.encrypt_if_needed(&serialized)?;
|
|
lists_table.insert(key, encrypted.as_slice())?;
|
|
}
|
|
|
|
write_txn.commit()?;
|
|
Ok(_length)
|
|
}
|
|
|
|
// ✅ ENCRYPTION APPLIED: Elements are encrypted before storage
|
|
pub fn rpush(&self, key: &str, elements: Vec<String>) -> Result<i64, DBError> {
|
|
let write_txn = self.db.begin_write()?;
|
|
let mut _length = 0i64;
|
|
|
|
{
|
|
let mut types_table = write_txn.open_table(TYPES_TABLE)?;
|
|
let mut lists_table = write_txn.open_table(LISTS_TABLE)?;
|
|
|
|
// Set the type to list
|
|
types_table.insert(key, "list")?;
|
|
|
|
// Get current list or create empty one
|
|
let mut list: Vec<String> = match lists_table.get(key)? {
|
|
Some(data) => {
|
|
let decrypted = self.decrypt_if_needed(data.value())?;
|
|
serde_json::from_slice(&decrypted)?
|
|
}
|
|
None => Vec::new(),
|
|
};
|
|
|
|
// Add elements to the end (right)
|
|
list.extend(elements);
|
|
_length = list.len() as i64;
|
|
|
|
// Encrypt and store the updated list
|
|
let serialized = serde_json::to_vec(&list)?;
|
|
let encrypted = self.encrypt_if_needed(&serialized)?;
|
|
lists_table.insert(key, encrypted.as_slice())?;
|
|
}
|
|
|
|
write_txn.commit()?;
|
|
Ok(_length)
|
|
}
|
|
|
|
// ✅ ENCRYPTION APPLIED: Elements are decrypted after retrieval and encrypted before storage
|
|
pub fn lpop(&self, key: &str, count: u64) -> Result<Vec<String>, DBError> {
|
|
let write_txn = self.db.begin_write()?;
|
|
let mut result = Vec::new();
|
|
|
|
// First check if key exists and is a list, and get the data
|
|
let list_data = {
|
|
let types_table = write_txn.open_table(TYPES_TABLE)?;
|
|
let lists_table = write_txn.open_table(LISTS_TABLE)?;
|
|
|
|
let result = match types_table.get(key)? {
|
|
Some(type_val) if type_val.value() == "list" => {
|
|
if let Some(data) = lists_table.get(key)? {
|
|
let decrypted = self.decrypt_if_needed(data.value())?;
|
|
let list: Vec<String> = serde_json::from_slice(&decrypted)?;
|
|
Some(list)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
_ => None,
|
|
};
|
|
result
|
|
};
|
|
|
|
if let Some(mut list) = list_data {
|
|
let pop_count = std::cmp::min(count as usize, list.len());
|
|
for _ in 0..pop_count {
|
|
if !list.is_empty() {
|
|
result.push(list.remove(0));
|
|
}
|
|
}
|
|
|
|
let mut lists_table = write_txn.open_table(LISTS_TABLE)?;
|
|
if list.is_empty() {
|
|
// Remove the key if list is empty
|
|
lists_table.remove(key)?;
|
|
let mut types_table = write_txn.open_table(TYPES_TABLE)?;
|
|
types_table.remove(key)?;
|
|
} else {
|
|
// Encrypt and store the updated list
|
|
let serialized = serde_json::to_vec(&list)?;
|
|
let encrypted = self.encrypt_if_needed(&serialized)?;
|
|
lists_table.insert(key, encrypted.as_slice())?;
|
|
}
|
|
}
|
|
|
|
write_txn.commit()?;
|
|
Ok(result)
|
|
}
|
|
|
|
// ✅ ENCRYPTION APPLIED: Elements are decrypted after retrieval and encrypted before storage
|
|
pub fn rpop(&self, key: &str, count: u64) -> Result<Vec<String>, DBError> {
|
|
let write_txn = self.db.begin_write()?;
|
|
let mut result = Vec::new();
|
|
|
|
// First check if key exists and is a list, and get the data
|
|
let list_data = {
|
|
let types_table = write_txn.open_table(TYPES_TABLE)?;
|
|
let lists_table = write_txn.open_table(LISTS_TABLE)?;
|
|
|
|
let result = match types_table.get(key)? {
|
|
Some(type_val) if type_val.value() == "list" => {
|
|
if let Some(data) = lists_table.get(key)? {
|
|
let decrypted = self.decrypt_if_needed(data.value())?;
|
|
let list: Vec<String> = serde_json::from_slice(&decrypted)?;
|
|
Some(list)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
_ => None,
|
|
};
|
|
result
|
|
};
|
|
|
|
if let Some(mut list) = list_data {
|
|
let pop_count = std::cmp::min(count as usize, list.len());
|
|
for _ in 0..pop_count {
|
|
if !list.is_empty() {
|
|
result.push(list.pop().unwrap());
|
|
}
|
|
}
|
|
|
|
let mut lists_table = write_txn.open_table(LISTS_TABLE)?;
|
|
if list.is_empty() {
|
|
// Remove the key if list is empty
|
|
lists_table.remove(key)?;
|
|
let mut types_table = write_txn.open_table(TYPES_TABLE)?;
|
|
types_table.remove(key)?;
|
|
} else {
|
|
// Encrypt and store the updated list
|
|
let serialized = serde_json::to_vec(&list)?;
|
|
let encrypted = self.encrypt_if_needed(&serialized)?;
|
|
lists_table.insert(key, encrypted.as_slice())?;
|
|
}
|
|
}
|
|
|
|
write_txn.commit()?;
|
|
Ok(result)
|
|
}
|
|
|
|
pub fn llen(&self, key: &str) -> Result<i64, DBError> {
|
|
let read_txn = self.db.begin_read()?;
|
|
let types_table = read_txn.open_table(TYPES_TABLE)?;
|
|
|
|
match types_table.get(key)? {
|
|
Some(type_val) if type_val.value() == "list" => {
|
|
let lists_table = read_txn.open_table(LISTS_TABLE)?;
|
|
match lists_table.get(key)? {
|
|
Some(data) => {
|
|
let decrypted = self.decrypt_if_needed(data.value())?;
|
|
let list: Vec<String> = serde_json::from_slice(&decrypted)?;
|
|
Ok(list.len() as i64)
|
|
}
|
|
None => Ok(0),
|
|
}
|
|
}
|
|
_ => Ok(0),
|
|
}
|
|
}
|
|
|
|
// ✅ ENCRYPTION APPLIED: Element is decrypted after retrieval
|
|
pub fn lindex(&self, key: &str, index: i64) -> Result<Option<String>, DBError> {
|
|
let read_txn = self.db.begin_read()?;
|
|
let types_table = read_txn.open_table(TYPES_TABLE)?;
|
|
|
|
match types_table.get(key)? {
|
|
Some(type_val) if type_val.value() == "list" => {
|
|
let lists_table = read_txn.open_table(LISTS_TABLE)?;
|
|
match lists_table.get(key)? {
|
|
Some(data) => {
|
|
let decrypted = self.decrypt_if_needed(data.value())?;
|
|
let list: Vec<String> = serde_json::from_slice(&decrypted)?;
|
|
|
|
let actual_index = if index < 0 {
|
|
list.len() as i64 + index
|
|
} else {
|
|
index
|
|
};
|
|
|
|
if actual_index >= 0 && (actual_index as usize) < list.len() {
|
|
Ok(Some(list[actual_index as usize].clone()))
|
|
} else {
|
|
Ok(None)
|
|
}
|
|
}
|
|
None => Ok(None),
|
|
}
|
|
}
|
|
_ => Ok(None),
|
|
}
|
|
}
|
|
|
|
// ✅ ENCRYPTION APPLIED: Elements are decrypted after retrieval
|
|
pub fn lrange(&self, key: &str, start: i64, stop: i64) -> Result<Vec<String>, DBError> {
|
|
let read_txn = self.db.begin_read()?;
|
|
let types_table = read_txn.open_table(TYPES_TABLE)?;
|
|
|
|
match types_table.get(key)? {
|
|
Some(type_val) if type_val.value() == "list" => {
|
|
let lists_table = read_txn.open_table(LISTS_TABLE)?;
|
|
match lists_table.get(key)? {
|
|
Some(data) => {
|
|
let decrypted = self.decrypt_if_needed(data.value())?;
|
|
let list: Vec<String> = serde_json::from_slice(&decrypted)?;
|
|
|
|
if list.is_empty() {
|
|
return Ok(Vec::new());
|
|
}
|
|
|
|
let len = list.len() as i64;
|
|
let start_idx = if start < 0 { std::cmp::max(0, len + start) } else { std::cmp::min(start, len) };
|
|
let stop_idx = if stop < 0 { std::cmp::max(-1, len + stop) } else { std::cmp::min(stop, len - 1) };
|
|
|
|
if start_idx > stop_idx || start_idx >= len {
|
|
return Ok(Vec::new());
|
|
}
|
|
|
|
let start_usize = start_idx as usize;
|
|
let stop_usize = (stop_idx + 1) as usize;
|
|
|
|
Ok(list[start_usize..std::cmp::min(stop_usize, list.len())].to_vec())
|
|
}
|
|
None => Ok(Vec::new()),
|
|
}
|
|
}
|
|
_ => Ok(Vec::new()),
|
|
}
|
|
}
|
|
|
|
// ✅ ENCRYPTION APPLIED: Elements are decrypted after retrieval and encrypted before storage
|
|
pub fn ltrim(&self, key: &str, start: i64, stop: i64) -> Result<(), DBError> {
|
|
let write_txn = self.db.begin_write()?;
|
|
|
|
// First check if key exists and is a list, and get the data
|
|
let list_data = {
|
|
let types_table = write_txn.open_table(TYPES_TABLE)?;
|
|
let lists_table = write_txn.open_table(LISTS_TABLE)?;
|
|
|
|
let result = match types_table.get(key)? {
|
|
Some(type_val) if type_val.value() == "list" => {
|
|
if let Some(data) = lists_table.get(key)? {
|
|
let decrypted = self.decrypt_if_needed(data.value())?;
|
|
let list: Vec<String> = serde_json::from_slice(&decrypted)?;
|
|
Some(list)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
_ => None,
|
|
};
|
|
result
|
|
};
|
|
|
|
if let Some(list) = list_data {
|
|
if list.is_empty() {
|
|
write_txn.commit()?;
|
|
return Ok(());
|
|
}
|
|
|
|
let len = list.len() as i64;
|
|
let start_idx = if start < 0 { std::cmp::max(0, len + start) } else { std::cmp::min(start, len) };
|
|
let stop_idx = if stop < 0 { std::cmp::max(-1, len + stop) } else { std::cmp::min(stop, len - 1) };
|
|
|
|
let mut lists_table = write_txn.open_table(LISTS_TABLE)?;
|
|
if start_idx > stop_idx || start_idx >= len {
|
|
// Remove the entire list
|
|
lists_table.remove(key)?;
|
|
let mut types_table = write_txn.open_table(TYPES_TABLE)?;
|
|
types_table.remove(key)?;
|
|
} else {
|
|
let start_usize = start_idx as usize;
|
|
let stop_usize = (stop_idx + 1) as usize;
|
|
let trimmed = list[start_usize..std::cmp::min(stop_usize, list.len())].to_vec();
|
|
|
|
if trimmed.is_empty() {
|
|
lists_table.remove(key)?;
|
|
let mut types_table = write_txn.open_table(TYPES_TABLE)?;
|
|
types_table.remove(key)?;
|
|
} else {
|
|
// Encrypt and store the trimmed list
|
|
let serialized = serde_json::to_vec(&trimmed)?;
|
|
let encrypted = self.encrypt_if_needed(&serialized)?;
|
|
lists_table.insert(key, encrypted.as_slice())?;
|
|
}
|
|
}
|
|
}
|
|
|
|
write_txn.commit()?;
|
|
Ok(())
|
|
}
|
|
|
|
// ✅ ENCRYPTION APPLIED: Elements are decrypted after retrieval and encrypted before storage
|
|
pub fn lrem(&self, key: &str, count: i64, element: &str) -> Result<i64, DBError> {
|
|
let write_txn = self.db.begin_write()?;
|
|
let mut removed = 0i64;
|
|
|
|
// First check if key exists and is a list, and get the data
|
|
let list_data = {
|
|
let types_table = write_txn.open_table(TYPES_TABLE)?;
|
|
let lists_table = write_txn.open_table(LISTS_TABLE)?;
|
|
|
|
let result = match types_table.get(key)? {
|
|
Some(type_val) if type_val.value() == "list" => {
|
|
if let Some(data) = lists_table.get(key)? {
|
|
let decrypted = self.decrypt_if_needed(data.value())?;
|
|
let list: Vec<String> = serde_json::from_slice(&decrypted)?;
|
|
Some(list)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
_ => None,
|
|
};
|
|
result
|
|
};
|
|
|
|
if let Some(mut list) = list_data {
|
|
if count == 0 {
|
|
// Remove all occurrences
|
|
let original_len = list.len();
|
|
list.retain(|x| x != element);
|
|
removed = (original_len - list.len()) as i64;
|
|
} else if count > 0 {
|
|
// Remove first count occurrences
|
|
let mut to_remove = count as usize;
|
|
list.retain(|x| {
|
|
if x == element && to_remove > 0 {
|
|
to_remove -= 1;
|
|
removed += 1;
|
|
false
|
|
} else {
|
|
true
|
|
}
|
|
});
|
|
} else {
|
|
// Remove last |count| occurrences
|
|
let mut to_remove = (-count) as usize;
|
|
for i in (0..list.len()).rev() {
|
|
if list[i] == element && to_remove > 0 {
|
|
list.remove(i);
|
|
to_remove -= 1;
|
|
removed += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
let mut lists_table = write_txn.open_table(LISTS_TABLE)?;
|
|
if list.is_empty() {
|
|
lists_table.remove(key)?;
|
|
let mut types_table = write_txn.open_table(TYPES_TABLE)?;
|
|
types_table.remove(key)?;
|
|
} else {
|
|
// Encrypt and store the updated list
|
|
let serialized = serde_json::to_vec(&list)?;
|
|
let encrypted = self.encrypt_if_needed(&serialized)?;
|
|
lists_table.insert(key, encrypted.as_slice())?;
|
|
}
|
|
}
|
|
|
|
write_txn.commit()?;
|
|
Ok(removed)
|
|
}
|
|
} |