use alloc::string::String;
use alloc::vec::Vec;
use super::adapter::WireAdapter;
use super::conversion_error::ConversionError;
use super::source::{WireColumnTypes, WireSchema, WireSource};
use super::wire_type::WireType;
use crate::builders::{ChangeDelete, Insert, PatchDelete, PatchsetFormat, Update};
use crate::encoding::Value;
use crate::schema::NamedColumns;
pub(crate) fn resolve_table<'a, Sch>(
schema: &'a Sch,
name: &str,
) -> Result<&'a Sch::Table, ConversionError>
where
Sch: WireSchema,
{
schema
.get(name)
.ok_or_else(|| ConversionError::TableNotFound(String::from(name)))
}
pub(crate) trait WireColumnItem<Src: WireSource> {
fn name(&self) -> &str;
fn payload(&self, wire_type: WireType) -> Src::Payload<'_>;
}
fn decode_item<Src, T, S, B, A, C>(
item: &C,
table: &T,
adapter: &A,
) -> Result<(usize, Value<S, B>), ConversionError>
where
Src: WireSource,
T: NamedColumns + WireColumnTypes,
A: WireAdapter<Src, S, B>,
C: WireColumnItem<Src>,
{
let name = item.name();
let col_idx = table
.column_index(name)
.ok_or_else(|| ConversionError::ColumnNotFound(String::from(name)))?;
let wire_type = table.column_type(col_idx);
let value = adapter.decode(item.payload(wire_type))?;
Ok((col_idx, value))
}
pub(crate) fn build_insert<Src, T, S, B, A, I, C>(
items: I,
table: &T,
adapter: &A,
) -> Result<Insert<T, S, B>, ConversionError>
where
Src: WireSource,
T: NamedColumns + WireColumnTypes,
S: Clone + AsRef<str>,
B: Clone + AsRef<[u8]>,
A: WireAdapter<Src, S, B>,
I: IntoIterator<Item = C>,
C: WireColumnItem<Src>,
{
let mut insert = Insert::from(table.clone());
for item in items {
let (col_idx, value) = decode_item(&item, table, adapter)?;
insert = insert
.set(col_idx, value)
.map_err(|_| ConversionError::ColumnNotFound(String::from(item.name())))?;
}
Ok(insert)
}
pub(crate) fn build_patchset_update<Src, T, S, B, A, I, C>(
items: I,
table: &T,
adapter: &A,
) -> Result<Update<T, PatchsetFormat, S, B>, ConversionError>
where
Src: WireSource,
T: NamedColumns + WireColumnTypes,
S: Clone + AsRef<str>,
B: Clone + AsRef<[u8]>,
A: WireAdapter<Src, S, B>,
I: IntoIterator<Item = C>,
C: WireColumnItem<Src>,
{
let mut update: Update<T, PatchsetFormat, S, B> = Update::from(table.clone());
for item in items {
let (col_idx, value) = decode_item(&item, table, adapter)?;
update = update
.set(col_idx, value)
.map_err(|_| ConversionError::ColumnNotFound(String::from(item.name())))?;
}
Ok(update)
}
pub(crate) fn build_changeset_delete<Src, T, S, B, A, I, C>(
items: I,
table: &T,
adapter: &A,
) -> Result<ChangeDelete<T, S, B>, ConversionError>
where
Src: WireSource,
T: NamedColumns + WireColumnTypes,
S: Clone + Default + AsRef<str>,
B: Clone + Default + AsRef<[u8]>,
A: WireAdapter<Src, S, B>,
I: IntoIterator<Item = C>,
C: WireColumnItem<Src>,
{
let mut delete = ChangeDelete::from(table.clone());
for item in items {
let (col_idx, value) = decode_item(&item, table, adapter)?;
delete = delete
.set(col_idx, value)
.map_err(|_| ConversionError::ColumnNotFound(String::from(item.name())))?;
}
Ok(delete)
}
pub(crate) fn build_patch_delete<Src, T, S, B, A, I, C>(
items: I,
table: &T,
adapter: &A,
) -> Result<PatchDelete<T, S, B>, ConversionError>
where
Src: WireSource,
T: NamedColumns + WireColumnTypes,
S: Clone + AsRef<str>,
B: Clone + AsRef<[u8]>,
A: WireAdapter<Src, S, B>,
I: IntoIterator<Item = C>,
C: WireColumnItem<Src>,
{
let num_pks = table.number_of_primary_keys();
let mut pk_slots: Vec<Option<Value<S, B>>> = alloc::vec![None; num_pks];
for item in items {
let name = item.name();
let col_idx = table
.column_index(name)
.ok_or_else(|| ConversionError::ColumnNotFound(String::from(name)))?;
if let Some(pk_idx) = table.primary_key_index(col_idx) {
let wire_type = table.column_type(col_idx);
pk_slots[pk_idx] = Some(adapter.decode(item.payload(wire_type))?);
}
}
let pk = pk_slots
.into_iter()
.collect::<Option<Vec<_>>>()
.ok_or(ConversionError::MissingColumns)?;
Ok(PatchDelete::new(table.clone(), pk))
}