use std::marker::PhantomData;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::{
Result, Store, Transaction,
crdt::{CRDT, Doc},
store::errors::StoreError,
};
pub struct Table<T>
where
T: Serialize + for<'de> Deserialize<'de> + Clone,
{
name: String,
atomic_op: Transaction,
phantom: PhantomData<T>,
}
impl<T> Store for Table<T>
where
T: Serialize + for<'de> Deserialize<'de> + Clone,
{
fn new(op: &Transaction, subtree_name: impl Into<String>) -> Result<Self> {
Ok(Self {
name: subtree_name.into(),
atomic_op: op.clone(),
phantom: PhantomData,
})
}
fn name(&self) -> &str {
&self.name
}
}
impl<T> Table<T>
where
T: Serialize + for<'de> Deserialize<'de> + Clone,
{
pub fn get(&self, key: impl AsRef<str>) -> Result<T> {
let key = key.as_ref();
let local_data: Result<Doc> = self.atomic_op.get_local_data(&self.name);
if let Ok(ref data) = local_data
&& data.is_tombstone(key)
{
return Err(StoreError::KeyNotFound {
store: self.name.clone(),
key: key.to_string(),
}
.into());
}
if let Ok(ref data) = local_data
&& let Some(map_value) = data.get(key)
&& let Some(value) = map_value.as_text()
{
return serde_json::from_str(value).map_err(|e| {
StoreError::DeserializationFailed {
store: self.name.clone(),
reason: format!("Failed to deserialize record for key '{key}': {e}"),
}
.into()
});
}
let data: Doc = self.atomic_op.get_full_state(&self.name)?;
match data.get(key).and_then(|v| v.as_text()) {
Some(value) => serde_json::from_str(value).map_err(|e| {
StoreError::DeserializationFailed {
store: self.name.clone(),
reason: format!("Failed to deserialize record for key '{key}': {e}"),
}
.into()
}),
None => Err(StoreError::KeyNotFound {
store: self.name.clone(),
key: key.to_string(),
}
.into()),
}
}
pub fn insert(&self, row: T) -> Result<String> {
let primary_key = Uuid::new_v4().to_string();
let mut data = self
.atomic_op
.get_local_data::<Doc>(&self.name)
.unwrap_or_default();
let serialized_row =
serde_json::to_string(&row).map_err(|e| StoreError::SerializationFailed {
store: self.name.clone(),
reason: format!("Failed to serialize record: {e}"),
})?;
data.set(primary_key.clone(), serialized_row);
let serialized_data =
serde_json::to_string(&data).map_err(|e| StoreError::SerializationFailed {
store: self.name.clone(),
reason: format!("Failed to serialize subtree data: {e}"),
})?;
self.atomic_op
.update_subtree(&self.name, &serialized_data)?;
Ok(primary_key)
}
pub fn set(&self, key: impl AsRef<str>, row: T) -> Result<()> {
let key_str = key.as_ref();
let mut data = self
.atomic_op
.get_local_data::<Doc>(&self.name)
.unwrap_or_default();
let serialized_row =
serde_json::to_string(&row).map_err(|e| StoreError::SerializationFailed {
store: self.name.clone(),
reason: format!("Failed to serialize record for key '{key_str}': {e}"),
})?;
data.set(key_str, serialized_row);
let serialized_data =
serde_json::to_string(&data).map_err(|e| StoreError::SerializationFailed {
store: self.name.clone(),
reason: format!("Failed to serialize subtree data: {e}"),
})?;
self.atomic_op.update_subtree(&self.name, &serialized_data)
}
pub fn delete(&self, key: impl AsRef<str>) -> Result<bool> {
let key_str = key.as_ref();
let exists = self.get(key_str).is_ok();
if !exists {
return Ok(false);
}
let mut data = self
.atomic_op
.get_local_data::<Doc>(&self.name)
.unwrap_or_default();
data.remove(key_str);
let serialized_data =
serde_json::to_string(&data).map_err(|e| StoreError::SerializationFailed {
store: self.name.clone(),
reason: format!("Failed to serialize subtree data: {e}"),
})?;
self.atomic_op
.update_subtree(&self.name, &serialized_data)?;
Ok(true)
}
pub fn search(&self, query: impl Fn(&T) -> bool) -> Result<Vec<(String, T)>> {
let mut result = Vec::new();
let local_data = self.atomic_op.get_local_data::<Doc>(&self.name);
let mut data = self.atomic_op.get_full_state::<Doc>(&self.name)?;
if let Ok(local) = local_data {
data = data.merge(&local)?;
}
for (key, map_value) in data.as_hashmap().iter() {
if let Some(value) = map_value.as_text() {
let row: T =
serde_json::from_str(value).map_err(|e| StoreError::DeserializationFailed {
store: self.name.clone(),
reason: format!(
"Failed to deserialize record for key '{key}' during search: {e}"
),
})?;
if query(&row) {
result.push((key.clone(), row));
}
}
}
Ok(result)
}
}