#[cfg(test)]
mod test;
use std::sync::Arc;
use vortex_dtype::datetime::{DATE_ID, TIME_ID, TIMESTAMP_ID, TemporalMetadata, TimeUnit};
use vortex_dtype::{DType, ExtDType};
use vortex_error::{VortexError, vortex_err, vortex_panic};
use crate::arrays::{ExtensionArray, ExtensionVTable};
use crate::{Array, ArrayRef, IntoArray};
#[derive(Clone, Debug)]
pub struct TemporalArray {
ext: ExtensionArray,
temporal_metadata: TemporalMetadata,
}
macro_rules! assert_width {
($width:ty, $array:expr) => {{
let DType::Primitive(ptype, _) = $array.dtype() else {
panic!("array must have primitive type");
};
assert_eq!(
<$width as vortex_dtype::NativePType>::PTYPE,
*ptype,
"invalid ptype {} for array, expected {}",
<$width as vortex_dtype::NativePType>::PTYPE,
*ptype
);
}};
}
impl TemporalArray {
pub fn new_date(array: ArrayRef, time_unit: TimeUnit) -> Self {
match time_unit {
TimeUnit::Days => {
assert_width!(i32, array);
}
TimeUnit::Milliseconds => {
assert_width!(i64, array);
}
TimeUnit::Nanoseconds | TimeUnit::Microseconds | TimeUnit::Seconds => {
vortex_panic!("invalid TimeUnit {time_unit} for vortex.date")
}
};
let ext_dtype = ExtDType::new(
DATE_ID.clone(),
Arc::new(array.dtype().clone()),
Some(TemporalMetadata::Date(time_unit).into()),
);
Self {
ext: ExtensionArray::new(Arc::new(ext_dtype), array),
temporal_metadata: TemporalMetadata::Date(time_unit),
}
}
pub fn new_time(array: ArrayRef, time_unit: TimeUnit) -> Self {
match time_unit {
TimeUnit::Seconds | TimeUnit::Milliseconds => assert_width!(i32, array),
TimeUnit::Microseconds | TimeUnit::Nanoseconds => assert_width!(i64, array),
TimeUnit::Days => vortex_panic!("invalid unit D for vortex.time data"),
}
let temporal_metadata = TemporalMetadata::Time(time_unit);
Self {
ext: ExtensionArray::new(
Arc::new(ExtDType::new(
TIME_ID.clone(),
Arc::new(array.dtype().clone()),
Some(temporal_metadata.clone().into()),
)),
array,
),
temporal_metadata,
}
}
pub fn new_timestamp(array: ArrayRef, time_unit: TimeUnit, time_zone: Option<String>) -> Self {
assert_width!(i64, array);
let temporal_metadata = TemporalMetadata::Timestamp(time_unit, time_zone);
Self {
ext: ExtensionArray::new(
Arc::new(ExtDType::new(
TIMESTAMP_ID.clone(),
Arc::new(array.dtype().clone()),
Some(temporal_metadata.clone().into()),
)),
array,
),
temporal_metadata,
}
}
}
impl TemporalArray {
pub fn temporal_values(&self) -> &ArrayRef {
self.ext.storage()
}
pub fn temporal_metadata(&self) -> &TemporalMetadata {
&self.temporal_metadata
}
pub fn ext_dtype(&self) -> Arc<ExtDType> {
self.ext.ext_dtype().clone()
}
pub fn dtype(&self) -> &DType {
self.ext.dtype()
}
}
impl From<TemporalArray> for ArrayRef {
fn from(value: TemporalArray) -> Self {
value.ext.into_array()
}
}
impl IntoArray for TemporalArray {
fn into_array(self) -> ArrayRef {
self.into()
}
}
impl TryFrom<ArrayRef> for TemporalArray {
type Error = VortexError;
fn try_from(value: ArrayRef) -> Result<Self, Self::Error> {
let ext = value
.as_opt::<ExtensionVTable>()
.ok_or_else(|| vortex_err!("array must be an ExtensionArray"))?;
let temporal_metadata = TemporalMetadata::try_from(ext.ext_dtype())?;
Ok(Self {
ext: ext.clone(),
temporal_metadata,
})
}
}
impl From<&TemporalArray> for ExtensionArray {
fn from(value: &TemporalArray) -> Self {
value.ext.clone()
}
}
impl From<TemporalArray> for ExtensionArray {
fn from(value: TemporalArray) -> Self {
value.ext
}
}
impl TryFrom<ExtensionArray> for TemporalArray {
type Error = VortexError;
fn try_from(ext: ExtensionArray) -> Result<Self, Self::Error> {
let temporal_metadata = TemporalMetadata::try_from(ext.ext_dtype().as_ref())?;
Ok(Self {
ext,
temporal_metadata,
})
}
}