nxtnote_savefile_format/crud/
blocks.rs1use 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
18pub 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 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 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(¤t_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}