use std::sync::Arc;
use vibesql_types::{Date, Interval, SqlValue, Time, Timestamp};
use super::{data::ColumnData, interner::StringInterner, types::ColumnTypeClass};
pub(crate) struct ColumnBuilder {
type_class: ColumnTypeClass,
int64_values: Vec<i64>,
float64_values: Vec<f64>,
string_values: Vec<Arc<str>>,
bool_values: Vec<bool>,
date_values: Vec<Date>,
time_values: Vec<Time>,
timestamp_values: Vec<Timestamp>,
interval_values: Vec<Interval>,
blob_values: Vec<Vec<u8>>,
nulls: Vec<bool>,
string_interner: StringInterner,
}
impl ColumnBuilder {
pub fn new(type_class: ColumnTypeClass, capacity: usize) -> Self {
let mut builder = ColumnBuilder {
type_class,
int64_values: Vec::new(),
float64_values: Vec::new(),
string_values: Vec::new(),
bool_values: Vec::new(),
date_values: Vec::new(),
time_values: Vec::new(),
timestamp_values: Vec::new(),
interval_values: Vec::new(),
blob_values: Vec::new(),
nulls: Vec::with_capacity(capacity),
string_interner: StringInterner::default(),
};
match type_class {
ColumnTypeClass::Int64 | ColumnTypeClass::Null => {
builder.int64_values = Vec::with_capacity(capacity);
}
ColumnTypeClass::Float64 => {
builder.float64_values = Vec::with_capacity(capacity);
}
ColumnTypeClass::String => {
builder.string_values = Vec::with_capacity(capacity);
}
ColumnTypeClass::Bool => {
builder.bool_values = Vec::with_capacity(capacity);
}
ColumnTypeClass::Date => {
builder.date_values = Vec::with_capacity(capacity);
}
ColumnTypeClass::Time => {
builder.time_values = Vec::with_capacity(capacity);
}
ColumnTypeClass::Timestamp => {
builder.timestamp_values = Vec::with_capacity(capacity);
}
ColumnTypeClass::Interval => {
builder.interval_values = Vec::with_capacity(capacity);
}
ColumnTypeClass::Vector => {
}
ColumnTypeClass::Blob => {
builder.blob_values = Vec::with_capacity(capacity);
}
}
builder
}
pub fn push(&mut self, value: &SqlValue) -> Result<(), String> {
match (self.type_class, value) {
(ColumnTypeClass::Int64 | ColumnTypeClass::Null, SqlValue::Integer(v)) => {
self.int64_values.push(*v);
self.nulls.push(false);
}
(ColumnTypeClass::Int64 | ColumnTypeClass::Null, SqlValue::Bigint(v)) => {
self.int64_values.push(*v);
self.nulls.push(false);
}
(ColumnTypeClass::Int64 | ColumnTypeClass::Null, SqlValue::Smallint(v)) => {
self.int64_values.push(*v as i64);
self.nulls.push(false);
}
(ColumnTypeClass::Int64 | ColumnTypeClass::Null, SqlValue::Null) => {
self.int64_values.push(0);
self.nulls.push(true);
}
(ColumnTypeClass::Float64, SqlValue::Float(v)) => {
self.float64_values.push(*v as f64);
self.nulls.push(false);
}
(ColumnTypeClass::Float64, SqlValue::Double(v)) => {
self.float64_values.push(*v);
self.nulls.push(false);
}
(ColumnTypeClass::Float64, SqlValue::Real(v)) => {
self.float64_values.push(*v as f64);
self.nulls.push(false);
}
(ColumnTypeClass::Float64, SqlValue::Numeric(v)) => {
self.float64_values.push(*v);
self.nulls.push(false);
}
(ColumnTypeClass::Float64, SqlValue::Unsigned(v)) => {
self.float64_values.push(*v as f64);
self.nulls.push(false);
}
(ColumnTypeClass::Float64, SqlValue::Null) => {
self.float64_values.push(0.0);
self.nulls.push(true);
}
(ColumnTypeClass::String, SqlValue::Varchar(v)) => {
let interned = self.string_interner.intern_arc(Arc::from(v.as_str()));
self.string_values.push(interned);
self.nulls.push(false);
}
(ColumnTypeClass::String, SqlValue::Character(v)) => {
let interned = self.string_interner.intern_arc(Arc::from(v.as_str()));
self.string_values.push(interned);
self.nulls.push(false);
}
(ColumnTypeClass::String, SqlValue::Null) => {
self.string_values.push(Arc::from(""));
self.nulls.push(true);
}
(ColumnTypeClass::Bool, SqlValue::Boolean(v)) => {
self.bool_values.push(*v);
self.nulls.push(false);
}
(ColumnTypeClass::Bool, SqlValue::Null) => {
self.bool_values.push(false);
self.nulls.push(true);
}
(ColumnTypeClass::Date, SqlValue::Date(v)) => {
self.date_values.push(*v);
self.nulls.push(false);
}
(ColumnTypeClass::Date, SqlValue::Null) => {
self.date_values.push(Date::new(1970, 1, 1).unwrap());
self.nulls.push(true);
}
(ColumnTypeClass::Time, SqlValue::Time(v)) => {
self.time_values.push(*v);
self.nulls.push(false);
}
(ColumnTypeClass::Time, SqlValue::Null) => {
self.time_values.push(Time::new(0, 0, 0, 0).unwrap());
self.nulls.push(true);
}
(ColumnTypeClass::Timestamp, SqlValue::Timestamp(v)) => {
self.timestamp_values.push(*v);
self.nulls.push(false);
}
(ColumnTypeClass::Timestamp, SqlValue::Null) => {
let date = Date::new(1970, 1, 1).unwrap();
let time = Time::new(0, 0, 0, 0).unwrap();
self.timestamp_values.push(Timestamp::new(date, time));
self.nulls.push(true);
}
(ColumnTypeClass::Interval, SqlValue::Interval(v)) => {
self.interval_values.push(v.clone());
self.nulls.push(false);
}
(ColumnTypeClass::Interval, SqlValue::Null) => {
self.interval_values.push(Interval::new("0".to_string()));
self.nulls.push(true);
}
(ColumnTypeClass::Vector, SqlValue::Null) => {
self.nulls.push(true);
}
(ColumnTypeClass::Vector, _) => {
self.nulls.push(false);
}
(ColumnTypeClass::Blob, SqlValue::Blob(v)) => {
self.blob_values.push(v.clone());
self.nulls.push(false);
}
(ColumnTypeClass::Blob, SqlValue::Null) => {
self.blob_values.push(Vec::new());
self.nulls.push(true);
}
(expected, got) => {
return Err(format!(
"Column has mixed types: expected {:?}, got {}",
expected,
got.type_name()
));
}
}
Ok(())
}
pub fn build(self) -> ColumnData {
match self.type_class {
ColumnTypeClass::Int64 | ColumnTypeClass::Null => ColumnData::Int64 {
values: Arc::new(self.int64_values),
nulls: Arc::new(self.nulls),
},
ColumnTypeClass::Float64 => ColumnData::Float64 {
values: Arc::new(self.float64_values),
nulls: Arc::new(self.nulls),
},
ColumnTypeClass::String => ColumnData::String {
values: Arc::new(self.string_values),
nulls: Arc::new(self.nulls),
},
ColumnTypeClass::Bool => {
ColumnData::Bool { values: Arc::new(self.bool_values), nulls: Arc::new(self.nulls) }
}
ColumnTypeClass::Date => {
ColumnData::Date { values: Arc::new(self.date_values), nulls: Arc::new(self.nulls) }
}
ColumnTypeClass::Time => {
ColumnData::Time { values: Arc::new(self.time_values), nulls: Arc::new(self.nulls) }
}
ColumnTypeClass::Timestamp => ColumnData::Timestamp {
values: Arc::new(self.timestamp_values),
nulls: Arc::new(self.nulls),
},
ColumnTypeClass::Interval => ColumnData::Interval {
values: Arc::new(self.interval_values),
nulls: Arc::new(self.nulls),
},
ColumnTypeClass::Vector => {
ColumnData::Vector { values: Arc::new(Vec::new()), nulls: Arc::new(self.nulls) }
}
ColumnTypeClass::Blob => {
ColumnData::Blob { values: Arc::new(self.blob_values), nulls: Arc::new(self.nulls) }
}
}
}
}