• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

getdozer / dozer / 5709656380

pending completion
5709656380

push

github

web-flow
Version bump (#1808)

45512 of 59772 relevant lines covered (76.14%)

39312.43 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

54.91
/dozer-types/src/json_types.rs
1
use crate::errors::types::{CannotConvertF64ToJson, DeserializationError};
2
use crate::types::{DozerDuration, Field, DATE_FORMAT};
3
use chrono::SecondsFormat;
4
use ordered_float::OrderedFloat;
5
use prost_types::value::Kind;
6
use prost_types::{ListValue, Struct, Value as ProstValue};
7
use rust_decimal::prelude::FromPrimitive;
8
use serde::{Deserialize, Serialize};
9
use serde_json::{Map, Number, Value};
10
use std::borrow::Cow;
11
use std::collections::BTreeMap;
12
use std::fmt::{Display, Formatter};
13
use std::str::FromStr;
14

15
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord, Hash)]
148,896✔
16
pub enum JsonValue {
17
    Null,
18
    Bool(bool),
19
    Number(OrderedFloat<f64>),
20
    String(String),
21
    Array(Vec<JsonValue>),
22
    Object(BTreeMap<String, JsonValue>),
23
}
24

25
#[allow(clippy::derivable_impls)]
26
impl Default for JsonValue {
27
    fn default() -> JsonValue {
×
28
        JsonValue::Null
×
29
    }
×
30
}
31

32
impl JsonValue {
33
    pub fn as_array(&self) -> Option<&Vec<JsonValue>> {
156✔
34
        match self {
156✔
35
            JsonValue::Array(array) => Some(array),
156✔
36
            _ => None,
×
37
        }
38
    }
156✔
39

40
    pub fn as_object(&self) -> Option<&BTreeMap<String, JsonValue>> {
×
41
        match self {
×
42
            JsonValue::Object(map) => Some(map),
×
43
            _ => None,
×
44
        }
45
    }
×
46

47
    pub fn as_str(&self) -> Option<&str> {
2✔
48
        match self {
2✔
49
            JsonValue::String(s) => Some(s),
×
50
            _ => None,
2✔
51
        }
52
    }
2✔
53

54
    pub fn as_i64(&self) -> Option<i64> {
1✔
55
        match self {
1✔
56
            JsonValue::Number(n) => Some(n.0 as i64),
×
57
            _ => None,
1✔
58
        }
59
    }
1✔
60

61
    pub fn as_i128(&self) -> Option<i128> {
1✔
62
        match self {
1✔
63
            JsonValue::Number(n) => i128::from_f64(n.0),
×
64
            _ => None,
1✔
65
        }
66
    }
1✔
67

68
    pub fn as_u64(&self) -> Option<u64> {
156✔
69
        match self {
156✔
70
            JsonValue::Number(n) => Some(n.0 as u64),
156✔
71
            _ => None,
×
72
        }
73
    }
156✔
74

75
    pub fn as_u128(&self) -> Option<u128> {
1✔
76
        match self {
1✔
77
            JsonValue::Number(n) => u128::from_f64(n.0),
×
78
            _ => None,
1✔
79
        }
80
    }
1✔
81

82
    pub fn as_f64(&self) -> Option<f64> {
1✔
83
        match self {
1✔
84
            JsonValue::Number(n) => Some(n.0),
×
85
            _ => None,
1✔
86
        }
87
    }
1✔
88

89
    pub fn as_bool(&self) -> Option<bool> {
1✔
90
        match *self {
1✔
91
            JsonValue::Bool(b) => Some(b),
×
92
            _ => None,
1✔
93
        }
94
    }
1✔
95

96
    pub fn as_null(&self) -> Option<()> {
1✔
97
        match *self {
1✔
98
            JsonValue::Null => Some(()),
×
99
            _ => None,
1✔
100
        }
101
    }
1✔
102
}
103

