From 15c5ec1ee8ffd123c305e0072bb959baae54d353 Mon Sep 17 00:00:00 2001 From: Ritchie Vink Date: Thu, 27 Jul 2023 13:45:29 +0200 Subject: [PATCH] feat: add duration type to json writer (#1522) --- src/io/json/write/serialize.rs | 43 +++++++++++++++++++++++++++++++--- src/temporal_conversions.rs | 26 +++++++++++++++++++- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/io/json/write/serialize.rs b/src/io/json/write/serialize.rs index 7d46b82e0f..abf845714c 100644 --- a/src/io/json/write/serialize.rs +++ b/src/io/json/write/serialize.rs @@ -1,4 +1,4 @@ -use chrono::{NaiveDate, NaiveDateTime}; +use chrono::{Duration, NaiveDate, NaiveDateTime}; use lexical_core::ToLexical; use std::io::Write; use streaming_iterator::StreamingIterator; @@ -8,8 +8,9 @@ use crate::datatypes::{IntegerType, TimeUnit}; use crate::io::iterator::BufStreamingIterator; use crate::offset::Offset; use crate::temporal_conversions::{ - date32_to_date, date64_to_date, timestamp_ms_to_datetime, timestamp_ns_to_datetime, - timestamp_s_to_datetime, timestamp_us_to_datetime, + date32_to_date, date64_to_date, duration_ms_to_duration, duration_ns_to_duration, + duration_s_to_duration, duration_us_to_duration, timestamp_ms_to_datetime, + timestamp_ns_to_datetime, timestamp_s_to_datetime, timestamp_us_to_datetime, }; use crate::util::lexical_to_bytes_mut; use crate::{array::*, datatypes::DataType, types::NativeType}; @@ -266,6 +267,28 @@ where materialize_serializer(f, array.iter(), offset, take) } +fn duration_serializer<'a, T, F>( + array: &'a PrimitiveArray, + convert: F, + offset: usize, + take: usize, +) -> Box + 'a + Send + Sync> +where + T: NativeType, + F: Fn(T) -> Duration + 'static + Send + Sync, +{ + let f = move |x: Option<&T>, buf: &mut Vec| { + if let Some(x) = x { + let duration = convert(*x); + write!(buf, "\"{duration}\"").unwrap(); + } else { + buf.extend_from_slice(b"null") + } + }; + + materialize_serializer(f, array.iter(), offset, take) +} + fn timestamp_serializer<'a, F>( array: &'a PrimitiveArray, convert: F, @@ -385,6 +408,20 @@ pub(crate) fn new_serializer<'a>( ) } } + DataType::Duration(tu) => { + let convert = match tu { + TimeUnit::Nanosecond => duration_ns_to_duration, + TimeUnit::Microsecond => duration_us_to_duration, + TimeUnit::Millisecond => duration_ms_to_duration, + TimeUnit::Second => duration_s_to_duration, + }; + duration_serializer( + array.as_any().downcast_ref().unwrap(), + convert, + offset, + take, + ) + } DataType::Null => null_serializer(array.len(), offset, take), other => todo!("Writing {:?} to JSON", other), } diff --git a/src/temporal_conversions.rs b/src/temporal_conversions.rs index a76700f444..48f2078a2a 100644 --- a/src/temporal_conversions.rs +++ b/src/temporal_conversions.rs @@ -2,7 +2,7 @@ use chrono::{ format::{parse, Parsed, StrftimeItems}, - Datelike, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime, + Datelike, Duration, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime, }; use crate::error::Result; @@ -66,6 +66,30 @@ pub fn time32s_to_time(v: i32) -> NaiveTime { NaiveTime::from_num_seconds_from_midnight_opt(v as u32, 0).expect("invalid time") } +/// converts a `i64` representing a `duration(s)` to [`Duration`] +#[inline] +pub fn duration_s_to_duration(v: i64) -> Duration { + Duration::seconds(v) +} + +/// converts a `i64` representing a `duration(ms)` to [`Duration`] +#[inline] +pub fn duration_ms_to_duration(v: i64) -> Duration { + Duration::milliseconds(v) +} + +/// converts a `i64` representing a `duration(us)` to [`Duration`] +#[inline] +pub fn duration_us_to_duration(v: i64) -> Duration { + Duration::microseconds(v) +} + +/// converts a `i64` representing a `duration(ns)` to [`Duration`] +#[inline] +pub fn duration_ns_to_duration(v: i64) -> Duration { + Duration::nanoseconds(v) +} + /// converts a `i32` representing a `time32(ms)` to [`NaiveTime`] #[inline] pub fn time32ms_to_time(v: i32) -> NaiveTime {