Skip to main content

vantage_dataset/im/
dataset_writable.rs

1use async_trait::async_trait;
2use vantage_types::{Entity, Record, TryFromRecord, TryIntoRecord};
3
4use crate::{
5    im::ImTable,
6    traits::{Result, WritableDataSet},
7};
8
9#[async_trait]
10impl<E> WritableDataSet<E> for ImTable<E>
11where
12    E: Entity + Clone + Send + Sync,
13    <E as TryFromRecord<serde_json::Value>>::Error: std::fmt::Debug,
14    <E as TryIntoRecord<serde_json::Value>>::Error: std::fmt::Debug,
15{
16    async fn insert(&self, id: impl Into<Self::Id> + Send, entity: &E) -> Result<E> {
17        let id = id.into();
18        self.data_source.with_table_mut(&self.table_name, |table| {
19            // Check if record already exists (idempotent behavior)
20            if let Some(existing_record) = table.get(&id) {
21                // Return existing entity; add the id field back for conversion
22                let mut record_with_id = existing_record.clone();
23                record_with_id.insert("id".to_string(), serde_json::Value::String(id.clone()));
24
25                return E::try_from_record(&record_with_id).map_err(|e| {
26                    vantage_core::util::error::vantage_error!(
27                        "Failed to convert record to entity: {:?}",
28                        e
29                    )
30                });
31            }
32
33            // Convert entity to record for storage (remove id field since it's in the key)
34            let mut record: Record<serde_json::Value> =
35                entity.clone().try_into_record().map_err(|e| {
36                    vantage_core::util::error::vantage_error!(
37                        "Failed to serialize entity to record: {:?}",
38                        e
39                    )
40                })?;
41            record.shift_remove("id");
42
43            table.insert(id.clone(), record);
44            Ok(entity.clone())
45        })
46    }
47
48    async fn replace(&self, id: impl Into<Self::Id> + Send, entity: &E) -> Result<E> {
49        let id = id.into();
50        // Convert entity to record for storage (remove id field since it's in the key)
51        let mut record: Record<serde_json::Value> =
52            entity.clone().try_into_record().map_err(|e| {
53                vantage_core::util::error::vantage_error!(
54                    "Failed to serialize entity to record: {:?}",
55                    e
56                )
57            })?;
58        record.shift_remove("id");
59
60        self.data_source.with_table_mut(&self.table_name, |table| {
61            table.insert(id.clone(), record);
62        });
63
64        Ok(entity.clone())
65    }
66
67    async fn patch(&self, id: impl Into<Self::Id> + Send, partial: &E) -> Result<E> {
68        let id = id.into();
69        // Convert partial entity to record
70        let partial_record: Record<serde_json::Value> =
71            partial.clone().try_into_record().map_err(|e| {
72                vantage_core::util::error::vantage_error!(
73                    "Failed to serialize entity to record: {:?}",
74                    e
75                )
76            })?;
77
78        self.data_source.with_table_mut(&self.table_name, |table| {
79            // Check if record exists
80            let mut existing_record = table
81                .get(&id)
82                .ok_or_else(|| {
83                    vantage_core::util::error::vantage_error!("Record with id '{}' not found", id)
84                })?
85                .clone();
86
87            // Merge the partial fields into the existing record
88            for (key, value) in partial_record.iter() {
89                if key != "id" {
90                    // Don't allow patching the id field
91                    existing_record.insert(key.clone(), value.clone());
92                }
93            }
94
95            table.insert(id.clone(), existing_record.clone());
96
97            // Return the merged entity
98            let mut record_with_id = existing_record;
99            record_with_id.insert("id".to_string(), serde_json::Value::String(id));
100
101            E::try_from_record(&record_with_id).map_err(|e| {
102                vantage_core::util::error::vantage_error!(
103                    "Failed to convert record to entity: {:?}",
104                    e
105                )
106            })
107        })
108    }
109}
110
111// Tests are in tests/im_dataset.rs integration tests