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
use crate::{
    model::{Model, StoredModel},
    PersistenceEngine, Serializer,
};

#[derive(Debug)]
pub enum Error {
    DatabaseVersionError {
        db_version: String,
        current_version: String,
    },
    PersisterAlreadyExists {
        persister_name: String,
    },
    WrappedError(anyhow::Error),
}

pub type Result<T> = std::result::Result<T, Error>;

/// A Catwalk acts as a common interface to a [serializer](Serializer) and
/// a [persistence engine](PersistenceEngine).
pub struct Catwalk<S, P>
where
    S: Serializer,
    P: PersistenceEngine,
{
    pub serializer: S,
    pub p_engine: P,
}

impl<S, P> Catwalk<S, P>
where
    S: Serializer,
    P: PersistenceEngine,
{
    pub fn new(serializer: S, p_engine: P) -> Self {
        Self {
            serializer,
            p_engine,
        }
    }

    pub fn store<M: Model>(&mut self, model: &M) -> Result<()> {
        let bytes = self.serializer.to_bytes::<M, &[u8]>(model)?;
        self.p_engine.store(M::model_name(), model.get_key(), bytes)
    }

    pub fn get<M: Model>(&mut self, key: &str) -> Result<Option<M>> {
        let bytes = match self.p_engine.get::<&[u8]>(M::model_name(), key)? {
            Some(b) => b,
            None => return Ok(None),
        };
        let stored_model: StoredModel<M> = self.serializer.from_bytes(bytes)?;
        Ok(Some(self.check_version(stored_model)?))
    }

    #[allow(unused_variables)]
    pub fn check_version<M: Model>(
        &self,
        StoredModel { model, version }: StoredModel<M>,
    ) -> Result<M> {
        todo!();
    }
}