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

getdozer / dozer / 4414871180

pending completion
4414871180

push

github

GitHub
feat: add object store validation (#1140)

40 of 40 new or added lines in 2 files covered. (100.0%)

28658 of 39135 relevant lines covered (73.23%)

92989.89 hits per line

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

67.07
/dozer-types/src/types/field.rs
1
use crate::errors::types::{DeserializationError, TypeError};
2
#[allow(unused_imports)]
3
use chrono::{DateTime, Datelike, FixedOffset, LocalResult, NaiveDate, TimeZone, Utc};
4
use ordered_float::OrderedFloat;
5
use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
6
use rust_decimal::Decimal;
7
use serde::{self, Deserialize, Serialize};
8
use std::borrow::Cow;
9

10
use crate::types::DozerPoint;
11
use std::fmt::{Display, Formatter};
12

13
pub const DATE_FORMAT: &str = "%Y-%m-%d";
14
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord, Hash)]
86,011,117✔
15
pub enum Field {
16
    UInt(u64),
17
    Int(i64),
18
    Float(OrderedFloat<f64>),
19
    Boolean(bool),
20
    String(String),
21
    Text(String),
22
    Binary(Vec<u8>),
23
    Decimal(Decimal),
24
    Timestamp(DateTime<FixedOffset>),
25
    Date(NaiveDate),
26
    Bson(Vec<u8>),
27
    Point(DozerPoint),
28
    Null,
29
}
30

31
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord)]
2,647,638✔
32
pub enum FieldBorrow<'a> {
33
    UInt(u64),
34
    Int(i64),
35
    Float(OrderedFloat<f64>),
36
    Boolean(bool),
