kdb_connection/value/
de.rs1use 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 if is_typed_value(&map)
76 {
77 return serde_json::from_value(JsonValue::Object(map)).map_err(|e| e.into());
78 }
79
80 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 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 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 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}