tempest-engine 0.0.2

Relational database engine for TempestDB
Documentation
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,
                // Allow any enum value for an enum column (type_id checked at eval time)
                (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);
    }

    /// Encodes a full row into `key_buf` and `value_buf`.
    /// `row` is flat - one value per leaf field in `flat_fields` order.
    #[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);
    }
}