104
impl Display for JsonValue {
105
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
29✔
106
        match self {
29✔
107
            JsonValue::Null => f.write_str("NULL"),
×
108
            JsonValue::Bool(v) => f.write_str(&format!("{v}")),
×
109
            JsonValue::Number(v) => f.write_str(&format!("{v}")),
25✔
110
            JsonValue::String(v) => f.write_str(&v.to_string()),
×
111
            JsonValue::Array(v) => {
4✔
112
                let list: Vec<String> = v.iter().map(|val| format!("{val}")).collect();
12✔
113
                let data = &format!("[{}]", list.join(","));
4✔
114
                f.write_str(data)
4✔
115
            }
116
            JsonValue::Object(v) => {
×
117
                let list: Vec<String> = v.iter().map(|(key, val)| format!("{key}:{val}")).collect();
×
118
                let data = &format!("{{ {} }}", list.join(","));
×
119
                f.write_str(data)
×
120
            }
121
        }
122
    }
29✔
123
}
124

125
impl FromStr for JsonValue {
126
    type Err = DeserializationError;
127

128
    fn from_str(s: &str) -> Result<Self, Self::Err> {
56✔
129
        let object = serde_json::from_str(s);
56✔
130
        if object.is_ok() {
56✔
131
            serde_json_to_json_value(object?)
16✔
132
        } else {
133
            let f = OrderedFloat::from_str(s)
40✔
134
                .map_err(|e| DeserializationError::Custom(Box::from(format!("{:?}", e))));
40✔
135
            if f.is_ok() {
40✔
136
                Ok(JsonValue::Number(f?))
×
137
            } else {
138
                let b = bool::from_str(s)
40✔
139
                    .map_err(|e| DeserializationError::Custom(Box::from(format!("{:?}", e))));
40✔
140
                if b.is_ok() {
40✔
141
                    Ok(JsonValue::Bool(b?))
×
142
                } else {
143
                    Ok(JsonValue::String(String::from(s)))
40✔
144
                }
145
            }
146
        }
147
    }
56✔
148
}
149

150
impl From<usize> for JsonValue {
151
    fn from(f: usize) -> Self {
×
152
        From::from(f as f64)
×
153
    }
×
154
}
155

156
impl From<f32> for JsonValue {
157
    fn from(f: f32) -> Self {
×
158
        From::from(f as f64)
×
159
    }
×
160
}
161

162
impl From<f64> for JsonValue {
163
    fn from(f: f64) -> Self {
78✔
164
        JsonValue::Number(OrderedFloat(f))
78✔
165
    }
78✔
166
}
167

168
impl From<bool> for JsonValue {
169
    fn from(f: bool) -> Self {
×
170
        JsonValue::Bool(f)
×
171
    }
×
172
}
173

174
impl From<String> for JsonValue {
175
    fn from(f: String) -> Self {
×
176
        JsonValue::String(f)
×
177
    }
×
178
}
179

180
impl<'a> From<&'a str> for JsonValue {
181
    fn from(f: &str) -> Self {
×
182
        JsonValue::String(f.to_string())
×
183
    }
×
184
}
185

186
impl<'a> From<Cow<'a, str>> for JsonValue {
187
    fn from(f: Cow<'a, str>) -> Self {
×
188
        JsonValue::String(f.into_owned())
×
189
    }
×
190
}
191

192
impl From<OrderedFloat<f64>> for JsonValue {
193
    fn from(f: OrderedFloat<f64>) -> Self {
×
194
        JsonValue::Number(f)
×
195
    }
×
196
}
197

198
impl From<BTreeMap<String, JsonValue>> for JsonValue {
199
    fn from(f: BTreeMap<String, JsonValue>) -> Self {
×
200
        JsonValue::Object(f)
×
201
    }
×
202
}
203

204
impl<T: Into<JsonValue>> From<Vec<T>> for JsonValue {
205
    fn from(f: Vec<T>) -> Self {
×
206
        JsonValue::Array(f.into_iter().map(Into::into).collect())
×
207
    }
×
208
}
209

210
impl<'a, T: Clone + Into<JsonValue>> From<&'a [T]> for JsonValue {
211
    fn from(f: &'a [T]) -> Self {
×
212
        JsonValue::Array(f.iter().cloned().map(Into::into).collect())
×
213
    }
×
214
}
215

