377 lines
15 KiB
Rust
377 lines
15 KiB
Rust
use redb::{ReadableTable};
|
|
use crate::error::DBError;
|
|
use super::*;
|
|
|
|
impl Storage {
|
|
// ✅ ENCRYPTION APPLIED: Values are encrypted before storage
|
|
pub fn hset(&self, key: &str, pairs: Vec<(String, String)>) -> Result<i64, DBError> {
|
|
let write_txn = self.db.begin_write()?;
|
|
let mut new_fields = 0i64;
|
|
|
|
{
|
|
let mut types_table = write_txn.open_table(TYPES_TABLE)?;
|
|
let mut hashes_table = write_txn.open_table(HASHES_TABLE)?;
|
|
|
|
let key_type = {
|
|
let access_guard = types_table.get(key)?;
|
|
access_guard.map(|v| v.value().to_string())
|
|
};
|
|
|
|
match key_type.as_deref() {
|
|
Some("hash") | None => { // Proceed if hash or new key
|
|
// Set the type to hash (only if new key or existing hash)
|
|
types_table.insert(key, "hash")?;
|
|
|
|
for (field, value) in pairs {
|
|
// Check if field already exists
|
|
let exists = hashes_table.get((key, field.as_str()))?.is_some();
|
|
|
|
// Encrypt the value before storing
|
|
let encrypted = self.encrypt_if_needed(value.as_bytes())?;
|
|
hashes_table.insert((key, field.as_str()), encrypted.as_slice())?;
|
|
|
|
if !exists {
|
|
new_fields += 1;
|
|
}
|
|
}
|
|
}
|
|
Some(_) => return Err(DBError("WRONGTYPE Operation against a key holding the wrong kind of value".to_string())),
|
|
}
|
|
}
|
|
|
|
write_txn.commit()?;
|
|
Ok(new_fields)
|
|
}
|
|
|
|
// ✅ ENCRYPTION APPLIED: Value is decrypted after retrieval
|
|
pub fn hget(&self, key: &str, field: &str) -> Result<Option<String>, DBError> {
|
|
let read_txn = self.db.begin_read()?;
|
|
let types_table = read_txn.open_table(TYPES_TABLE)?;
|
|
|
|
let key_type = types_table.get(key)?.map(|v| v.value().to_string());
|
|
|
|
match key_type.as_deref() {
|
|
Some("hash") => {
|
|
let hashes_table = read_txn.open_table(HASHES_TABLE)?;
|
|
match hashes_table.get((key, field))? {
|
|
Some(data) => {
|
|
let decrypted = self.decrypt_if_needed(data.value())?;
|
|
let value = String::from_utf8(decrypted)?;
|
|
Ok(Some(value))
|
|
}
|
|
None => Ok(None),
|
|
}
|
|
}
|
|
Some(_) => Err(DBError("WRONGTYPE Operation against a key holding the wrong kind of value".to_string())),
|
|
None => Ok(None),
|
|
}
|
|
}
|
|
|
|
// ✅ ENCRYPTION APPLIED: All values are decrypted after retrieval
|
|
pub fn hgetall(&self, key: &str) -> Result<Vec<(String, String)>, DBError> {
|
|
let read_txn = self.db.begin_read()?;
|
|
let types_table = read_txn.open_table(TYPES_TABLE)?;
|
|
let key_type = {
|
|
let access_guard = types_table.get(key)?;
|
|
access_guard.map(|v| v.value().to_string())
|
|
};
|
|
|
|
match key_type.as_deref() {
|
|
Some("hash") => {
|
|
let hashes_table = read_txn.open_table(HASHES_TABLE)?;
|
|
let mut result = Vec::new();
|
|
|
|
let mut iter = hashes_table.iter()?;
|
|
while let Some(entry) = iter.next() {
|
|
let entry = entry?;
|
|
let (hash_key, field) = entry.0.value();
|
|
if hash_key == key {
|
|
let decrypted = self.decrypt_if_needed(entry.1.value())?;
|
|
let value = String::from_utf8(decrypted)?;
|
|
result.push((field.to_string(), value));
|
|
}
|
|
}
|
|
|
|
Ok(result)
|
|
}
|
|
Some(_) => Err(DBError("WRONGTYPE Operation against a key holding the wrong kind of value".to_string())),
|
|
None => Ok(Vec::new()),
|
|
}
|
|
}
|
|
|
|
pub fn hdel(&self, key: &str, fields: Vec<String>) -> Result<i64, DBError> {
|
|
let write_txn = self.db.begin_write()?;
|
|
let mut deleted = 0i64;
|
|
|
|
// First check if key exists and is a hash
|
|
let key_type = {
|
|
let types_table = write_txn.open_table(TYPES_TABLE)?;
|
|
let access_guard = types_table.get(key)?;
|
|
access_guard.map(|v| v.value().to_string())
|
|
};
|
|
|
|
match key_type.as_deref() {
|
|
Some("hash") => {
|
|
let mut hashes_table = write_txn.open_table(HASHES_TABLE)?;
|
|
|
|
for field in fields {
|
|
if hashes_table.remove((key, field.as_str()))?.is_some() {
|
|
deleted += 1;
|
|
}
|
|
}
|
|
|
|
// Check if hash is now empty and remove type if so
|
|
let mut has_fields = false;
|
|
let mut iter = hashes_table.iter()?;
|
|
while let Some(entry) = iter.next() {
|
|
let entry = entry?;
|
|
let (hash_key, _) = entry.0.value();
|
|
if hash_key == key {
|
|
has_fields = true;
|
|
break;
|
|
}
|
|
}
|
|
drop(iter);
|
|
|
|
if !has_fields {
|
|
let mut types_table = write_txn.open_table(TYPES_TABLE)?;
|
|
types_table.remove(key)?;
|
|
}
|
|
}
|
|
Some(_) => return Err(DBError("WRONGTYPE Operation against a key holding the wrong kind of value".to_string())),
|
|
None => {} // Key does not exist, nothing to delete, return 0 deleted
|
|
}
|
|
|
|
write_txn.commit()?;
|
|
Ok(deleted)
|
|
}
|
|
|
|
pub fn hexists(&self, key: &str, field: &str) -> Result<bool, DBError> {
|
|
let read_txn = self.db.begin_read()?;
|
|
let types_table = read_txn.open_table(TYPES_TABLE)?;
|
|
let key_type = {
|
|
let access_guard = types_table.get(key)?;
|
|
access_guard.map(|v| v.value().to_string())
|
|
};
|
|
|
|
match key_type.as_deref() {
|
|
Some("hash") => {
|
|
let hashes_table = read_txn.open_table(HASHES_TABLE)?;
|
|
Ok(hashes_table.get((key, field))?.is_some())
|
|
}
|
|
Some(_) => Err(DBError("WRONGTYPE Operation against a key holding the wrong kind of value".to_string())),
|
|
None => Ok(false),
|
|
}
|
|
}
|
|
|
|
pub fn hkeys(&self, key: &str) -> Result<Vec<String>, DBError> {
|
|
let read_txn = self.db.begin_read()?;
|
|
let types_table = read_txn.open_table(TYPES_TABLE)?;
|
|
let key_type = {
|
|
let access_guard = types_table.get(key)?;
|
|
access_guard.map(|v| v.value().to_string())
|
|
};
|
|
|
|
match key_type.as_deref() {
|
|
Some("hash") => {
|
|
let hashes_table = read_txn.open_table(HASHES_TABLE)?;
|
|
let mut result = Vec::new();
|
|
|
|
let mut iter = hashes_table.iter()?;
|
|
while let Some(entry) = iter.next() {
|
|
let entry = entry?;
|
|
let (hash_key, field) = entry.0.value();
|
|
if hash_key == key {
|
|
result.push(field.to_string());
|
|
}
|
|
}
|
|
|
|
Ok(result)
|
|
}
|
|
Some(_) => Err(DBError("WRONGTYPE Operation against a key holding the wrong kind of value".to_string())),
|
|
None => Ok(Vec::new()),
|
|
}
|
|
}
|
|
|
|
// ✅ ENCRYPTION APPLIED: All values are decrypted after retrieval
|
|
pub fn hvals(&self, key: &str) -> Result<Vec<String>, DBError> {
|
|
let read_txn = self.db.begin_read()?;
|
|
let types_table = read_txn.open_table(TYPES_TABLE)?;
|
|
let key_type = {
|
|
let access_guard = types_table.get(key)?;
|
|
access_guard.map(|v| v.value().to_string())
|
|
};
|
|
|
|
match key_type.as_deref() {
|
|
Some("hash") => {
|
|
let hashes_table = read_txn.open_table(HASHES_TABLE)?;
|
|
let mut result = Vec::new();
|
|
|
|
let mut iter = hashes_table.iter()?;
|
|
while let Some(entry) = iter.next() {
|
|
let entry = entry?;
|
|
let (hash_key, _) = entry.0.value();
|
|
if hash_key == key {
|
|
let decrypted = self.decrypt_if_needed(entry.1.value())?;
|
|
let value = String::from_utf8(decrypted)?;
|
|
result.push(value);
|
|
}
|
|
}
|
|
|
|
Ok(result)
|
|
}
|
|
Some(_) => Err(DBError("WRONGTYPE Operation against a key holding the wrong kind of value".to_string())),
|
|
None => Ok(Vec::new()),
|
|
}
|
|
}
|
|
|
|
pub fn hlen(&self, key: &str) -> Result<i64, DBError> {
|
|
let read_txn = self.db.begin_read()?;
|
|
let types_table = read_txn.open_table(TYPES_TABLE)?;
|
|
let key_type = {
|
|
let access_guard = types_table.get(key)?;
|
|
access_guard.map(|v| v.value().to_string())
|
|
};
|
|
|
|
match key_type.as_deref() {
|
|
Some("hash") => {
|
|
let hashes_table = read_txn.open_table(HASHES_TABLE)?;
|
|
let mut count = 0i64;
|
|
|
|
let mut iter = hashes_table.iter()?;
|
|
while let Some(entry) = iter.next() {
|
|
let entry = entry?;
|
|
let (hash_key, _) = entry.0.value();
|
|
if hash_key == key {
|
|
count += 1;
|
|
}
|
|
}
|
|
|
|
Ok(count)
|
|
}
|
|
Some(_) => Err(DBError("WRONGTYPE Operation against a key holding the wrong kind of value".to_string())),
|
|
None => Ok(0),
|
|
}
|
|
}
|
|
|
|
// ✅ ENCRYPTION APPLIED: Values are decrypted after retrieval
|
|
pub fn hmget(&self, key: &str, fields: Vec<String>) -> Result<Vec<Option<String>>, DBError> {
|
|
let read_txn = self.db.begin_read()?;
|
|
let types_table = read_txn.open_table(TYPES_TABLE)?;
|
|
let key_type = {
|
|
let access_guard = types_table.get(key)?;
|
|
access_guard.map(|v| v.value().to_string())
|
|
};
|
|
|
|
match key_type.as_deref() {
|
|
Some("hash") => {
|
|
let hashes_table = read_txn.open_table(HASHES_TABLE)?;
|
|
let mut result = Vec::new();
|
|
|
|
for field in fields {
|
|
match hashes_table.get((key, field.as_str()))? {
|
|
Some(data) => {
|
|
let decrypted = self.decrypt_if_needed(data.value())?;
|
|
let value = String::from_utf8(decrypted)?;
|
|
result.push(Some(value));
|
|
}
|
|
None => result.push(None),
|
|
}
|
|
}
|
|
|
|
Ok(result)
|
|
}
|
|
Some(_) => Err(DBError("WRONGTYPE Operation against a key holding the wrong kind of value".to_string())),
|
|
None => Ok(fields.into_iter().map(|_| None).collect()),
|
|
}
|
|
}
|
|
|
|
// ✅ ENCRYPTION APPLIED: Value is encrypted before storage
|
|
pub fn hsetnx(&self, key: &str, field: &str, value: &str) -> Result<bool, DBError> {
|
|
let write_txn = self.db.begin_write()?;
|
|
let mut result = false;
|
|
|
|
{
|
|
let mut types_table = write_txn.open_table(TYPES_TABLE)?;
|
|
let mut hashes_table = write_txn.open_table(HASHES_TABLE)?;
|
|
|
|
let key_type = {
|
|
let access_guard = types_table.get(key)?;
|
|
access_guard.map(|v| v.value().to_string())
|
|
};
|
|
|
|
match key_type.as_deref() {
|
|
Some("hash") | None => { // Proceed if hash or new key
|
|
// Check if field already exists
|
|
if hashes_table.get((key, field))?.is_none() {
|
|
// Set the type to hash (only if new key or existing hash)
|
|
types_table.insert(key, "hash")?;
|
|
|
|
// Encrypt the value before storing
|
|
let encrypted = self.encrypt_if_needed(value.as_bytes())?;
|
|
hashes_table.insert((key, field), encrypted.as_slice())?;
|
|
result = true;
|
|
}
|
|
}
|
|
Some(_) => return Err(DBError("WRONGTYPE Operation against a key holding the wrong kind of value".to_string())),
|
|
}
|
|
}
|
|
|
|
write_txn.commit()?;
|
|
Ok(result)
|
|
}
|
|
|
|
// ✅ ENCRYPTION APPLIED: Values are decrypted after retrieval
|
|
pub fn hscan(&self, key: &str, cursor: u64, pattern: Option<&str>, count: Option<u64>) -> Result<(u64, Vec<(String, String)>), DBError> {
|
|
let read_txn = self.db.begin_read()?;
|
|
let types_table = read_txn.open_table(TYPES_TABLE)?;
|
|
let key_type = {
|
|
let access_guard = types_table.get(key)?;
|
|
access_guard.map(|v| v.value().to_string())
|
|
};
|
|
|
|
match key_type.as_deref() {
|
|
Some("hash") => {
|
|
let hashes_table = read_txn.open_table(HASHES_TABLE)?;
|
|
let mut result = Vec::new();
|
|
let mut current_cursor = 0u64;
|
|
let limit = count.unwrap_or(10) as usize;
|
|
|
|
let mut iter = hashes_table.iter()?;
|
|
while let Some(entry) = iter.next() {
|
|
let entry = entry?;
|
|
let (hash_key, field) = entry.0.value();
|
|
|
|
if hash_key == key {
|
|
if current_cursor >= cursor {
|
|
let field_str = field.to_string();
|
|
|
|
// Apply pattern matching if specified
|
|
let matches = if let Some(pat) = pattern {
|
|
super::storage_extra::glob_match(pat, &field_str)
|
|
} else {
|
|
true
|
|
};
|
|
|
|
if matches {
|
|
let decrypted = self.decrypt_if_needed(entry.1.value())?;
|
|
let value = String::from_utf8(decrypted)?;
|
|
result.push((field_str, value));
|
|
|
|
if result.len() >= limit {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
current_cursor += 1;
|
|
}
|
|
}
|
|
|
|
let next_cursor = if result.len() < limit { 0 } else { current_cursor };
|
|
Ok((next_cursor, result))
|
|
}
|
|
Some(_) => Err(DBError("WRONGTYPE Operation against a key holding the wrong kind of value".to_string())),
|
|
None => Ok((0, Vec::new())),
|
|
}
|
|
}
|
|
} |