use arrow::datatypes::{
DataType as ArrowDataType, Time32MillisecondType as ArrowTimeMillisecondType,
Time32SecondType as ArrowTimeSecondType, Time64MicrosecondType as ArrowTimeMicrosecondType,
Time64NanosecondType as ArrowTimeNanosecondType, TimeUnit as ArrowTimeUnit,
};
use common_time::time::Time;
use common_time::timestamp::TimeUnit;
use enum_dispatch::enum_dispatch;
use paste::paste;
use serde::{Deserialize, Serialize};
use snafu::OptionExt;
use crate::error;
use crate::prelude::{
ConcreteDataType, DataType, LogicalTypeId, MutableVector, ScalarVectorBuilder, Value, ValueRef,
Vector,
};
use crate::time::{TimeMicrosecond, TimeMillisecond, TimeNanosecond, TimeSecond};
use crate::types::LogicalPrimitiveType;
use crate::vectors::{
PrimitiveVector, TimeMicrosecondVector, TimeMicrosecondVectorBuilder, TimeMillisecondVector,
TimeMillisecondVectorBuilder, TimeNanosecondVector, TimeNanosecondVectorBuilder,
TimeSecondVector, TimeSecondVectorBuilder,
};
const SECOND_VARIATION: u64 = 0;
const MILLISECOND_VARIATION: u64 = 3;
const MICROSECOND_VARIATION: u64 = 6;
const NANOSECOND_VARIATION: u64 = 9;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[enum_dispatch(DataType)]
pub enum TimeType {
Second(TimeSecondType),
Millisecond(TimeMillisecondType),
Microsecond(TimeMicrosecondType),
Nanosecond(TimeNanosecondType),
}
impl TimeType {
pub fn from_unit(unit: TimeUnit) -> Self {
match unit {
TimeUnit::Second => Self::Second(TimeSecondType),
TimeUnit::Millisecond => Self::Millisecond(TimeMillisecondType),
TimeUnit::Microsecond => Self::Microsecond(TimeMicrosecondType),
TimeUnit::Nanosecond => Self::Nanosecond(TimeNanosecondType),
}
}
pub fn unit(&self) -> TimeUnit {
match self {
TimeType::Second(_) => TimeUnit::Second,
TimeType::Millisecond(_) => TimeUnit::Millisecond,
TimeType::Microsecond(_) => TimeUnit::Microsecond,
TimeType::Nanosecond(_) => TimeUnit::Nanosecond,
}
}
pub fn precision(&self) -> u64 {
match self {
TimeType::Second(_) => SECOND_VARIATION,
TimeType::Millisecond(_) => MILLISECOND_VARIATION,
TimeType::Microsecond(_) => MICROSECOND_VARIATION,
TimeType::Nanosecond(_) => NANOSECOND_VARIATION,
}
}
}
macro_rules! impl_data_type_for_time {
($unit: ident,$arrow_type: ident, $type: ty, $TargetType: ident) => {
paste! {
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub struct [<Time $unit Type>];
impl DataType for [<Time $unit Type>] {
fn name(&self) -> String {
stringify!([<Time $unit>]).to_string()
}
fn logical_type_id(&self) -> LogicalTypeId {
LogicalTypeId::[<Time $unit>]
}
fn default_value(&self) -> Value {
Value::Time(Time::new(0, TimeUnit::$unit))
}
fn as_arrow_type(&self) -> ArrowDataType {
ArrowDataType::$arrow_type(ArrowTimeUnit::$unit)
}
fn create_mutable_vector(&self, capacity: usize) -> Box<dyn MutableVector> {
Box::new([<Time $unit Vector Builder>]::with_capacity(capacity))
}
fn try_cast(&self, from: Value) -> Option<Value> {
match from {
Value::$TargetType(v) => Some(Value::Time(Time::new(v as i64, TimeUnit::$unit))),
Value::Time(v) => v.convert_to(TimeUnit::$unit).map(Value::Time),
_ => None,
}
}
}
impl LogicalPrimitiveType for [<Time $unit Type>] {
type ArrowPrimitive = [<Arrow Time $unit Type>];
type Native = $type;
type Wrapper = [<Time $unit>];
type LargestType = Self;
fn build_data_type() -> ConcreteDataType {
ConcreteDataType::Time(TimeType::$unit(
[<Time $unit Type>]::default(),
))
}
fn type_name() -> &'static str {
stringify!([<Time $unit Type>])
}
fn cast_vector(vector: &dyn Vector) -> crate::Result<&PrimitiveVector<Self>> {
vector
.as_any()
.downcast_ref::<[<Time $unit Vector>]>()
.with_context(|| error::CastTypeSnafu {
msg: format!(
"Failed to cast {} to {}",
vector.vector_type_name(), stringify!([<Time $unit Vector>])
),
})
}
fn cast_value_ref(value: ValueRef) -> crate::Result<Option<Self::Wrapper>> {
match value {
ValueRef::Null => Ok(None),
ValueRef::Int64(v) =>{
Ok(Some([<Time $unit>]::from(v)))
}
ValueRef::Time(t) => match t.unit() {
TimeUnit::$unit => Ok(Some([<Time $unit>](t))),
other => error::CastTypeSnafu {
msg: format!(
"Failed to cast Time value with different unit {:?} to {}",
other, stringify!([<Time $unit>])
),
}
.fail(),
},
other => error::CastTypeSnafu {
msg: format!("Failed to cast value {:?} to {}", other, stringify!([<Time $unit>])),
}
.fail(),
}
}
}
}
}
}
impl_data_type_for_time!(Second, Time32, i32, Int32);
impl_data_type_for_time!(Millisecond, Time32, i32, Int32);
impl_data_type_for_time!(Nanosecond, Time64, i64, Int64);
impl_data_type_for_time!(Microsecond, Time64, i64, Int64);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_time_type_unit() {
assert_eq!(TimeUnit::Second, TimeType::Second(TimeSecondType).unit());
assert_eq!(
TimeUnit::Millisecond,
TimeType::Millisecond(TimeMillisecondType).unit()
);
assert_eq!(
TimeUnit::Microsecond,
TimeType::Microsecond(TimeMicrosecondType).unit()
);
assert_eq!(
TimeUnit::Nanosecond,
TimeType::Nanosecond(TimeNanosecondType).unit()
);
}
#[test]
fn test_as_arrow_datatype() {
assert_eq!(
ArrowDataType::Time32(ArrowTimeUnit::Second),
TimeSecondType.as_arrow_type()
);
assert_eq!(
ArrowDataType::Time32(ArrowTimeUnit::Millisecond),
TimeMillisecondType.as_arrow_type()
);
assert_eq!(
ArrowDataType::Time64(ArrowTimeUnit::Microsecond),
TimeMicrosecondType.as_arrow_type()
);
assert_eq!(
ArrowDataType::Time64(ArrowTimeUnit::Nanosecond),
TimeNanosecondType.as_arrow_type()
);
}
#[test]
fn test_time_cast() {
let val = Value::Int32(1000);
let time = ConcreteDataType::time_second_datatype()
.try_cast(val)
.unwrap();
assert_eq!(time, Value::Time(Time::new_second(1000)));
let val = Value::Int32(2000);
let time = ConcreteDataType::time_millisecond_datatype()
.try_cast(val)
.unwrap();
assert_eq!(time, Value::Time(Time::new_millisecond(2000)));
let val = Value::Int64(3000);
let time = ConcreteDataType::time_microsecond_datatype()
.try_cast(val)
.unwrap();
assert_eq!(time, Value::Time(Time::new_microsecond(3000)));
let val = Value::Int64(4000);
let time = ConcreteDataType::time_nanosecond_datatype()
.try_cast(val)
.unwrap();
assert_eq!(time, Value::Time(Time::new_nanosecond(4000)));
let val = Value::Int64(123);
let time = ConcreteDataType::time_second_datatype().try_cast(val);
assert_eq!(time, None);
let val = Value::Int32(123);
let time = ConcreteDataType::time_microsecond_datatype().try_cast(val);
assert_eq!(time, None);
let second = Value::Time(Time::new_second(2023));
let microsecond = ConcreteDataType::time_microsecond_datatype()
.try_cast(second)
.unwrap();
assert_eq!(
microsecond,
Value::Time(Time::new_microsecond(2023 * 1000000))
);
let second = Value::Time(Time::new_second(i64::MAX));
let microsecond = ConcreteDataType::time_microsecond_datatype().try_cast(second);
assert_eq!(microsecond, None);
}
}