use bytes::{BufMut, Bytes, BytesMut};
use crate::{
base::KeySpace, ctrl::hlc::HlcTimestamp, row::resolved::ResolvedTable, types::TempestValue,
};
#[derive(Debug)]
pub(crate) struct RowEncoder<'a> {
table: &'a ResolvedTable<'a>,
pk_indices: Vec<usize>,
}
impl<'a> RowEncoder<'a> {
pub(crate) fn new(table: &'a ResolvedTable<'a>) -> Self {
let pk_indices = table.primary_key.clone();
Self { table, pk_indices }
}
fn typecheck(&self, row: &[TempestValue<'_>]) {
assert_eq!(row.len(), self.table.flat_fields.len());
for (val, ff) in row.iter().zip(self.table.flat_fields.iter()) {
let types_match = match (val.ty(), ff.ty) {
(a, b) if a == b => true,
(crate::types::TempestType::Enum(_), crate::types::TempestType::Enum(_)) => true,
_ => false,
};
assert!(
types_match,
"invalid type for column '{}': expected {:?}, but got {:?}",
ff.name,
ff.ty,
val.ty(),
);
}
}
fn encode_key(&self, row: &[TempestValue<'_>], hlc: HlcTimestamp, key_buf: &mut BytesMut) {
key_buf.put_u8(KeySpace::TableRow as u8);
key_buf.put_slice(&self.table.id.to_be_bytes());
for &idx in &self.pk_indices {
row[idx].encode_lexical(key_buf);
}
key_buf.put_u64(*hlc);
}
fn encode_value(&self, row: &[TempestValue<'_>], value_buf: &mut BytesMut) {
for (idx, val) in row.iter().enumerate() {
if !self.pk_indices.contains(&idx) {
val.encode(value_buf);
}
}
}
pub(crate) fn search_prefix(&self) -> Bytes {
let mut buf = BytesMut::new();
buf.put_u8(KeySpace::TableRow as u8);
buf.put_slice(&self.table.id.to_be_bytes());
buf.put_u64(*HlcTimestamp::MAX);
buf.freeze()
}
pub(crate) fn encode_row_key(
&self,
row: &[TempestValue<'_>],
hlc: HlcTimestamp,
key_buf: &mut BytesMut,
) {
self.typecheck(row);
self.encode_key(row, hlc, key_buf);
}
#[instrument(level = "trace")]
pub(crate) fn encode_row(
&self,
row: &[TempestValue<'_>],
hlc: HlcTimestamp,
key_buf: &mut BytesMut,
value_buf: &mut BytesMut,
) {
self.typecheck(row);
self.encode_key(row, hlc, key_buf);
self.encode_value(row, value_buf);
}
}