diff options
| author | Jan Tuomi <jan@jantuomi.fi> | 2025-01-06 18:52:22 +0200 |
|---|---|---|
| committer | Jan Tuomi <jan@jantuomi.fi> | 2025-01-06 18:52:22 +0200 |
| commit | 21d0b647d6916c4dbbde8a310a0760872d44f7a2 (patch) | |
| tree | 0a22a2d94fe061ea778f03000d74d4bf1d4749f4 /log_db/src/record.rs | |
| parent | 563703446eaec2dbed721dbe2c6565cee0d419be (diff) | |
Rework DB interface to use Recordable instances
Diffstat (limited to 'log_db/src/record.rs')
| -rw-r--r-- | log_db/src/record.rs | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/log_db/src/record.rs b/log_db/src/record.rs new file mode 100644 index 0000000..1b882ed --- /dev/null +++ b/log_db/src/record.rs @@ -0,0 +1,113 @@ +use super::*; + +#[derive(Debug, Clone)] +pub struct Record { + pub values: Vec<Value>, + pub tombstone: bool, +} + +impl Record { + pub fn serialize(&self) -> Vec<u8> { + let mut bytes = Vec::new(); + + if self.tombstone { + bytes.extend(&[B_TOMBSTONE]); + } else { + bytes.extend(&[B_LIVE]); + } + + for value in &self.values { + bytes.extend(value.serialize()); + } + bytes + } + + pub fn deserialize(bytes: &[u8]) -> Record { + let mut values = Vec::new(); + + let tombstone = bytes[0] == B_TOMBSTONE; + + let mut start = 1; + while start < bytes.len() { + let (rv, consumed) = Value::deserialize(&bytes[start..]); + values.push(rv); + start += consumed; + } + Record { values, tombstone } + } + + pub fn from(values: &[Value]) -> Record { + Record { + values: values.to_vec(), + tombstone: false, + } + } + + pub fn at(&self, index: usize) -> &Value { + &self.values[index] + } + + pub fn validate<Field: Eq>(&self, schema: &Vec<(Field, ValueType)>) -> Result<(), DBError> { + // Validate the record length + if self.values.len() != schema.len() { + return Err(DBError::ValidationError(format!( + "Record has an incorrect number of fields: {}, expected {}", + self.values.len(), + schema.len() + ))); + } + + // Validate that record fields match schema types + for (i, (_, field)) in schema.iter().enumerate() { + match (&self.values[i], field) { + ( + Value::Null, + ValueType { + nullable: true, + prim_value_type: _, + }, + ) => {} + ( + Value::Int(_), + ValueType { + prim_value_type: PrimValueType::Int, + .. + }, + ) => {} + ( + Value::String(_), + ValueType { + prim_value_type: PrimValueType::String, + .. + }, + ) => {} + ( + Value::Bytes(_), + ValueType { + prim_value_type: PrimValueType::Bytes, + .. + }, + ) => {} + _ => { + return Err(DBError::ValidationError(format!( + "Record field {} has incorrect type: {:?}, expected {:?}", + &i, &self.values[i], &field.prim_value_type + ))); + } + } + } + Ok(()) + } +} + +/// A trait that describes how to convert a data structure into a database record and vice versa. +pub trait Recordable { + /// The field type of the data structure implementing the `Recordable` trait. + type Field: Eq + Clone + Debug; + /// Define the schema of the data structure implementing the `Recordable` trait. + fn schema() -> Vec<(Self::Field, ValueType)>; + /// Convert the data structure implementing the `Recordable` trait into a vector of database values. + fn into_record(self) -> Vec<Value>; + /// Convert a vector of database values into the data structure implementing the `Recordable` trait. + fn from_record(record: Vec<Value>) -> Self; +} |
