use crate::value_types::vector_layout::{
element_child_vector, finish_elements, map_keys, map_values, reserve_elements, set_entry,
struct_field, write_null_row,
};
use crate::{DuckResult, DuckValueWriter, duck_error};
use libduckdb_sys::duckdb_vector;
use super::dynamic_row::DuckDynamicRow;
use super::dynamic_value::DuckDynamicValue;
use super::type_desc::DuckTypeDesc;
pub(super) struct DynColumnWriter {
writer: DuckValueWriter,
desc: DuckTypeDesc,
children: Vec<Self>,
offset: usize,
}
impl DynColumnWriter {
pub(super) fn prepare(
vector: duckdb_vector,
desc: &DuckTypeDesc,
values: &[Option<&DuckDynamicValue>],
) -> Self {
match desc {
DuckTypeDesc::Scalar(_) | DuckTypeDesc::Decimal { .. } => Self {
writer: DuckValueWriter::new_from_vector(vector),
desc: desc.clone(),
children: Vec::new(),
offset: 0,
},
DuckTypeDesc::List(element) => {
let total: usize = values
.iter()
.flatten()
.filter_map(|value| match value {
DuckDynamicValue::List(items) => Some(items.len()),
_ => None,
})
.sum();
reserve_elements(vector, total);
let child_vector = element_child_vector(vector);
let child_values: Vec<Option<&DuckDynamicValue>> = values
.iter()
.flatten()
.filter_map(|value| match value {
DuckDynamicValue::List(items) => Some(items.as_slice()),
_ => None,
})
.flatten()
.map(Option::as_ref)
.collect();
let child = Self::prepare(child_vector, element, &child_values);
Self {
writer: DuckValueWriter::new_from_vector(vector),
desc: desc.clone(),
children: vec![child],
offset: 0,
}
}
DuckTypeDesc::Struct(fields) => {
let children = fields
.iter()
.enumerate()
.map(|(index, (_, field_desc))| {
let child_vector = struct_field(vector, index);
let child_values = column_struct_values(values, index);
Self::prepare(child_vector, field_desc, &child_values)
})
.collect();
Self {
writer: DuckValueWriter::new_from_vector(vector),
desc: desc.clone(),
children,
offset: 0,
}
}
DuckTypeDesc::Map(key_desc, value_desc) => {
let total: usize = values
.iter()
.flatten()
.filter_map(|value| match value {
DuckDynamicValue::Map(pairs) => Some(pairs.len()),
_ => None,
})
.sum();
reserve_elements(vector, total);
let keys_vector = map_keys(vector);
let values_vector = map_values(vector);
let mut key_values: Vec<Option<&DuckDynamicValue>> = Vec::new();
let mut entry_values: Vec<Option<&DuckDynamicValue>> = Vec::new();
for value in values.iter().flatten() {
if let DuckDynamicValue::Map(pairs) = value {
for (key, map_value) in pairs {
key_values.push(Some(key));
entry_values.push(Some(map_value));
}
}
}
let key_writer = Self::prepare(keys_vector, key_desc, &key_values);
let value_writer = Self::prepare(values_vector, value_desc, &entry_values);
Self {
writer: DuckValueWriter::new_from_vector(vector),
desc: desc.clone(),
children: vec![key_writer, value_writer],
offset: 0,
}
}
}
}
pub(super) fn write_value(&mut self, idx: usize, value: &DuckDynamicValue) -> DuckResult<()> {
match value {
DuckDynamicValue::List(items) => {
if self.children.len() != 1 {
return Err(duck_error(
"dynamic column: LIST value written through a non-LIST column writer",
));
}
let offset = self.offset;
set_entry(self.writer.c_duckdb_vector, idx, offset, items.len());
for (index, item) in items.iter().enumerate() {
match item {
Some(item) => self.children[0].write_value(offset + index, item)?,
None => self.children[0].write_null(offset + index)?,
}
}
self.offset += items.len();
Ok(())
}
DuckDynamicValue::Struct(values) => {
if self.children.len() != values.len() {
return Err(duck_error(format!(
"dynamic column: STRUCT has {} fields but the column declares {}",
values.len(),
self.children.len()
)));
}
for (index, value) in values.iter().enumerate() {
match value {
Some(value) => self.children[index].write_value(idx, value)?,
None => self.children[index].write_null(idx)?,
}
}
Ok(())
}
DuckDynamicValue::Map(pairs) => {
if self.children.len() != 2 {
return Err(duck_error(
"dynamic column: MAP value written through a non-MAP column writer",
));
}
let offset = self.offset;
set_entry(self.writer.c_duckdb_vector, idx, offset, pairs.len());
for (index, (key, map_value)) in pairs.iter().enumerate() {
self.children[0].write_value(offset + index, key)?;
self.children[1].write_value(offset + index, map_value)?;
}
self.offset += pairs.len();
Ok(())
}
scalar => scalar.write_scalar(&mut self.writer, idx),
}
}
pub(super) fn write_null(&mut self, idx: usize) -> DuckResult<()> {
match &self.desc {
DuckTypeDesc::Scalar(_) | DuckTypeDesc::Decimal { .. } => unsafe {
self.writer.vector_writer.set_null(idx);
},
DuckTypeDesc::Struct(_) => {
unsafe { self.writer.vector_writer.set_null(idx) };
for child in &mut self.children {
child.write_null(idx)?;
}
}
DuckTypeDesc::List(_) | DuckTypeDesc::Map(_, _) => {
write_null_row(&mut self.writer, idx);
}
}
Ok(())
}
pub(super) fn finish(&mut self) {
match &self.desc {
DuckTypeDesc::Scalar(_) | DuckTypeDesc::Decimal { .. } => {}
DuckTypeDesc::Struct(_) => {
for child in &mut self.children {
child.finish();
}
}
DuckTypeDesc::List(_) => {
self.children[0].finish();
finish_elements(self.writer.c_duckdb_vector, self.offset);
}
DuckTypeDesc::Map(_, _) => {
self.children[0].finish();
self.children[1].finish();
finish_elements(self.writer.c_duckdb_vector, self.offset);
}
}
}
}
pub(super) fn column_values<'a>(
rows: &'a [Option<&'a DuckDynamicRow>],
column_index: usize,
) -> Vec<Option<&'a DuckDynamicValue>> {
rows.iter()
.map(|row| row.and_then(|row| row.values.get(column_index)).and_then(Option::as_ref))
.collect()
}
fn column_struct_values<'a>(
values: &[Option<&'a DuckDynamicValue>],
field_index: usize,
) -> Vec<Option<&'a DuckDynamicValue>> {
values
.iter()
.map(|value| {
value.and_then(|value| match value {
DuckDynamicValue::Struct(fields) => {
fields.get(field_index).and_then(Option::as_ref)
}
_ => None,
})
})
.collect()
}