nxtnote_savefile_format/crud/
blocks.rs

1use std::collections::HashMap;
2use std::str::FromStr;
3
4use diesel::prelude::*;
5use diesel::SqliteConnection;
6use uuid::Uuid;
7
8use crate::models::{Block, BlockProperty};
9use crate::utils::rank::SaveFileRanking;
10
11pub type SavedBlockProperties = HashMap<String, Vec<u8>>;
12
13pub struct BlockRanking {
14    pub previous_id: Option<String>,
15    pub next_id: Option<String>,
16}
17
18// todo: return Result
19pub trait BlockCrud {
20    fn create_block(&self, ranking: BlockRanking, block_type: String) -> Block;
21    fn retrieve_block(&self, block_id: &str) -> Block;
22    fn retrieve_block_with_properties(&self, block_id: &str) -> (Block, SavedBlockProperties);
23    fn retrieve_all_blocks(&self) -> Vec<Block>;
24    fn retrieve_all_blocks_with_properties(&self) -> Vec<(Block, SavedBlockProperties)>;
25    fn update_block_rank(&self, block_id: &str, ranking: BlockRanking) -> Block;
26    fn delete_block(&self, block_id: &str);
27}
28
29impl BlockCrud for SqliteConnection {
30    // todo: add properties too
31    fn create_block(&self, ranking: BlockRanking, block_type: String) -> Block {
32        use crate::schema::blocks::dsl::*;
33
34        let block_uuid = Uuid::new_v4().as_bytes().to_vec();
35        let block_rank = self.generate_ranking(ranking.previous_id, ranking.next_id);
36
37        let new_block = Block {
38            id: block_uuid.clone(),
39            rank: block_rank,
40            type_: block_type,
41        };
42
43        diesel::insert_into(blocks)
44            .values(&new_block)
45            .execute(self)
46            .and_then(|_| blocks.find(&block_uuid).first(self))
47            .expect("Error saving new block")
48    }
49
50    // todo: add properties too
51    fn retrieve_block(&self, block_id: &str) -> Block {
52        use crate::schema::blocks::dsl::*;
53
54        let block_uuid = Uuid::from_str(&block_id).unwrap().as_bytes().to_vec();
55
56        blocks
57            .find(block_uuid)
58            .first(self)
59            .expect(&format!("Could not retrieve block with {}", block_id))
60    }
61
62    fn retrieve_block_with_properties(&self, block_id: &str) -> (Block, SavedBlockProperties) {
63        use crate::schema::block_properties::dsl as block_properties_dsl;
64        use crate::schema::blocks::dsl as blocks_dsl;
65
66        let block_uuid = Uuid::from_str(&block_id).unwrap().as_bytes().to_vec();
67
68        let mut results: Vec<(Block, BlockProperty)> = blocks_dsl::blocks
69            .find(block_uuid)
70            .inner_join(block_properties_dsl::block_properties)
71            .get_results(self)
72            .expect(&format!("Could not retrieve block with {}", block_id));
73
74        let mut block: Option<Block> = None;
75        let mut properties: SavedBlockProperties = SavedBlockProperties::new();
76
77        while !results.is_empty() {
78            let (current_block, property) = results.remove(0);
79
80            if block.is_none() {
81                block = Some(current_block);
82            }
83
84            properties.insert(property.name, property.data);
85        }
86
87        (block.unwrap(), properties)
88    }
89
90    fn retrieve_all_blocks(&self) -> Vec<Block> {
91        use crate::schema::blocks::dsl::*;
92
93        blocks
94            .order(rank)
95            .get_results(self)
96            .expect("Could not retrieve all blocks from save file")
97    }
98
99    fn retrieve_all_blocks_with_properties(&self) -> Vec<(Block, SavedBlockProperties)> {
100        use crate::schema::block_properties::dsl as block_properties_dsl;
101        use crate::schema::blocks::dsl as blocks_dsl;
102
103        let mut results: Vec<(Block, BlockProperty)> = blocks_dsl::blocks
104            .order(blocks_dsl::rank)
105            .inner_join(block_properties_dsl::block_properties)
106            .get_results(self)
107            .expect("Could not retrieve blocks with their properties");
108
109        let mut blocks = Vec::new();
110        let mut next_block_index: usize = 0;
111        let mut block_index_registry: HashMap<Vec<u8>, usize> = HashMap::new();
112
113        while !results.is_empty() {
114            let (current_block, property) = results.remove(0);
115
116            match block_index_registry.get(&current_block.id) {
117                None => {
118                    let mut properties = SavedBlockProperties::new();
119                    properties.insert(property.name, property.data);
120
121                    block_index_registry.insert(current_block.id.clone(), next_block_index);
122
123                    blocks.push((current_block, properties));
124
125                    next_block_index += 1;
126                }
127                Some(index) => {
128                    let (_, block_properties) = blocks.get_mut(*index).unwrap();
129
130                    block_properties.insert(property.name, property.data);
131                }
132            }
133        }
134
135        blocks
136    }
137
138    fn update_block_rank(&self, block_id: &str, ranking: BlockRanking) -> Block {
139        use crate::schema::blocks::dsl::*;
140
141        let block_uuid = Uuid::from_str(&block_id).unwrap().as_bytes().to_vec();
142        let block_rank = self.generate_ranking(ranking.previous_id, ranking.next_id);
143
144        diesel::update(blocks.find(&block_uuid))
145            .set(rank.eq(block_rank))
146            .execute(self)
147            .and_then(|_| blocks.find(&block_uuid).first(self))
148            .expect(&format!("Could not find block {}", block_id))
149    }
150
151    fn delete_block(&self, block_id: &str) {
152        use crate::schema::blocks::dsl::*;
153
154        let block_uuid = Uuid::from_str(&block_id).unwrap().as_bytes().to_vec();
155
156        diesel::delete(blocks.find(block_uuid))
157            .execute(self)
158            .expect(&format!("Could not delete block {}", block_id));
159    }
160}