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
use diesel::prelude::*;
use diesel::result::Error;
use diesel::SqliteConnection;
use std::collections::HashMap;
use std::str::FromStr;
use uuid::Uuid;

use crate::models::BlockProperty;

pub type BlockProperties = HashMap<String, Vec<u8>>;

pub trait BlockPropertyCrud {
    fn create_block_properties(&self, block_id: &str, properties: BlockProperties) -> Vec<BlockProperty>;
    fn retrieve_block_properties(&self, block_id: &str) -> Vec<BlockProperty>;
    fn update_block_property(&self, block_id: &str, name: String, data: &[u8]) -> BlockProperty;
    fn update_block_properties(&self, block_id: &str, properties: BlockProperties) -> Vec<BlockProperty>;
    fn delete_block_property(&self, block_id: &str, name: String);
}

impl BlockPropertyCrud for SqliteConnection {
    fn create_block_properties(&self, block_id: &str, properties: BlockProperties) -> Vec<BlockProperty> {
        use crate::schema::block_properties::dsl;

        let block_uuid = Uuid::from_str(&block_id).unwrap().as_bytes().to_vec();

        self.transaction::<(), Error, _>(|| {
            for (name, data) in properties {
                let new_property = BlockProperty {
                    block_id: block_uuid.clone(),
                    name,
                    data: data.to_vec(),
                };

                diesel::insert_into(dsl::block_properties)
                    .values(new_property)
                    .execute(self)?;
            }

            Ok(())
        })
        .expect("Could not insert new properties");

        dsl::block_properties
            .filter(dsl::block_id.eq(block_uuid))
            .get_results(self)
            .expect("Could not retrieve the block properties")
    }

    fn retrieve_block_properties(&self, block_id: &str) -> Vec<BlockProperty> {
        use crate::schema::block_properties::dsl;

        let block_uuid = Uuid::from_str(&block_id).unwrap().as_bytes().to_vec();

        dsl::block_properties
            .filter(dsl::block_id.eq(block_uuid))
            .get_results(self)
            .expect(&format!("Could not retrieve properties from block {}", block_id))
    }

    fn update_block_property(&self, block_id: &str, name: String, data: &[u8]) -> BlockProperty {
        use crate::schema::block_properties::dsl;

        let block_uuid = Uuid::from_str(&block_id).unwrap().as_bytes().to_vec();

        diesel::update(dsl::block_properties.find((&block_uuid, &name)))
            .set(dsl::data.eq(data.to_vec()))
            .execute(self)
            .and_then(|_| dsl::block_properties.find((&block_uuid, &name)).first(self))
            .expect(&format!("Could not update property {} of block {}", name, block_id))
    }

    fn update_block_properties(&self, block_id: &str, properties: BlockProperties) -> Vec<BlockProperty> {
        let blocks_properties = self
            .transaction::<Vec<BlockProperty>, Error, _>(|| {
                let block_properties: Vec<BlockProperty> = properties
                    .iter()
                    .map(|(name, data)| self.update_block_property(block_id, name.clone(), data))
                    .collect();

                Ok(block_properties)
            })
            .expect(&format!("Could not update properties of block {}", block_id));

        blocks_properties
    }

    fn delete_block_property(&self, block_id: &str, name: String) {
        use crate::schema::block_properties::dsl;

        let block_uuid = Uuid::from_str(&block_id).unwrap().as_bytes().to_vec();

        diesel::delete(dsl::block_properties.find((&block_uuid, &name)))
            .execute(self)
            .expect(&format!("Could not delete property {} of block {}", name, block_id));
    }
}