216
impl<T: Into<JsonValue>> FromIterator<T> for JsonValue {
217
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
×
218
        JsonValue::Array(iter.into_iter().map(Into::into).collect())
×
219
    }
×
220
}
221

222
impl<K: Into<String>, V: Into<JsonValue>> FromIterator<(K, V)> for JsonValue {
223
    fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
×
224
        JsonValue::Object(
×
225
            iter.into_iter()
×
226
                .map(|(k, v)| (k.into(), v.into()))
×
227
                .collect(),
×
228
        )
×
229
    }
×
230
}
231

232
impl From<()> for JsonValue {
233
    fn from((): ()) -> Self {
×
234
        JsonValue::Null
×
235
    }
×
236
}
237

238
impl<T> From<Option<T>> for JsonValue
239
where
240
    T: Into<JsonValue>,
241
{
242
    fn from(opt: Option<T>) -> Self {
×
243
        match opt {
×
244
            None => JsonValue::Null,
×
245
            Some(value) => Into::into(value),
×
246
        }
247
    }
×
248
}
249

250
fn convert_x_y_to_object((x, y): &(OrderedFloat<f64>, OrderedFloat<f64>)) -> Value {
1✔
251
    let mut m = Map::new();
1✔
252
    m.insert("x".to_string(), Value::from(x.0));
1✔
253
    m.insert("y".to_string(), Value::from(y.0));
1✔
254
    Value::Object(m)
1✔
255
}
1✔
256

257
fn convert_duration_to_object(d: &DozerDuration) -> Value {
1✔
258
    let mut m = Map::new();
1✔
259
    m.insert("value".to_string(), Value::from(d.0.as_nanos().to_string()));
1✔
260
    m.insert("time_unit".to_string(), Value::from(d.1.to_string()));
1✔
261
    Value::Object(m)
1✔
262
}
1✔
263

264
/// Should be consistent with `convert_cache_type_to_schema_type`.
265
pub fn field_to_json_value(field: Field) -> Result<Value, CannotConvertF64ToJson> {
20,358✔
266
    match field {
20,358✔
267
        Field::UInt(n) => Ok(Value::from(n)),
8,139✔
268
        Field::U128(n) => Ok(Value::String(n.to_string())),
×
269
        Field::Int(n) => Ok(Value::from(n)),
1✔
270
        Field::I128(n) => Ok(Value::String(n.to_string())),
×
271
        Field::Float(n) => Ok(Value::from(n.0)),
1✔
272
        Field::Boolean(b) => Ok(Value::from(b)),
1✔
273
        Field::String(s) => Ok(Value::from(s)),
4,070✔
274
        Field::Text(n) => Ok(Value::from(n)),
1✔
275
        Field::Binary(b) => Ok(Value::from(b)),
1✔
276
        Field::Decimal(n) => Ok(Value::String(n.to_string())),
1✔
277
        Field::Timestamp(ts) => Ok(Value::String(
1✔
278
            ts.to_rfc3339_opts(SecondsFormat::Millis, true),
1✔
279
        )),
1✔
280
        Field::Date(n) => Ok(Value::String(n.format(DATE_FORMAT).to_string())),
1✔
281
        Field::Json(b) => json_value_to_serde_json(b),
1✔
282
        Field::Point(point) => Ok(convert_x_y_to_object(&point.0.x_y())),
1✔
283
        Field::Duration(d) => Ok(convert_duration_to_object(&d)),
1✔
284
        Field::Null => Ok(Value::Null),
8,138✔
285
    }
286
}
20,358✔
287

