Skip to main content

vantage_dataset/im/
valueset_insertable.rs

1use async_trait::async_trait;
2use vantage_types::Record;
3
4use crate::{im::ImTable, traits::InsertableValueSet};
5
6/// `InsertableValueSet` is only available for `V = serde_json::Value` because
7/// it inspects the record for an `"id"` field via JSON-specific accessors
8/// (`as_str`, `as_u64`, …). CBOR consumers carry their own id generation
9/// upstream (e.g. `MockTableSource::insert_table_value` constructs the id
10/// before calling into `ImTable`).
11#[async_trait]
12impl<E> InsertableValueSet for ImTable<E, serde_json::Value>
13where
14    E: Send + Sync,
15{
16    async fn insert_return_id_value(
17        &self,
18        record: &Record<Self::Value>,
19    ) -> crate::traits::Result<Self::Id> {
20        // Extract ID from record if present, otherwise generate random ID
21        let id = if let Some(record_id) = record.get("id") {
22            if record_id.is_null() {
23                self.generate_id()
24            } else if let Some(id_str) = record_id.as_str() {
25                if id_str.is_empty() {
26                    self.generate_id()
27                } else {
28                    id_str.to_string()
29                }
30            } else if let Some(id_num) = record_id.as_u64() {
31                id_num.to_string()
32            } else {
33                self.generate_id()
34            }
35        } else {
36            self.generate_id()
37        };
38
39        self.data_source.with_table_mut(&self.table_name, |table| {
40            table.insert(id.clone(), record.clone())
41        });
42
43        Ok(id)
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50    use crate::im::ImDataSource;
51    use serde::{Deserialize, Serialize};
52
53    #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
54    struct User {
55        id: Option<String>,
56        name: String,
57    }
58
59    #[tokio::test]
60    async fn test_insert_return_id_value() {
61        let ds = ImDataSource::new();
62        let table = ImTable::<User>::new(&ds, "users");
63
64        let mut record = Record::new();
65        record.insert(
66            "name".to_string(),
67            serde_json::Value::String("Alice".to_string()),
68        );
69        let id = table.insert_return_id_value(&record).await.unwrap();
70        assert!(!id.is_empty());
71    }
72
73    #[tokio::test]
74    async fn test_insert_return_id_value_with_existing_id() {
75        let ds = ImDataSource::new();
76        let table = ImTable::<User>::new(&ds, "users");
77
78        let mut record = Record::new();
79        record.insert(
80            "id".to_string(),
81            serde_json::Value::String("user-123".to_string()),
82        );
83        record.insert(
84            "name".to_string(),
85            serde_json::Value::String("Bob".to_string()),
86        );
87        let id = table.insert_return_id_value(&record).await.unwrap();
88        assert_eq!(id, "user-123");
89    }
90
91    #[tokio::test]
92    async fn test_insert_return_id_value_with_null_id() {
93        let ds = ImDataSource::new();
94        let table = ImTable::<User>::new(&ds, "users");
95
96        let mut record = Record::new();
97        record.insert("id".to_string(), serde_json::Value::Null);
98        record.insert(
99            "name".to_string(),
100            serde_json::Value::String("Charlie".to_string()),
101        );
102        let id = table.insert_return_id_value(&record).await.unwrap();
103        assert!(!id.is_empty());
104        assert_ne!(id, "null");
105    }
106}