From fbba2ecd939aedf88563b9c0ebdbe28a08036094 Mon Sep 17 00:00:00 2001 From: Shar-jeel-Sajid Date: Sat, 15 Mar 2025 21:18:51 +0500 Subject: [PATCH] Added Datatype NaiveDate and NaiveTime --- Cargo.lock | 1 + libraries/arrow-convert/Cargo.toml | 1 + libraries/arrow-convert/src/from_impls.rs | 40 +++++++++++++++++++ libraries/arrow-convert/src/into_impls.rs | 18 ++++++++- .../arrow-convert/tests/conversion_test.rs | 23 ++++++++++- 5 files changed, 80 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a5b8ec59..c5e6e333 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2654,6 +2654,7 @@ version = "0.3.10" dependencies = [ "arrow 54.2.1", "arrow_convert", + "chrono", "eyre", ] diff --git a/libraries/arrow-convert/Cargo.toml b/libraries/arrow-convert/Cargo.toml index 60656967..558f8bce 100644 --- a/libraries/arrow-convert/Cargo.toml +++ b/libraries/arrow-convert/Cargo.toml @@ -13,3 +13,4 @@ repository.workspace = true arrow = { workspace = true } arrow_convert = "0.8.1" eyre = "0.6.8" +chrono = "0.4.39" diff --git a/libraries/arrow-convert/src/from_impls.rs b/libraries/arrow-convert/src/from_impls.rs index 66828f46..bfcd8a05 100644 --- a/libraries/arrow-convert/src/from_impls.rs +++ b/libraries/arrow-convert/src/from_impls.rs @@ -2,6 +2,7 @@ use arrow::{ array::{Array, AsArray, PrimitiveArray, StringArray}, datatypes::ArrowPrimitiveType, }; +use chrono::{NaiveDate, NaiveTime}; use arrow_convert::deserialize::TryIntoCollection; use eyre::ContextCompat; @@ -355,6 +356,45 @@ impl<'a> TryFrom<&'a ArrowData> for String { } } + +impl TryFrom<&ArrowData> for NaiveDate { + type Error = eyre::Report; + fn try_from(value: &ArrowData) -> Result { + let array = value + .as_primitive_opt::() + .context("not a primitive Date32Type array")?; + if array.is_empty() { + eyre::bail!("empty array"); + } + if array.len() != 1 { + eyre::bail!("expected length 1"); + } + if array.null_count() != 0 { + eyre::bail!("array has nulls"); + } + Ok(array.value_as_date(0).context("data type cannot be converted to NaiveDate")?) + } +} + +impl TryFrom<&ArrowData> for NaiveTime { + type Error = eyre::Report; + fn try_from(value: &ArrowData) -> Result { + let array = value + .as_primitive_opt::() + .context("not a primitive Time64NanosecondType array")?; + if array.is_empty() { + eyre::bail!("empty array"); + } + if array.len() != 1 { + eyre::bail!("expected length 1"); + } + if array.null_count() != 0 { + eyre::bail!("array has nulls"); + } + Ok(array.value_as_time(0).context("data type cannot be converted to NaiveTime")?) + } +} + fn extract_single_primitive(array: &PrimitiveArray) -> Result where T: ArrowPrimitiveType, diff --git a/libraries/arrow-convert/src/into_impls.rs b/libraries/arrow-convert/src/into_impls.rs index f9e278bc..2d6a12d4 100644 --- a/libraries/arrow-convert/src/into_impls.rs +++ b/libraries/arrow-convert/src/into_impls.rs @@ -1,6 +1,8 @@ use crate::IntoArrow; use arrow::array::{Array, ArrayRef, PrimitiveArray, StringArray}; use arrow_convert::serialize::TryIntoArrow; +use crate::IntoArrow; +use chrono::{NaiveDate, NaiveTime}; impl IntoArrow for bool { type A = arrow::array::BooleanArray; @@ -146,7 +148,21 @@ impl IntoArrow for () { } } -impl IntoArrow for &String { +impl IntoArrow for NaiveDate { + type A = arrow::array::Date32Array; + fn into_arrow(self) -> Self::A { + arrow::array::Date32Array::from(vec![arrow::datatypes::Date32Type::from_naive_date(self)]) + } +} + +impl IntoArrow for NaiveTime { + type A = arrow::array::Time64NanosecondArray; + fn into_arrow(self) -> Self::A { + arrow::array::Time64NanosecondArray::from(vec![arrow::array::temporal_conversions::time_to_time64ns(self)]) + } +} + +impl IntoArrow for String { type A = StringArray; fn into_arrow(self) -> Self::A { diff --git a/libraries/arrow-convert/tests/conversion_test.rs b/libraries/arrow-convert/tests/conversion_test.rs index 32d1eeea..71dd6ca0 100644 --- a/libraries/arrow-convert/tests/conversion_test.rs +++ b/libraries/arrow-convert/tests/conversion_test.rs @@ -1,6 +1,5 @@ use dora_arrow_convert::{ArrowData, IntoArrow}; -use std::convert::TryFrom; -use std::sync::Arc; +use chrono::{NaiveDate, NaiveTime}; #[cfg(test)] mod tests { @@ -235,4 +234,24 @@ mod tests { assert_eq!(value_vec_f64, result_vec_f64); Ok(()) } + + #[test] + fn test_naivedate_round_trip() -> Result<(), Report> { + let value_naivedate = NaiveDate::from_ymd_opt(2024,4,4).unwrap(); + let arrow_array = value_naivedate.into_arrow(); + let data: ArrowData = ArrowData(Arc::new(arrow_array)); + let result_naivedate: NaiveDate = TryFrom::try_from(&data)?; + assert_eq!(value_naivedate,result_naivedate); + Ok(()) + } + #[test] + fn test_naivetime_round_trip() -> Result<(), Report> { + let value_naivetime = NaiveTime::from_hms_milli_opt(23,56,4,10).unwrap(); + let arrow_array = value_naivetime.into_arrow(); + let data: ArrowData = ArrowData(Arc::new(arrow_array)); + let result_naivetime: NaiveTime = TryFrom::try_from(&data)?; + assert_eq!(value_naivetime,result_naivetime); + Ok(()) + } } +