288
pub fn json_value_to_serde_json(value: JsonValue) -> Result<Value, CannotConvertF64ToJson> {
13✔
289
    match value {
13✔
290
        JsonValue::Null => Ok(Value::Null),
×
291
        JsonValue::Bool(b) => Ok(Value::Bool(b)),
×
292
        JsonValue::Number(n) => match Number::from_f64(n.0) {
12✔
293
            Some(number) => Ok(Value::Number(number)),
12✔
294
            None => Err(CannotConvertF64ToJson(n.0)),
×
295
        },
296
        JsonValue::String(s) => Ok(Value::String(s)),
×
297
        JsonValue::Array(a) => {
1✔
298
            let mut lst: Vec<Value> = vec![];
1✔
299
            for val in a {
13✔
300
                lst.push(json_value_to_serde_json(val)?);
12✔
301
            }
×
302
            Ok(Value::Array(lst))
1✔
303
        }
×
304
        JsonValue::Object(o) => {
×
305
            let mut values: Map<String, Value> = Map::new();
×
306
            for (key, val) in o {
×
307
                values.insert(key, json_value_to_serde_json(val)?);
×
308
            }
×
309
            Ok(Value::Object(values))
×
310
        }
×
311
    }
312
}
13✔
313

314
pub fn prost_to_json_value(val: ProstValue) -> JsonValue {
×
315
    match val.kind {
×
316
        Some(v) => match v {
×
317
            Kind::NullValue(_) => JsonValue::Null,
×
318
            Kind::BoolValue(b) => JsonValue::Bool(b),
×
319
            Kind::NumberValue(n) => JsonValue::Number(OrderedFloat(n)),
×
320
            Kind::StringValue(s) => JsonValue::String(s),
×
321
            Kind::ListValue(l) => {
×
322
                JsonValue::Array(l.values.into_iter().map(prost_to_json_value).collect())
×
323
            }
×
324
            Kind::StructValue(s) => JsonValue::Object(
×
325
                s.fields
×
326
                    .into_iter()
×
327
                    .map(|(key, val)| (key, prost_to_json_value(val)))
×
328
                    .collect(),
×
329
            ),
×
330
        },
×
331
        None => JsonValue::Null,
×
332
    }
×
333
}
×
334

×
335
pub fn json_value_to_prost(val: JsonValue) -> ProstValue {
×
336
    ProstValue {
×
337
        kind: match val {
×
338
            JsonValue::Null => Some(Kind::NullValue(0)),
×
339
            JsonValue::Bool(b) => Some(Kind::BoolValue(b)),
×
340
            JsonValue::Number(n) => Some(Kind::NumberValue(*n)),
×
341
            JsonValue::String(s) => Some(Kind::StringValue(s)),
×
342
            JsonValue::Array(a) => {
×
343
                let values: prost::alloc::vec::Vec<ProstValue> =
×
344
                    a.into_iter().map(json_value_to_prost).collect();
×
345
                Some(Kind::ListValue(ListValue { values }))
×
346
            }
×
347
            JsonValue::Object(o) => {
×
348
                let fields: prost::alloc::collections::BTreeMap<
×
349
                    prost::alloc::string::String,
×
350
                    ProstValue,
×
351
                > = o
×
352
                    .into_iter()
×
353
                    .map(|(key, val)| (key, json_value_to_prost(val)))
×
354
                    .collect();
×
355
                Some(Kind::StructValue(Struct { fields }))
×
356
            }
×
357
        },
×
358
    }
×
359
}
×
360

361
pub fn serde_json_to_json_value(value: Value) -> Result<JsonValue, DeserializationError> {
1,875✔
362
    match value {
1,875✔
363
        Value::Null => Ok(JsonValue::Null),
×
364
        Value::Bool(b) => Ok(JsonValue::Bool(b)),
13✔
365
        Value::Number(n) => Ok(JsonValue::Number(OrderedFloat(match n.as_f64() {
388✔
366
            Some(f) => f,
388✔
367
            None => return Err(DeserializationError::F64TypeConversionError(n)),
×
368
        }))),
×
369
        Value::String(s) => Ok(JsonValue::String(s)),
729✔
370
        Value::Array(a) => {
185✔
371
            let mut lst = vec![];
185✔
372
            for val in a {
625✔
373
                lst.push(serde_json_to_json_value(val)?);
440✔
374
            }
×
375
            Ok(JsonValue::Array(lst))
185✔
376
        }
×
377
        Value::Object(o) => {
560✔
378
            let mut values: BTreeMap<String, JsonValue> = BTreeMap::<String, JsonValue>::new();
560✔
379
            for (key, val) in o {
1,653✔
380
                values.insert(key, serde_json_to_json_value(val)?);
1,093✔
381
            }
×
382
            Ok(JsonValue::Object(values))
560✔
383
        }
×
384
    }
385
}
1,875✔
386

