mithril_persistence/database/query/block_range_root/
get_block_range_root.rs

1use sqlite::Value;
2
3use mithril_common::entities::BlockNumber;
4
5use crate::database::record::BlockRangeRootRecord;
6use crate::sqlite::{Query, SourceAlias, SqLiteEntity, WhereCondition};
7
8/// Simple queries to retrieve [BlockRangeRootRecord] from the sqlite database.
9pub struct GetBlockRangeRootQuery {
10    condition: WhereCondition,
11}
12
13impl GetBlockRangeRootQuery {
14    pub fn all() -> Self {
15        Self {
16            condition: WhereCondition::default(),
17        }
18    }
19
20    pub fn contains_or_below_block_number(block_number: BlockNumber) -> Self {
21        Self {
22            condition: WhereCondition::new(
23                "start < ?*",
24                vec![Value::Integer(*block_number as i64)],
25            ),
26        }
27    }
28
29    pub fn highest() -> Self {
30        Self {
31            condition: WhereCondition::new("end = (select max(end) from block_range_root)", vec![]),
32        }
33    }
34}
35
36impl Query for GetBlockRangeRootQuery {
37    type Entity = BlockRangeRootRecord;
38
39    fn filters(&self) -> WhereCondition {
40        self.condition.clone()
41    }
42
43    fn get_definition(&self, condition: &str) -> String {
44        let aliases = SourceAlias::new(&[("{:block_range_root:}", "block_range_root")]);
45        let projection = Self::Entity::get_projection().expand(aliases);
46
47        format!("select {projection} from block_range_root where {condition} order by start, end")
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use mithril_common::crypto_helper::MKTreeNode;
54    use mithril_common::entities::BlockRange;
55
56    use crate::database::query::block_range_root::test_helper::insert_block_range_roots;
57    use crate::database::query::GetBlockRangeRootQuery;
58    use crate::database::test_helper::cardano_tx_db_connection;
59    use crate::sqlite::ConnectionExtensions;
60
61    use super::*;
62
63    fn block_range_root_dataset() -> Vec<BlockRangeRootRecord> {
64        [
65            (
66                BlockRange::from_block_number(BlockNumber(15)),
67                MKTreeNode::from_hex("AAAA").unwrap(),
68            ),
69            (
70                BlockRange::from_block_number(BlockNumber(30)),
71                MKTreeNode::from_hex("BBBB").unwrap(),
72            ),
73            (
74                BlockRange::from_block_number(BlockNumber(45)),
75                MKTreeNode::from_hex("CCCC").unwrap(),
76            ),
77        ]
78        .into_iter()
79        .map(BlockRangeRootRecord::from)
80        .collect()
81    }
82
83    #[test]
84    fn test_get_contains_or_below_block_number_with_empty_db() {
85        let connection = cardano_tx_db_connection().unwrap();
86
87        let cursor: Vec<BlockRangeRootRecord> = connection
88            .fetch_collect(GetBlockRangeRootQuery::contains_or_below_block_number(
89                BlockNumber(100),
90            ))
91            .unwrap();
92        assert_eq!(Vec::<BlockRangeRootRecord>::new(), cursor);
93    }
94
95    #[test]
96    fn test_get_contains_or_below_block_number_higher_than_the_highest_stored_block_range() {
97        let connection = cardano_tx_db_connection().unwrap();
98        let dataset = block_range_root_dataset();
99        insert_block_range_roots(&connection, dataset.clone());
100
101        let cursor: Vec<BlockRangeRootRecord> = connection
102            .fetch_collect(GetBlockRangeRootQuery::contains_or_below_block_number(
103                BlockNumber(10_000),
104            ))
105            .unwrap();
106
107        assert_eq!(dataset, cursor);
108    }
109
110    #[test]
111    fn test_get_contains_or_below_block_number_below_end_of_the_third_block_range() {
112        let connection = cardano_tx_db_connection().unwrap();
113        let dataset = block_range_root_dataset();
114        insert_block_range_roots(&connection, dataset.clone());
115
116        let cursor: Vec<BlockRangeRootRecord> = connection
117            .fetch_collect(GetBlockRangeRootQuery::contains_or_below_block_number(
118                BlockNumber(44),
119            ))
120            .unwrap();
121
122        assert_eq!(&dataset[0..2], &cursor);
123    }
124
125    #[test]
126    fn test_get_contains_or_below_block_number_equal_to_end_of_the_third_block_range() {
127        let connection = cardano_tx_db_connection().unwrap();
128        let dataset = block_range_root_dataset();
129        insert_block_range_roots(&connection, dataset.clone());
130
131        let cursor: Vec<BlockRangeRootRecord> = connection
132            .fetch_collect(GetBlockRangeRootQuery::contains_or_below_block_number(
133                BlockNumber(45),
134            ))
135            .unwrap();
136
137        assert_eq!(&dataset[0..2], &cursor);
138    }
139
140    #[test]
141    fn test_get_contains_or_below_block_number_after_end_of_the_third_block_range() {
142        let connection = cardano_tx_db_connection().unwrap();
143        let dataset = block_range_root_dataset();
144        insert_block_range_roots(&connection, dataset.clone());
145
146        let cursor: Vec<BlockRangeRootRecord> = connection
147            .fetch_collect(GetBlockRangeRootQuery::contains_or_below_block_number(
148                BlockNumber(46),
149            ))
150            .unwrap();
151
152        assert_eq!(dataset, cursor);
153    }
154
155    #[test]
156    fn test_get_highest_with_empty_db() {
157        let connection = cardano_tx_db_connection().unwrap();
158
159        let cursor: Option<BlockRangeRootRecord> = connection
160            .fetch_first(GetBlockRangeRootQuery::highest())
161            .unwrap();
162        assert_eq!(None, cursor);
163    }
164
165    #[test]
166    fn test_get_highest() {
167        let connection = cardano_tx_db_connection().unwrap();
168        let dataset = block_range_root_dataset();
169        insert_block_range_roots(&connection, dataset.clone());
170
171        let cursor: Option<BlockRangeRootRecord> = connection
172            .fetch_first(GetBlockRangeRootQuery::highest())
173            .unwrap();
174        assert_eq!(dataset.last().cloned(), cursor);
175    }
176}