use crate::{
db::{
data::{DataKey, DataRow, PersistedRow, RawRow},
executor::CursorPage,
executor::PageCursor,
response::{EntityResponse, Row},
},
error::InternalError,
traits::{EntityKind, EntityValue},
types::Id,
};
use std::fmt::Display;
pub(in crate::db) fn decode_raw_row_for_entity_key<E>(
data_key: &DataKey,
raw_row: &RawRow,
) -> Result<(E::Key, E), InternalError>
where
E: PersistedRow + EntityValue,
{
let expected_key = data_key.try_key::<E>()?;
let entity = RawRow::try_decode::<E>(raw_row).map_err(|err| {
InternalError::serialize_corruption(decode_failure_message(data_key, err))
})?;
let actual_key = entity.id().key();
if expected_key != actual_key {
let expected = format_entity_key_for_mismatch::<E>(expected_key);
let found = format_entity_key_for_mismatch::<E>(actual_key);
return Err(InternalError::store_corruption(key_mismatch_message(
expected, found,
)));
}
Ok((expected_key, entity))
}
pub(in crate::db) fn decode_data_rows_into_entity_response<E>(
rows: Vec<DataRow>,
) -> Result<EntityResponse<E>, InternalError>
where
E: PersistedRow + EntityValue,
{
let mut decoded_rows = Vec::with_capacity(rows.len());
for row in rows {
let (data_key, raw_row) = row;
let (expected_key, entity) = decode_raw_row_for_entity_key::<E>(&data_key, &raw_row)?;
decoded_rows.push(Row::new(Id::from_key(expected_key), entity));
}
Ok(EntityResponse::new(decoded_rows))
}
pub(in crate::db) fn decode_data_rows_into_cursor_page<E>(
rows: Vec<DataRow>,
next_cursor: Option<PageCursor>,
) -> Result<CursorPage<E>, InternalError>
where
E: PersistedRow + EntityValue,
{
Ok(CursorPage {
items: decode_data_rows_into_entity_response::<E>(rows)?,
next_cursor,
})
}
fn decode_failure_message(data_key: &DataKey, err: impl Display) -> String {
format!("failed to deserialize row: {data_key} ({err})")
}
fn key_mismatch_message(expected: impl Display, actual: impl Display) -> String {
format!("row key mismatch: expected {expected}, found {actual}")
}
pub(in crate::db) fn format_entity_key_for_mismatch<E>(key: E::Key) -> String
where
E: EntityKind,
E::Key: std::fmt::Debug,
{
DataKey::try_new::<E>(key).map_or_else(|_| format!("{key:?}"), |key| key.to_string())
}