use {
crate::{Cast, Error, Result, Value, ValueType},
odbc_api::buffers::{
AnyColumnBuffer, BufferDescription, BufferKind, ColumnarBuffer, TextRowSet,
},
};
impl Into<BufferKind> for ValueType {
fn into(self) -> BufferKind {
match self {
ValueType::Str => BufferKind::Text {
max_str_len: 255, },
ValueType::I64 => BufferKind::I64,
ValueType::F64 => BufferKind::F64,
ValueType::Bool => BufferKind::Bit,
ValueType::Timestamp => BufferKind::Timestamp,
ValueType::U64 => BufferKind::I64, _ => unimplemented!(),
}
}
}
struct ColumnValues {
index: usize,
value_type: ValueType,
pub values: Vec<Value>,
size: usize,
}
impl TryInto<AnyColumnBuffer> for ColumnValues {
type Error = Error;
fn try_into(self) -> Result<AnyColumnBuffer> {
let description = BufferDescription {
nullable: true,
kind: self.value_type.into(),
};
let mut buffer = AnyColumnBuffer::from_description(self.size, description);
match &mut buffer {
AnyColumnBuffer::NullableI64(column) => {
let values = self
.values
.into_iter()
.map(|cell| {
Ok(if matches!(cell, Value::Null) {
None
} else {
Some(cell.cast()?)
})
})
.collect::<Result<Vec<Option<i64>>>>()?;
column.writer_n(self.size).write(values.into_iter());
}
AnyColumnBuffer::Text(column) => {
let values = self
.values
.into_iter()
.map(|cell| {
Ok(if matches!(cell, Value::Null) {
None
} else {
Some(cell.cast()?)
})
})
.collect::<Result<Vec<Option<String>>>>()?;
column.writer_n(self.size).write(
values
.iter()
.map(|text| text.as_ref().map(|text| text.as_bytes())),
);
}
_ => unimplemented!(),
}
Ok(buffer)
}
}
pub(crate) struct ColumnSet {
columns: Vec<ColumnValues>,
}
impl ColumnSet {
pub fn new(rows: Vec<Vec<Value>>, size: usize) -> Self {
let columns: Vec<(Vec<Value>, Option<ValueType>)> =
rows[0].iter().map(|_| (Vec::new(), None)).collect();
let columns = rows.into_iter().fold(columns, |mut columns, row| {
row.into_iter().enumerate().for_each(|(index, cell)| {
if columns[index].1.is_none() && !matches!(cell, Value::Null) {
columns[index].1 = Some((&cell).into());
}
columns[index].0.push(cell);
});
columns
});
let columns = columns
.into_iter()
.enumerate()
.filter_map(|(index, (values, value_type))| {
value_type.map(|value_type| ColumnValues {
index,
value_type,
values,
size,
})
})
.collect();
Self { columns }
}
pub fn query(&self, table: &str, columns: &[&str]) -> String {
let columns: Vec<&str> = columns
.into_iter()
.enumerate()
.filter(|(index, _)| self.columns.iter().any(|col| index == &col.index))
.map(|(_, column)| *column)
.collect();
let placeholders: Vec<&str> = columns.iter().map(|_| "?").collect();
format!(
"INSERT INTO {table} ({columns}) VALUES ({placeholders})",
table = table,
columns = columns.join(", "),
placeholders = placeholders.join(", ")
)
}
}
impl TryInto<ColumnarBuffer<AnyColumnBuffer>> for ColumnSet {
type Error = Error;
fn try_into(self) -> Result<ColumnarBuffer<AnyColumnBuffer>> {
let buffers = self
.columns
.into_iter()
.enumerate()
.map(|(index, column)| column.try_into().map(|buffer| (index as u16, buffer)))
.collect::<Result<Vec<_>>>()?;
Ok(ColumnarBuffer::new(buffers))
}
}
impl TryInto<TextRowSet> for ColumnSet {
type Error = Error;
fn try_into(self) -> Result<TextRowSet> {
let mut buffer = TextRowSet::from_max_str_lens(
self.columns[0].values.len(),
self.columns.iter().map(|_| 0),
)?;
for index in 0..self.columns[0].values.len() {
let record = self
.columns
.iter()
.map(|column| column.values[index].clone().cast())
.collect::<Result<Vec<String>>>()?;
buffer.append(record.iter().map(|field| Some(field.as_bytes())))
}
Ok(buffer)
}
}