387
#[cfg(test)]
388
mod tests {
×
389
    use crate::{
390
        chrono::{NaiveDate, Offset, TimeZone, Utc},
391
        json_value_to_field,
392
        ordered_float::OrderedFloat,
393
        rust_decimal::Decimal,
394
        types::{DozerPoint, Field, FieldType, TimeUnit},
395
    };
396

397
    use std::time::Duration;
398

399
    use super::*;
400

401
    fn test_field_conversion(field_type: FieldType, field: Field) {
13✔
402
        // Convert the field to a JSON value.
13✔
403
        let value = field_to_json_value(field.clone());
13✔
404

13✔
405
        // Convert the JSON value back to a Field.
13✔
406
        let deserialized = json_value_to_field(value.unwrap(), field_type, true).unwrap();
13✔
407

13✔
408
        assert_eq!(deserialized, field, "must be equal");
13✔
409
    }
13✔
410

×
411
    #[test]
1✔
412
    fn test_field_types_json_conversion() {
1✔
413
        let fields = vec![
1✔
414
            (FieldType::Int, Field::Int(-1)),
1✔
415
            (FieldType::UInt, Field::UInt(1)),
1✔
416
            (FieldType::Float, Field::Float(OrderedFloat(1.1))),
1✔
417
            (FieldType::Boolean, Field::Boolean(true)),
1✔
418
            (FieldType::String, Field::String("a".to_string())),
1✔
419
            (FieldType::Binary, Field::Binary(b"asdf".to_vec())),
1✔
420
            (FieldType::Decimal, Field::Decimal(Decimal::new(202, 2))),
1✔
421
            (
1✔
422
                FieldType::Timestamp,
1✔
423
                Field::Timestamp(Utc.fix().with_ymd_and_hms(2001, 1, 1, 0, 4, 0).unwrap()),
1✔
424
            ),
1✔
425
            (
1✔
426
                FieldType::Date,
1✔
427
                Field::Date(NaiveDate::from_ymd_opt(2022, 11, 24).unwrap()),
1✔
428
            ),
1✔
429
            (
1✔
430
                FieldType::Json,
1✔
431
                Field::Json(JsonValue::Array(vec![
1✔
432
                    JsonValue::Number(OrderedFloat(123_f64)),
1✔
433
                    JsonValue::Number(OrderedFloat(34_f64)),
1✔
434
                    JsonValue::Number(OrderedFloat(97_f64)),
1✔
435
                    JsonValue::Number(OrderedFloat(98_f64)),
1✔
436
                    JsonValue::Number(OrderedFloat(99_f64)),
1✔
437
                    JsonValue::Number(OrderedFloat(34_f64)),
1✔
438
                    JsonValue::Number(OrderedFloat(58_f64)),
1✔
439
                    JsonValue::Number(OrderedFloat(34_f64)),
1✔
440
                    JsonValue::Number(OrderedFloat(102_f64)),
1✔
441
                    JsonValue::Number(OrderedFloat(111_f64)),
1✔
442
                    JsonValue::Number(OrderedFloat(111_f64)),
1✔
443
                    JsonValue::Number(OrderedFloat(34_f64)),
1✔
444
                ])),
1✔
445
            ),
1✔
446
            (FieldType::Text, Field::Text("lorem ipsum".to_string())),
1✔
447
            (
1✔
448
                FieldType::Point,
1✔
449
                Field::Point(DozerPoint::from((3.234, 4.567))),
1✔
450
            ),
1✔
451
            (
1✔
452
                FieldType::Duration,
1✔
453
                Field::Duration(DozerDuration(
1✔
454
                    Duration::from_nanos(123_u64),
1✔
455
                    TimeUnit::Nanoseconds,
1✔
456
                )),
1✔
457
            ),
1✔
458
        ];
1✔
459
        for (field_type, field) in fields {
14✔
460
            test_field_conversion(field_type, field);
13✔
461
        }
13✔
462
    }
1✔
463
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc