use rudb_common::{Error, LogicalType, Result};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DataType {
Null,
Boolean,
Int8,
Int16,
Int32,
Int64,
UInt8,
UInt16,
UInt32,
UInt64,
Float32,
Float64,
Utf8,
Binary,
Date32,
Time64,
Timestamp(TimeUnit, Option<String>),
Interval,
Decimal128 {
precision: u8,
scale: u8,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TimeUnit {
Second,
Millisecond,
Microsecond,
Nanosecond,
}
impl TimeUnit {
fn letter(self) -> char {
match self {
Self::Second => 's',
Self::Millisecond => 'm',
Self::Microsecond => 'u',
Self::Nanosecond => 'n',
}
}
}
impl DataType {
pub fn of(ty: &LogicalType) -> Result<Self> {
Ok(match ty {
LogicalType::Null => Self::Null,
LogicalType::Boolean => Self::Boolean,
LogicalType::TinyInt => Self::Int8,
LogicalType::SmallInt => Self::Int16,
LogicalType::Integer => Self::Int32,
LogicalType::BigInt => Self::Int64,
LogicalType::HugeInt => Self::Decimal128 { precision: 38, scale: 0 },
LogicalType::UTinyInt => Self::UInt8,
LogicalType::USmallInt => Self::UInt16,
LogicalType::UInteger => Self::UInt32,
LogicalType::UBigInt => Self::UInt64,
LogicalType::Float => Self::Float32,
LogicalType::Double => Self::Float64,
LogicalType::Decimal { width, scale } => {
Self::Decimal128 { precision: *width, scale: *scale }
}
LogicalType::Varchar => Self::Utf8,
LogicalType::Blob => Self::Binary,
LogicalType::Date => Self::Date32,
LogicalType::Time => Self::Time64,
LogicalType::Timestamp => Self::Timestamp(TimeUnit::Microsecond, None),
LogicalType::TimestampS => Self::Timestamp(TimeUnit::Second, None),
LogicalType::TimestampMs => Self::Timestamp(TimeUnit::Millisecond, None),
LogicalType::TimestampNs => Self::Timestamp(TimeUnit::Nanosecond, None),
LogicalType::TimestampTz => {
Self::Timestamp(TimeUnit::Microsecond, Some("UTC".to_string()))
}
LogicalType::Interval => Self::Interval,
other => {
return Err(Error::not_implemented(format!("exporting {other} to Arrow")));
}
})
}
#[must_use]
pub fn format(&self) -> String {
match self {
Self::Null => "n".to_string(),
Self::Boolean => "b".to_string(),
Self::Int8 => "c".to_string(),
Self::Int16 => "s".to_string(),
Self::Int32 => "i".to_string(),
Self::Int64 => "l".to_string(),
Self::UInt8 => "C".to_string(),
Self::UInt16 => "S".to_string(),
Self::UInt32 => "I".to_string(),
Self::UInt64 => "L".to_string(),
Self::Float32 => "f".to_string(),
Self::Float64 => "g".to_string(),
Self::Utf8 => "u".to_string(),
Self::Binary => "z".to_string(),
Self::Date32 => "tdD".to_string(),
Self::Time64 => "ttu".to_string(),
Self::Timestamp(unit, zone) => {
format!("ts{}:{}", unit.letter(), zone.clone().unwrap_or_default())
}
Self::Interval => "tin".to_string(),
Self::Decimal128 { precision, scale } => format!("d:{precision},{scale}"),
}
}
#[must_use]
pub fn buffer_count(&self) -> usize {
match self {
Self::Null => 0,
Self::Utf8 | Self::Binary => 3,
_ => 2,
}
}
#[must_use]
pub fn width(&self) -> Option<usize> {
Some(match self {
Self::Null | Self::Utf8 | Self::Binary => return None,
Self::Boolean => return None,
Self::Int8 | Self::UInt8 => 1,
Self::Int16 | Self::UInt16 => 2,
Self::Int32 | Self::UInt32 | Self::Float32 | Self::Date32 => 4,
Self::Int64 | Self::UInt64 | Self::Float64 | Self::Time64 | Self::Timestamp(_, _) => 8,
Self::Interval | Self::Decimal128 { .. } => 16,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Field {
pub name: String,
pub data_type: DataType,
pub nullable: bool,
}
impl Field {
#[must_use]
pub fn new(name: impl Into<String>, data_type: DataType) -> Self {
Self { name: name.into(), data_type, nullable: true }
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct Schema {
pub fields: Vec<Field>,
}
impl Schema {
#[must_use]
pub fn new(fields: Vec<Field>) -> Self {
Self { fields }
}
#[must_use]
pub fn len(&self) -> usize {
self.fields.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.fields.is_empty()
}
}