use async_trait::async_trait;
use serde::{Serialize, de::DeserializeOwned};
use vantage_core::util::error::{Context, vantage_error};
use vantage_dataset::dataset::{Id, InsertableDataSet, Result, WritableDataSet};
use vantage_table::{Entity, Table};
use super::SurrealTableCore;
use crate::SurrealDB;
#[async_trait]
impl<E> WritableDataSet<E> for Table<SurrealDB, E>
where
E: Entity + Serialize + DeserializeOwned + Send + Sync + 'static,
{
async fn insert_id(&self, id: impl Id, record: E) -> Result<()> {
let id_str = id.into();
let data = serde_json::to_value(&record).context("Serialization failed")?;
let filtered_table = self.clone().with_id(id);
let client = self.data_source().inner.lock().await;
client
.insert(&format!("{}:{}", self.table_name(), id_str), data)
.await
.context("SurrealDB insert failed")?;
Ok(())
}
async fn replace_id(&self, id: impl Id, record: E) -> Result<()> {
let id_str = id.into();
let data = serde_json::to_value(&record).context("Serialization failed")?;
let _filtered_table = self.clone().with_id(&id_str);
let client = self.data_source().inner.lock().await;
client
.update(&format!("{}:{}", self.table_name(), id_str), Some(data))
.await
.context("SurrealDB replace failed")?;
Ok(())
}
async fn patch_id(&self, id: impl Id, partial: serde_json::Value) -> Result<()> {
let id_str = id.into();
let record_id = format!("{}:{}", self.table_name(), id_str);
let _filtered_table = self.clone().with_id(&id_str);
let client = self.data_source().inner.lock().await;
client
.merge(&record_id, partial)
.await
.context("SurrealDB patch failed")?;
Ok(())
}
async fn delete_id(&self, id: impl Id) -> Result<()> {
let id_str = id.into();
let record_id = format!("{}:{}", self.table_name(), id_str);
let _filtered_table = self.clone().with_id(&id_str);
let client = self.data_source().inner.lock().await;
client
.delete(&record_id)
.await
.context("SurrealDB delete failed")?;
Ok(())
}
async fn update<F>(&self, callback: F) -> Result<()>
where
F: Fn(&mut E) + Send + Sync,
{
use super::SurrealTableSelectable;
let records = self.get_with_ids().await?;
for (id, mut record) in records {
let original_record = record.clone();
callback(&mut record);
let original_value = serde_json::to_value(&original_record)
.context("Failed to serialize original record")?;
let new_value =
serde_json::to_value(&record).context("Failed to serialize modified record")?;
if original_value != new_value {
self.replace_id(id, record).await?;
}
}
Ok(())
}
async fn delete(&self) -> Result<()> {
use super::SurrealTableSelectable;
let records = self.get_with_ids().await?;
for (id, _) in records {
self.delete_id(id).await?;
}
Ok(())
}
}
#[async_trait]
impl<E> InsertableDataSet<E> for Table<SurrealDB, E>
where
E: Entity + Serialize + Send + Sync + 'static,
{
async fn insert(&self, record: E) -> Result<String> {
let data = serde_json::to_value(&record).context("Serialization failed")?;
let client = self.data_source().inner.lock().await;
let result = client
.insert(self.table_name(), data)
.await
.context("SurrealDB insert failed")?;
if let serde_json::Value::Array(results) = result {
if let Some(serde_json::Value::Object(obj)) = results.first() {
if let Some(serde_json::Value::String(id)) = obj.get("id") {
let clean_id = if let Some(colon_pos) = id.find(':') {
id[colon_pos + 1..].to_string()
} else {
id.clone()
};
return Ok(clean_id);
}
}
}
Err(vantage_error!("Failed to extract ID from insert result"))
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
struct TestEntity {
name: String,
value: i32,
}
impl Entity for TestEntity {}
#[test]
fn test_writable_api() {
}
}