37
    String(&'a str),
38
    Text(&'a str),
39
    Binary(&'a [u8]),
40
    Decimal(Decimal),
41
    Timestamp(DateTime<FixedOffset>),
42
    Date(NaiveDate),
43
    Bson(&'a [u8]),
44
    Point(DozerPoint),
45
    Null,
46
}
47

48
impl Field {
49
    fn data_encoding_len(&self) -> usize {
8,308,362✔
50
        match self {
8,308,362✔
51
            Field::UInt(_) => 8,
290,317✔
52
            Field::Int(_) => 8,
778,795✔
53
            Field::Float(_) => 8,
102,739✔
54
            Field::Boolean(_) => 1,
7,522✔
55
            Field::String(s) => s.len(),
6,978,559✔
56
            Field::Text(s) => s.len(),
7,539✔
57
            Field::Binary(b) => b.len(),
7,522✔
58
            Field::Decimal(_) => 16,
7,522✔
59
            Field::Timestamp(_) => 8,
7,539✔
60
            Field::Date(_) => 10,
7,573✔
61
            Field::Bson(b) => b.len(),
3,795✔
62
            Field::Point(_p) => 16,
×
63
            Field::Null => 0,
108,940✔
64
        }
65
    }
8,308,362✔
66

67
    fn encode_data(&self) -> Cow<[u8]> {
8,086,473✔
68
        match self {
8,086,473✔
69
            Field::UInt(i) => Cow::Owned(i.to_be_bytes().into()),
216,654✔
70
            Field::Int(i) => Cow::Owned(i.to_be_bytes().into()),
770,123✔
71
            Field::Float(f) => Cow::Owned(f.to_be_bytes().into()),
60,900✔
72
            Field::Boolean(b) => Cow::Owned(if *b { [1] } else { [0] }.into()),
3,797✔
73
            Field::String(s) => Cow::Borrowed(s.as_bytes()),
6,932,504✔
74
            Field::Text(s) => Cow::Borrowed(s.as_bytes()),
3,797✔
75
            Field::Binary(b) => Cow::Borrowed(b.as_slice()),
3,797✔
76
            Field::Decimal(d) => Cow::Owned(d.serialize().into()),
3,763✔
77
            Field::Timestamp(t) => Cow::Owned(t.timestamp_millis().to_be_bytes().into()),
3,797✔
78
            Field::Date(t) => Cow::Owned(t.to_string().into()),
3,780✔
79
            Field::Bson(b) => Cow::Borrowed(b),
1,907✔
80
            Field::Null => Cow::Owned([].into()),
81,654✔
81
            Field::Point(p) => Cow::Owned(p.to_bytes().into()),
×
82
        }
83
    }
8,086,473✔
84

85
    pub fn encode_buf(&self, destination: &mut [u8]) {
8,152,807✔
86
        let prefix = self.get_type_prefix();
8,152,807✔
87
        let data = self.encode_data();
8,152,807✔
88
        destination[0] = prefix;
8,152,807✔
89
        destination[1..].copy_from_slice(&data);
8,152,807✔
90
    }
8,152,807✔
91

92
    pub fn encoding_len(&self) -> usize {
8,330,802✔
93
        self.data_encoding_len() + 1
8,330,802✔
94
    }
8,330,802✔
95

96
    pub fn encode(&self) -> Vec<u8> {
7,835,825✔
97
        let mut result = vec![0; self.encoding_len()];
7,835,825✔
98
        self.encode_buf(&mut result);
7,835,825✔
99
        result
7,835,825✔
100
    }
7,835,825✔
101

102
    pub fn borrow(&self) -> FieldBorrow {
16,852✔
103
        match self {
16,852✔
104
            Field::UInt(i) => FieldBorrow::UInt(*i),
1,532✔
105
            Field::Int(i) => FieldBorrow::Int(*i),
1,532✔
106
            Field::Float(f) => FieldBorrow::Float(*f),
1,532✔
107
            Field::Boolean(b) => FieldBorrow::Boolean(*b),
1,532✔
108
            Field::String(s) => FieldBorrow::String(s),
1,532✔
109
            Field::Text(s) => FieldBorrow::Text(s),
1,532✔
110
            Field::Binary(b) => FieldBorrow::Binary(b),
1,532✔
111
            Field::Decimal(d) => FieldBorrow::Decimal(*d),
1,532✔
112
            Field::Timestamp(t) => FieldBorrow::Timestamp(*t),
1,532✔
113
            Field::Date(t) => FieldBorrow::Date(*t),
1,532✔
114
            Field::Bson(b) => FieldBorrow::Bson(b),
766✔
115
            Field::Point(p) => FieldBorrow::Point(*p),
×
116
            Field::Null => FieldBorrow::Null,
766✔
117
        }
118
    }
16,852✔
119

120
    pub fn decode(buf: &[u8]) -> Result<Field, DeserializationError> {
22✔
121
        Self::decode_borrow(buf).map(|field| field.to_owned())
22✔
122
    }
22✔
123

124
    pub fn decode_borrow(buf: &[u8]) -> Result<FieldBorrow, DeserializationError> {
15,821,208✔
125
        let first_byte = *buf.first().ok_or(DeserializationError::EmptyInput)?;
15,821,208✔
126
        let val = &buf[1..];
15,821,208✔
127
        match first_byte {
15,821,208✔
128
            0 => Ok(FieldBorrow::UInt(u64::from_be_bytes(
129
                val.try_into()
10,126,664✔
130
                    .map_err(|_| DeserializationError::BadDataLength)?,
10,126,664✔
131
            ))),
132
            1 => Ok(FieldBorrow::Int(i64::from_be_bytes(
133
                val.try_into()
6,734✔
134
                    .map_err(|_| DeserializationError::BadDataLength)?,
6,734✔
135
            ))),
136
            2 => Ok(FieldBorrow::Float(OrderedFloat(f64::from_be_bytes(
137
                val.try_into()
1,769,906✔
138
                    .map_err(|_| DeserializationError::BadDataLength)?,
1,769,906✔
139
            )))),
140
            3 => Ok(FieldBorrow::Boolean(val[0] == 1)),
1,532✔
141
            4 => Ok(FieldBorrow::String(std::str::from_utf8(val)?)),
1,940✔
142
            5 => Ok(FieldBorrow::Text(std::str::from_utf8(val)?)),
1,532✔
143
            6 => Ok(FieldBorrow::Binary(val)),
1,532✔
144
            7 => Ok(FieldBorrow::Decimal(Decimal::deserialize(
145
                val.try_into()
1,532✔
146
                    .map_err(|_| DeserializationError::BadDataLength)?,
1,532✔
147
            ))),
148
            8 => {
149
                let timestamp = Utc.timestamp_millis_opt(i64::from_be_bytes(
1,532✔
150
                    val.try_into()
1,532✔
151
                        .map_err(|_| DeserializationError::BadDataLength)?,
1,532✔
152
                ));
153

154
                match timestamp {
1,532✔
155
                    LocalResult::Single(v) => Ok(FieldBorrow::Timestamp(DateTime::from(v))),
1,532✔
156
                    LocalResult::Ambiguous(_, _) => Err(DeserializationError::Custom(Box::new(
×
157
                        TypeError::AmbiguousTimestamp,
×
158
                    ))),
×
159
                    LocalResult::None => Err(DeserializationError::Custom(Box::new(
×
160
                        TypeError::InvalidTimestamp,
×
161
                    ))),
×
162
                }
163
            }
164
            9 => Ok(FieldBorrow::Date(NaiveDate::parse_from_str(
165
                std::str::from_utf8(val)?,
1,532✔
166
                DATE_FORMAT,
1,532✔
167
            )?)),
×
168
            10 => Ok(FieldBorrow::Bson(val)),
766✔
169
            11 => Ok(FieldBorrow::Point(
170
                DozerPoint::from_bytes(val).map_err(|_| DeserializationError::BadDataLength)?,
×
171
            )),
172
            12 => Ok(FieldBorrow::Null),
3,906,006✔
173
            other => Err(DeserializationError::UnrecognisedFieldType(other)),
×
174
        }
175
    }
15,879,042✔
176

177
    fn get_type_prefix(&self) -> u8 {
8,093,375✔
178
        match self {
8,093,375✔
179
            Field::UInt(_) => 0,
200,759✔
180
            Field::Int(_) => 1,
770,310✔
181
            Field::Float(_) => 2,
60,900✔
182
            Field::Boolean(_) => 3,
3,797✔
183
            Field::String(_) => 4,
6,955,114✔
184
            Field::Text(_) => 5,
3,797✔
185
            Field::Binary(_) => 6,
3,797✔
186
            Field::Decimal(_) => 7,
3,763✔
187
            Field::Timestamp(_) => 8,
3,797✔
188
            Field::Date(_) => 9,
3,780✔
189
            Field::Bson(_) => 10,
1,907✔
190
            Field::Point(_) => 11,
×
191
            Field::Null => 12,
81,654✔
192
        }
193
    }
8,093,375✔
194

195
    pub fn as_uint(&self) -> Option<u64> {
29,643,393✔
196
        match self {
29,643,393✔
197
            Field::UInt(i) => Some(*i),
27,544,012✔
198
            _ => None,
2,099,381✔
199
        }
200
    }
29,643,393✔
201

202
    pub fn as_int(&self) -> Option<i64> {
765✔
203
        match self {
765✔
204
            Field::Int(i) => Some(*i),
765✔
205
            _ => None,
×
206
        }
207
    }
765✔
208

209
    pub fn as_float(&self) -> Option<f64> {
4,232,830✔
210
        match self {
4,232,830✔
211
            Field::Float(f) => Some(f.0),
4,232,830✔
212
            _ => None,
×
213
        }
214
    }
4,232,830✔
215

216
    pub fn as_boolean(&self) -> Option<bool> {
1,020✔
217
        match self {
1,020✔
218
            Field::Boolean(b) => Some(*b),
1,020✔
219
            _ => None,
×
220
        }
221
    }
1,020✔
222

223
    pub fn as_string(&self) -> Option<&str> {
8,482,796✔
224
        match self {
8,482,796✔
225
            Field::String(s) => Some(s),
8,482,796✔
226
            _ => None,
×
227
        }
228
    }
8,482,796✔
229

230
    pub fn as_text(&self) -> Option<&str> {
34✔
231
        match self {
34✔
232
            Field::Text(s) => Some(s),
34✔
233
            _ => None,
×
234
        }
235
    }
34✔
236

237
    pub fn as_binary(&self) -> Option<&[u8]> {
×
238
        match self {
×
239
            Field::Binary(b) => Some(b),
×
240
            _ => None,
×
241
        }
242
    }
×
243

244
    pub fn as_decimal(&self) -> Option<Decimal> {
×
245
        match self {
×
246
            Field::Decimal(d) => Some(*d),
×
247
            _ => None,
×
248
        }
249
    }
×
250

251
    pub fn as_timestamp(&self) -> Option<DateTime<FixedOffset>> {
2,116,381✔
252
        match self {
2,116,381✔
253
            Field::Timestamp(t) => Some(*t),
2,116,381✔
254
            _ => None,
×
255
        }
256
    }
2,116,381✔
257

258
    pub fn as_date(&self) -> Option<NaiveDate> {
×
259
        match self {
×
260
            Field::Date(d) => Some(*d),
×
261
            _ => None,
×
262
        }
263
    }
×
264

265
    pub fn as_bson(&self) -> Option<&[u8]> {
×
266
        match self {
×
267
            Field::Bson(b) => Some(b),
×
268
            _ => None,
×
269
        }
270
    }
×
271

272
    pub fn as_point(&self) -> Option<DozerPoint> {
×
273
        match self {
×
274
            Field::Point(b) => Some(*b),
×
275
            _ => None,
×
276
        }
277
    }
×
278

279
    pub fn as_null(&self) -> Option<()> {
×
280
        match self {
×
281
            Field::Null => Some(()),
×
282
            _ => None,
×
283
        }
284
    }
×
285

286
    pub fn to_uint(&self) -> Option<u64> {
459✔
287
        match self {
459✔
288
            Field::UInt(i) => Some(*i),
459✔
289
            Field::Int(i) => u64::from_i64(*i),
×
290
            Field::String(s) => s.parse::<u64>().ok(),
×
291
            Field::Null => Some(0_u64),
×
292
            _ => None,
×
293
        }
294
    }
459✔
295

296
    pub fn to_int(&self) -> Option<i64> {
1,126,641✔
297
        match self {
1,126,641✔
298
            Field::Int(i) => Some(*i),
1,126,539✔
299
            Field::UInt(u) => i64::from_u64(*u),
17✔
300
            Field::String(s) => s.parse::<i64>().ok(),
17✔
301
            Field::Null => Some(0_i64),
68✔
302
            _ => None,
×
303
        }
304
    }
1,126,641✔
305

306
    pub fn to_float(&self) -> Option<f64> {
935✔
307
        match self {
935✔
308
            Field::Float(f) => Some(f.0),
799✔
309
            Field::Decimal(d) => d.to_f64(),
17✔
310
            Field::UInt(u) => f64::from_u64(*u),
17✔
311
            Field::Int(i) => f64::from_i64(*i),
17✔
312
            Field::Null => Some(0_f64),
68✔
313
            Field::String(s) => s.parse::<f64>().ok(),
17✔
314
            _ => None,
×
315
        }
316
    }
935✔
317

318
    pub fn to_boolean(&self) -> Option<bool> {
102✔
319
        match self {
102✔
320
            Field::Boolean(b) => Some(*b),
17✔
321
            Field::Null => Some(false),
×
322
            Field::Int(i) => Some(*i > 0_i64),
17✔
323
            Field::UInt(i) => Some(*i > 0_u64),
17✔
324
            Field::Float(i) => Some(i.0 > 0_f64),
17✔
325
            Field::Decimal(i) => Some(i.gt(&Decimal::from(0_u64))),
34✔
326
            _ => None,
×
327
        }
328
    }
102✔
329

330
    pub fn to_string(&self) -> Option<String> {
1,462✔
331
        match self {
1,462✔
332
            Field::String(s) => Some(s.to_owned()),
1,139✔
333
            Field::Text(t) => Some(t.to_owned()),
85✔
334
            Field::Int(i) => Some(format!("{i}")),
119✔
335
            Field::UInt(i) => Some(format!("{i}")),
17✔
336
            Field::Float(i) => Some(format!("{i}")),
17✔
337
            Field::Decimal(i) => Some(format!("{i}")),
17✔
338
            Field::Boolean(i) => Some(if *i {
17✔
339
                "TRUE".to_string()
17✔
340
            } else {
341
                "FALSE".to_string()
×
342
            }),
343
            Field::Date(d) => Some(d.format("%Y-%m-%d").to_string()),
17✔
344
            Field::Timestamp(t) => Some(t.to_rfc3339()),
17✔
345
            Field::Binary(b) => Some(format!("{b:X?}")),
×
346
            Field::Null => Some("".to_string()),
17✔
347
            _ => None,
×
348
        }
349
    }
1,462✔
350

351
    pub fn to_text(&self) -> Option<String> {
153✔
352
        match self {
153✔
353
            Field::String(s) => Some(s.to_owned()),
17✔
354
            Field::Text(t) => Some(t.to_owned()),
17✔
355
            Field::Int(i) => Some(format!("{i}")),
17✔
356
            Field::UInt(i) => Some(format!("{i}")),
17✔
357
            Field::Float(i) => Some(format!("{i}")),
17✔
358
            Field::Decimal(i) => Some(format!("{i}")),
17✔
359
            Field::Boolean(i) => Some(if *i {
17✔
360
                "TRUE".to_string()
17✔
361
            } else {
362
                "FALSE".to_string()
×
363
            }),
364
            Field::Date(d) => Some(d.format("%Y-%m-%d").to_string()),
17✔
365
            Field::Timestamp(t) => Some(t.to_rfc3339()),
17✔
366
            Field::Binary(b) => Some(format!("{b:X?}")),
×
367
            Field::Null => Some("".to_string()),
×
368
            _ => None,
×
369
        }
370
    }
153✔
371

372
    pub fn to_binary(&self) -> Option<&[u8]> {
×
373
        match self {
×
374
            Field::Binary(b) => Some(b),
×
375
            _ => None,
×
376
        }
377
    }
×
378

379
    pub fn to_decimal(&self) -> Option<Decimal> {
1,275✔
380
        match self {
1,275✔
381
            Field::Decimal(d) => Some(*d),
748✔
382
            Field::Float(f) => Decimal::from_f64_retain(f.0),
×
383
            Field::Int(i) => Decimal::from_i64(*i),
238✔
384
            Field::UInt(u) => Decimal::from_u64(*u),
221✔
385
            Field::Null => Some(Decimal::from(0)),
68✔
386
            Field::String(s) => Decimal::from_str_exact(s).ok(),
×
387
            _ => None,
×
388
        }
389
    }
1,275✔
390

391
    pub fn to_timestamp(&self) -> Result<Option<DateTime<FixedOffset>>, TypeError> {
306✔
392
        match self {
306✔
393
            Field::Timestamp(t) => Ok(Some(*t)),
306✔
394
            Field::String(s) => Ok(DateTime::parse_from_rfc3339(s.as_str()).ok()),
×
395
            Field::Null => match Utc.timestamp_millis_opt(0) {
×
396
                LocalResult::None => Err(TypeError::InvalidTimestamp),
×
397
                LocalResult::Single(v) => Ok(Some(DateTime::from(v))),
×
398
                LocalResult::Ambiguous(_, _) => Err(TypeError::AmbiguousTimestamp),
×
399
            },
400
            _ => Ok(None),
×
401
        }
402
    }
306✔
403

404
    pub fn to_date(&self) -> Result<Option<NaiveDate>, TypeError> {
306✔
405
        match self {
306✔
406
            Field::Date(d) => Ok(Some(*d)),
306✔
407
            Field::String(s) => Ok(NaiveDate::parse_from_str(s, "%Y-%m-%d").ok()),
×
408
            Field::Null => match Utc.timestamp_millis_opt(0) {
×
409
                LocalResult::None => Err(TypeError::InvalidTimestamp),
×
410
                LocalResult::Single(v) => Ok(Some(v.naive_utc().date())),
×
411
                LocalResult::Ambiguous(_, _) => Err(TypeError::AmbiguousTimestamp),
×
412
            },
413
            _ => Ok(None),
×
414
        }
415
    }
306✔
416

417
    pub fn to_bson(&self) -> Option<&[u8]> {
×
418
        match self {
×
419
            Field::Bson(b) => Some(b),
×
420
            _ => None,
×
421
        }
422
    }
×
423

424
    pub fn to_point(&self) -> Option<&DozerPoint> {
136✔
425
        match self {
136✔
426
            Field::Point(p) => Some(p),
136✔
427
            _ => None,
×
428
        }
429
    }
136✔
430

431
    pub fn to_null(&self) -> Option<()> {
×
432
        match self {
×
433
            Field::Null => Some(()),
×
434
            _ => None,
×
435
        }
436
    }
×
437
}
438

439
impl Display for Field {
440
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
5,712✔
441
        match self {
5,712✔
442
            Field::UInt(v) => f.write_str(&format!("{v} (unsigned int)")),
714✔
443
            Field::Int(v) => f.write_str(&format!("{v} (signed int)")),
1,802✔
444
            Field::Float(v) => f.write_str(&format!("{v} (Float)")),
748✔
445
            Field::Boolean(v) => f.write_str(&format!("{v}")),
×
446
            Field::String(v) => f.write_str(&v.to_string()),
×
447
            Field::Text(v) => f.write_str(&v.to_string()),
×
448
            Field::Binary(v) => f.write_str(&format!("{v:x?}")),
×
449
            Field::Decimal(v) => f.write_str(&format!("{v} (Decimal)")),
986✔
450
            Field::Timestamp(v) => f.write_str(&format!("{v}")),
578✔
451
            Field::Date(v) => f.write_str(&format!("{v}")),
680✔
452
            Field::Bson(v) => f.write_str(&format!("{v:x?}")),
×
453
            Field::Null => f.write_str("NULL"),
204✔
454
            Field::Point(v) => f.write_str(&format!("{v} (Point)")),
×
455
        }
456
    }
5,712✔
457
}
458

459
impl<'a> FieldBorrow<'a> {
460
    pub fn to_owned(self) -> Field {
41✔
461
        match self {
41✔
462
            FieldBorrow::Int(i) => Field::Int(i),
4✔
463
            FieldBorrow::UInt(i) => Field::UInt(i),
1✔
464
            FieldBorrow::Float(f) => Field::Float(f),
4✔
465
            FieldBorrow::Boolean(b) => Field::Boolean(b),
4✔
466
            FieldBorrow::String(s) => Field::String(s.to_owned()),
4✔
467
            FieldBorrow::Text(s) => Field::Text(s.to_owned()),
4✔
468
            FieldBorrow::Binary(b) => Field::Binary(b.to_owned()),
4✔
469
            FieldBorrow::Decimal(d) => Field::Decimal(d),
4✔
470
            FieldBorrow::Timestamp(t) => Field::Timestamp(t),
4✔
471
            FieldBorrow::Date(d) => Field::Date(d),
4✔
472
            FieldBorrow::Bson(b) => Field::Bson(b.to_owned()),
2✔
473
            FieldBorrow::Point(p) => Field::Point(p),
×
474
            FieldBorrow::Null => Field::Null,
2✔
475
        }
476
    }
41✔
477
}
478

479
#[derive(Clone, Copy, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord)]
3,623,072✔
480
pub enum FieldType {
481
    UInt,
482
    Int,
483
    Float,
484
    Boolean,
485
    String,
486
    Text,
487
    Binary,
488
    Decimal,
489
    Timestamp,
490
    Date,
491
    Bson,
492
    Point,
493
}
494

495
impl TryFrom<&str> for FieldType {
496
    type Error = String;
497

498
    fn try_from(value: &str) -> Result<Self, Self::Error> {
102✔
499
        let res = match value.to_lowercase().as_str() {
102✔
500
            "float" => FieldType::Float,
102✔
501
            "uint" => FieldType::UInt,
×
502
            "int" => FieldType::Int,
×
503
            "boolean" => FieldType::Boolean,
×
504
            "string" => FieldType::String,
×
505
            "text" => FieldType::Text,
×
506
            "binary" => FieldType::Binary,
×
507
            "decimal" => FieldType::Decimal,
×
508
            "timestamp" => FieldType::Timestamp,
×
509
            "date" => FieldType::Date,
×
510
            "bson" => FieldType::Bson,
×
511
            _ => return Err(format!("Unsupported '{value}' type")),
×
512
        };
513

514
        Ok(res)
102✔
515
    }
102✔
516
}
517

518
impl Display for FieldType {
519
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1,207✔
520
        match self {
1,207✔
521
            FieldType::UInt => f.write_str("unsigned int"),
×
522
            FieldType::Int => f.write_str("int"),
34✔
523
            FieldType::Float => f.write_str("float"),
×
524
            FieldType::Boolean => f.write_str("boolean"),
×
525
            FieldType::String => f.write_str("string"),
34✔
526
            FieldType::Text => f.write_str("text"),
×
527
            FieldType::Binary => f.write_str("binary"),
×
528
            FieldType::Decimal => f.write_str("decimal"),
1,139✔
529
            FieldType::Timestamp => f.write_str("timestamp"),
×
530
            FieldType::Date => f.write_str("date"),
×
531
            FieldType::Bson => f.write_str("bson"),
×
532
            FieldType::Point => f.write_str("point"),
×
533
        }
534
    }
1,207✔
535
}
536

537
/// Can't put it in `tests` module because of <https://github.com/rust-lang/cargo/issues/8379>
538
/// and we need this function in `dozer-cache`.
539
pub fn field_test_cases() -> impl Iterator<Item = Field> {
804✔
540
    [
804✔
541
        Field::Int(0_i64),
804✔
542
        Field::Int(1_i64),
804✔
543
        Field::UInt(0_u64),
804✔
544
        Field::UInt(1_u64),
804✔
545
        Field::Float(OrderedFloat::from(0_f64)),
804✔
546
        Field::Float(OrderedFloat::from(1_f64)),
804✔
547
        Field::Boolean(true),
804✔
548
        Field::Boolean(false),
804✔
549
        Field::String("".to_string()),
804✔
550
        Field::String("1".to_string()),
804✔
551
        Field::Text("".to_string()),
804✔
552
        Field::Text("1".to_string()),
804✔
553
        Field::Binary(vec![]),
804✔
554
        Field::Binary(vec![1]),
804✔
555
        Field::Decimal(Decimal::new(0, 0)),
804✔
556
        Field::Decimal(Decimal::new(1, 0)),
804✔
557
        Field::Timestamp(DateTime::from(Utc.timestamp_millis_opt(0).unwrap())),
804✔
558
        Field::Timestamp(DateTime::parse_from_rfc3339("2020-01-01T00:00:00Z").unwrap()),
804✔
559
        Field::Date(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()),
804✔
560
        Field::Date(NaiveDate::from_ymd_opt(2020, 1, 1).unwrap()),
804✔
561
        Field::Bson(vec![
804✔
562
            // BSON representation of `{"abc":"foo"}`
804✔
563
            123, 34, 97, 98, 99, 34, 58, 34, 102, 111, 111, 34, 125,
804✔
564
        ]),
804✔
565
        Field::Null,
804✔
566
    ]
804✔
567
    .into_iter()
804✔
568
}
804✔
569

570
#[cfg(feature = "python")]
571
impl pyo3::ToPyObject for Field {
572
    fn to_object(&self, py: pyo3::Python<'_>) -> pyo3::PyObject {
51✔
573
        match self {
51✔
574
            Field::UInt(val) => val.to_object(py),
×
575
            Field::Int(val) => val.to_object(py),
51✔
576
            Field::Float(val) => val.0.to_object(py),
×
577
            Field::Boolean(val) => val.to_object(py),
×
578
            Field::String(val) => val.to_object(py),
×
579
            Field::Text(val) => val.to_object(py),
×
580
            Field::Binary(val) => val.to_object(py),
×
581
            Field::Decimal(val) => val.to_f64().unwrap().to_object(py),
×
582
            Field::Timestamp(val) => val.timestamp().to_object(py),
×
583
            Field::Date(val) => {
×
584
                pyo3::types::PyDate::new(py, val.year(), val.month() as u8, val.day() as u8)
×
585
                    .unwrap()
×
586
                    .to_object(py)
×
587
            }
588
            Field::Bson(val) => val.to_object(py),
×
589
            Field::Null => unreachable!(),
×
590
            Field::Point(_val) => todo!(),
×
591
        }
592
    }
51✔
593
}
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