Skip to main content

kdb_connection/value/
de.rs

1use serde::Deserialize;
2use serde::de::Deserializer;
3use serde::de::Error as _;
4use serde_json::Value as JsonValue;
5
6use crate::ValueArray;
7use crate::ValueHash;
8use crate::errors::Error;
9
10use super::{Value, ValueData};
11
12impl<'de> Deserialize<'de> for ValueData
13{
14    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
15    where
16        D: Deserializer<'de>,
17    {
18        let json = serde_json::Value::deserialize(deserializer)?;
19        let value = lift_json(json).map_err(D::Error::custom)?;
20        Ok(value.value)
21    }
22}
23
24fn is_typed_value(map: &serde_json::Map<String, serde_json::Value>) -> bool
25{
26    (map.len() == 2
27        || (map.len() == 3
28            && map.get("type").is_some_and(|x| match x
29            {
30                serde_json::Value::String(string) => string == "literal",
31                _ => false,
32            })))
33        && map
34            .get("datatype")
35            .is_some_and(|x| matches!(x, serde_json::Value::String(_)))
36        && map.contains_key("value")
37}
38
39fn lift_json(j: JsonValue) -> Result<Value, crate::Error>
40{
41    Ok(match j
42    {
43        JsonValue::Null => ValueData::Null.into(),
44
45        JsonValue::Bool(b) => b.into(),
46
47        JsonValue::Number(n) =>
48        {
49            if let Some(i) = n.as_i64()
50            {
51                ValueData::Integer64(i).into()
52            }
53            else if let Some(f) = n.as_f64()
54            {
55                ValueData::Float64(f).into()
56            }
57            else
58            {
59                return Err(Error::UnsupportedNumber);
60            }
61        }
62
63        JsonValue::String(s) => s.into(),
64
65        JsonValue::Array(arr) =>
66        {
67            let values: ValueArray = arr.into_iter().map(lift_json).collect::<Result<_, _>>()?;
68
69            values.into()
70        }
71
72        JsonValue::Object(map) =>
73        {
74            // 1. Already a typed Value → preserve exactly
75            if is_typed_value(&map)
76            {
77                return serde_json::from_value(JsonValue::Object(map)).map_err(|e| e.into());
78            }
79
80            // 2. Raw object → valuehash
81            let values: ValueHash = map
82                .into_iter()
83                .map(|(k, v)| lift_json(v).map(|val| (k, val)))
84                .collect::<Result<_, _>>()?;
85
86            values.into()
87        }
88    })
89}
90
91#[derive(Deserialize)]
92struct RawValue
93{
94    #[serde(default)]
95    datatype: Option<String>,
96    value: ValueData,
97}
98
99fn guess_datatype(value: &ValueData) -> &'static str
100{
101    match value
102    {
103        ValueData::Null => "http://www.w3.org/2001/XMLSchema#nil",
104        ValueData::Boolean(_) => "http://www.w3.org/2001/XMLSchema#bool",
105        ValueData::Integer64(_) => "http://www.w3.org/2001/XMLSchema#long",
106        ValueData::Float64(_) => "http://www.w3.org/2001/XMLSchema#float64",
107        ValueData::String(_) => "http://www.w3.org/2001/XMLSchema#string",
108        ValueData::Map(_) => "http://askco.re/datatype#valuehash",
109        ValueData::Array(_) => "http://askco.re/datatype#valuelist",
110    }
111}
112
113impl<'de> Deserialize<'de> for Value
114{
115    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
116    where
117        D: Deserializer<'de>,
118    {
119        let raw = RawValue::deserialize(deserializer)?;
120
121        let datatype = match raw.datatype
122        {
123            Some(dt) => dt,
124            None => guess_datatype(&raw.value).to_string(),
125        };
126
127        Ok(Value {
128            datatype,
129            value: raw.value,
130        })
131    }
132}
133
134#[cfg(test)]
135mod tests
136{
137    use super::*;
138    use crate::{ValueArray, ValueHash, test::validate_dataset_0};
139
140    #[test]
141    fn test_agent_deserialization()
142    {
143        let raw_json = serde_json::json!({
144            "datatype": "http://askco.re/datatype#valuelist",
145            "type": "literal",
146            "value": [
147                {
148                    "datatype": "http://askco.re/datatype#valuehash",
149                    "value": {
150                        "object_uri": {
151                            "datatype": "http://www.w3.org/2001/XMLSchema#anyURI",
152                            "value": "http://example.org/agent/0"
153                        },
154                        "properties": {
155                            "datatype": "http://askco.re/datatype#valuehash",
156                            "value": {
157                                "http://askco.re/agent#agent_type": {
158                                    "datatype": "http://www.w3.org/2001/XMLSchema#anyURI",
159                                    "value": "http://askco.re/agent#uav"
160                                },
161                                "http://askco.re/agent#frame": {
162                                    "datatype": "http://www.w3.org/2001/XMLSchema#string",
163                                    "value": "agent0"
164                                },
165                                "http://xmlns.com/foaf/0.1/name": {
166                                    "datatype": "http://www.w3.org/2001/XMLSchema#string",
167                                    "value": "test agent"
168                                }
169                            }
170                        },
171                        "type_uri": {
172                            "datatype": "http://www.w3.org/2001/XMLSchema#anyURI",
173                            "value": "http://askco.re/agent#uav"
174                        }
175                    }
176                }
177            ]
178        });
179        // Parse JSON into Value
180        let agents: Value = serde_json::from_value(raw_json).unwrap();
181        let agents: ValueArray = agents.to_owned().try_into().unwrap();
182        let agent_0: ValueHash = agents.into_iter().next().unwrap().try_into().unwrap();
183
184        crate::test::validate_agent_0(agent_0);
185    }
186
187    #[test]
188    fn test_dataset_deserialization()
189    {
190        // JSON input (simplified, matching your examples)
191        let raw_json = serde_json::json!({
192            "datatype": "http://askco.re/datatype#valuehash",
193            "value": {
194                "object_uri": {
195                    "datatype": "http://www.w3.org/2001/XMLSchema#anyURI",
196                    "value": "http://example.org/dataset/0"
197                },
198                "type_uri": {
199                    "datatype": "http://www.w3.org/2001/XMLSchema#anyURI",
200                    "value": "http://askco.re/dataset#point_cloud_dataset"
201                },
202                "properties": {
203                    "datatype": "http://askco.re/datatype#valuehash",
204                    "value": {
205                        "http://askco.re/dataset#content_type": {
206                            "datatype": "http://www.w3.org/2001/XMLSchema#anyURI",
207                            "value": "http://askco.re/sensing#point_cloud"
208                        },
209                        "http://askco.re/sensing#point_density": {
210                            "datatype": "http://askco.re/datatype#quantityDecimal",
211                            "value": {
212                                "value": 10,
213                                "unit": "point/m^2"
214                            }
215                        },
216                        "http://www.opengis.net/ont/geosparql#hasGeometry": {
217                            "datatype": "http://www.opengis.net/ont/geosparql#Geometry",
218                            "value": {
219                                "type": "Polygon",
220                                "coordinates": [
221                                    [
222                                        [30, 10],
223                                        [40, 40],
224                                        [20, 40],
225                                        [10, 20],
226                                        [30, 10]
227                                    ]
228                                ]
229                            }
230                        }
231                    }
232                }
233            }
234        });
235
236        // Parse JSON into Value
237        let dataset_0: Value = serde_json::from_value(raw_json).unwrap();
238        let dataset_0: ValueHash = dataset_0.to_owned().try_into().unwrap();
239
240        validate_dataset_0(dataset_0);
241    }
242}