mithril_signer/database/query/signed_beacon/
get_signed_beacon.rs

1use sqlite::Value;
2
3use mithril_common::entities::SignedEntityType;
4use mithril_common::StdResult;
5use mithril_persistence::sqlite::{Query, SourceAlias, SqLiteEntity, WhereCondition};
6
7use crate::database::record::SignedBeaconRecord;
8
9/// Simple queries to retrieve [SignedBeacon] from the sqlite database.
10pub struct GetSignedBeaconQuery {
11    condition: WhereCondition,
12}
13
14impl GetSignedBeaconQuery {
15    /// Get all signed beacons.
16    pub fn all() -> Self {
17        Self {
18            condition: WhereCondition::default(),
19        }
20    }
21
22    /// Get all signed beacons that match the given signed entity types.
23    pub fn by_signed_entities(signed_entity_types: &[SignedEntityType]) -> StdResult<Self> {
24        fn signed_entity_condition(entity: &SignedEntityType) -> StdResult<WhereCondition> {
25            Ok(WhereCondition::new(
26                "signed_entity_type_id = ?* and beacon = ?*",
27                vec![
28                    Value::Integer(entity.index() as i64),
29                    Value::String(entity.get_json_beacon()?),
30                ],
31            ))
32        }
33
34        let condition = match signed_entity_types {
35            [] => WhereCondition::new("false", vec![]),
36            [first, rest @ ..] => {
37                rest.iter()
38                    .try_fold(signed_entity_condition(first)?, |condition, entity| {
39                        StdResult::Ok(condition.or_where(signed_entity_condition(entity)?))
40                    })?
41            }
42        };
43
44        Ok(Self { condition })
45    }
46}
47
48impl Query for GetSignedBeaconQuery {
49    type Entity = SignedBeaconRecord;
50
51    fn filters(&self) -> WhereCondition {
52        self.condition.clone()
53    }
54
55    fn get_definition(&self, condition: &str) -> String {
56        let aliases = SourceAlias::new(&[("{:signed_beacon:}", "signed_beacon")]);
57        let projection = Self::Entity::get_projection().expand(aliases);
58        format!("select {projection} from signed_beacon where {condition} order by rowid desc")
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use mithril_common::entities::{BlockNumber, Epoch};
65    use mithril_persistence::sqlite::ConnectionExtensions;
66
67    use crate::database::test_helper::{insert_signed_beacons, main_db_connection};
68
69    use super::*;
70
71    #[test]
72    fn test_get_all() {
73        let connection = main_db_connection().unwrap();
74        let records = SignedBeaconRecord::fakes(&[
75            (
76                Epoch(3),
77                vec![SignedEntityType::MithrilStakeDistribution(Epoch(3))],
78            ),
79            (
80                Epoch(4),
81                vec![
82                    SignedEntityType::CardanoStakeDistribution(Epoch(4)),
83                    SignedEntityType::CardanoTransactions(Epoch(4), BlockNumber(124)),
84                ],
85            ),
86        ]);
87        insert_signed_beacons(&connection, records.clone());
88
89        let stored_records: Vec<SignedBeaconRecord> = connection
90            .fetch_collect(GetSignedBeaconQuery::all())
91            .unwrap();
92
93        assert_eq!(
94            records.into_iter().rev().collect::<Vec<_>>(),
95            stored_records
96        );
97    }
98
99    mod get_by_signed_entities {
100        use super::*;
101
102        #[test]
103        fn with_empty_db() {
104            let connection = main_db_connection().unwrap();
105
106            let stored_records: Vec<SignedBeaconRecord> = connection
107                .fetch_collect(
108                    GetSignedBeaconQuery::by_signed_entities(&[
109                        SignedEntityType::MithrilStakeDistribution(Epoch(3)),
110                        SignedEntityType::CardanoTransactions(Epoch(4), BlockNumber(124)),
111                    ])
112                    .unwrap(),
113                )
114                .unwrap();
115
116            assert_eq!(Vec::<SignedBeaconRecord>::new(), stored_records);
117        }
118
119        #[test]
120        fn with_empty_list() {
121            let connection = main_db_connection().unwrap();
122            let records = SignedBeaconRecord::fakes(&[
123                (
124                    Epoch(3),
125                    vec![SignedEntityType::MithrilStakeDistribution(Epoch(3))],
126                ),
127                (
128                    Epoch(4),
129                    vec![SignedEntityType::CardanoStakeDistribution(Epoch(4))],
130                ),
131            ]);
132            insert_signed_beacons(&connection, records.clone());
133
134            let stored_records: Vec<SignedBeaconRecord> = connection
135                .fetch_collect(GetSignedBeaconQuery::by_signed_entities(&[]).unwrap())
136                .unwrap();
137
138            assert_eq!(Vec::<SignedBeaconRecord>::new(), stored_records);
139        }
140
141        #[test]
142        fn with_one_matching() {
143            let connection = main_db_connection().unwrap();
144            let records = SignedBeaconRecord::fakes(&[
145                (
146                    Epoch(974),
147                    vec![SignedEntityType::MithrilStakeDistribution(Epoch(3))],
148                ),
149                (
150                    Epoch(975),
151                    vec![SignedEntityType::CardanoStakeDistribution(Epoch(4))],
152                ),
153            ]);
154            insert_signed_beacons(&connection, records.clone());
155
156            let stored_records: Vec<SignedBeaconRecord> = connection
157                .fetch_collect(
158                    GetSignedBeaconQuery::by_signed_entities(&[
159                        SignedEntityType::MithrilStakeDistribution(Epoch(3)),
160                    ])
161                    .unwrap(),
162                )
163                .unwrap();
164
165            assert_eq!(
166                vec![SignedBeaconRecord::fake(
167                    Epoch(974),
168                    SignedEntityType::MithrilStakeDistribution(Epoch(3))
169                )],
170                stored_records
171            );
172        }
173
174        #[test]
175        fn with_multiple_matching_over_several_epochs() {
176            let connection = main_db_connection().unwrap();
177            let records = SignedBeaconRecord::fakes(&[
178                (
179                    Epoch(329),
180                    vec![
181                        SignedEntityType::MithrilStakeDistribution(Epoch(3)),
182                        SignedEntityType::CardanoStakeDistribution(Epoch(3)),
183                    ],
184                ),
185                (
186                    Epoch(330),
187                    vec![
188                        SignedEntityType::CardanoStakeDistribution(Epoch(4)),
189                        SignedEntityType::MithrilStakeDistribution(Epoch(4)),
190                        SignedEntityType::CardanoTransactions(Epoch(4), BlockNumber(109)),
191                    ],
192                ),
193                (
194                    Epoch(331),
195                    vec![
196                        SignedEntityType::CardanoTransactions(Epoch(5), BlockNumber(124)),
197                        SignedEntityType::CardanoTransactions(Epoch(5), BlockNumber(133)),
198                    ],
199                ),
200            ]);
201            insert_signed_beacons(&connection, records.clone());
202
203            let stored_records: Vec<SignedBeaconRecord> = connection
204                .fetch_collect(
205                    GetSignedBeaconQuery::by_signed_entities(&[
206                        SignedEntityType::MithrilStakeDistribution(Epoch(3)),
207                        SignedEntityType::MithrilStakeDistribution(Epoch(4)),
208                        SignedEntityType::CardanoTransactions(Epoch(4), BlockNumber(109)),
209                        SignedEntityType::CardanoTransactions(Epoch(5), BlockNumber(133)),
210                    ])
211                    .unwrap(),
212                )
213                .unwrap();
214
215            assert_eq!(
216                SignedBeaconRecord::fakes(&[
217                    (
218                        Epoch(331),
219                        vec![SignedEntityType::CardanoTransactions(
220                            Epoch(5),
221                            BlockNumber(133)
222                        ),],
223                    ),
224                    (
225                        Epoch(330),
226                        vec![
227                            SignedEntityType::CardanoTransactions(Epoch(4), BlockNumber(109)),
228                            SignedEntityType::MithrilStakeDistribution(Epoch(4)),
229                        ],
230                    ),
231                    (
232                        Epoch(329),
233                        vec![SignedEntityType::MithrilStakeDistribution(Epoch(3)),],
234                    ),
235                ]),
236                stored_records
237            );
238        }
239
240        #[test]
241        fn duplicate_entities_in_parameter_should_not_yield_duplicate_matching() {
242            let connection = main_db_connection().unwrap();
243            let records = SignedBeaconRecord::fakes(&[(
244                Epoch(242),
245                vec![SignedEntityType::MithrilStakeDistribution(Epoch(3))],
246            )]);
247            insert_signed_beacons(&connection, records.clone());
248
249            let stored_records: Vec<SignedBeaconRecord> = connection
250                .fetch_collect(
251                    GetSignedBeaconQuery::by_signed_entities(&[
252                        SignedEntityType::MithrilStakeDistribution(Epoch(3)),
253                        SignedEntityType::MithrilStakeDistribution(Epoch(3)),
254                    ])
255                    .unwrap(),
256                )
257                .unwrap();
258
259            assert_eq!(
260                vec![SignedBeaconRecord::fake(
261                    Epoch(242),
262                    SignedEntityType::MithrilStakeDistribution(Epoch(3))
263                )],
264                stored_records
265            );
266        }
267    }
268}