aboutsummaryrefslogtreecommitdiffstats
path: root/log_db/src/record.rs
blob: 1b882eda57605f79bfca81552f6ef71e8ab8bb27 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
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;
}