mithril_signer/database/query/signed_beacon/
get_signed_beacon.rs

1use sqlite::Value;
2
3use mithril_common::StdResult;
4use mithril_common::entities::SignedEntityType;
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> =
90            connection.fetch_collect(GetSignedBeaconQuery::all()).unwrap();
91
92        assert_eq!(
93            records.into_iter().rev().collect::<Vec<_>>(),
94            stored_records
95        );
96    }
97
98    mod get_by_signed_entities {
99        use super::*;
100
101        #[test]
102        fn with_empty_db() {
103            let connection = main_db_connection().unwrap();
104
105            let stored_records: Vec<SignedBeaconRecord> = connection
106                .fetch_collect(
107                    GetSignedBeaconQuery::by_signed_entities(&[
108                        SignedEntityType::MithrilStakeDistribution(Epoch(3)),
109                        SignedEntityType::CardanoTransactions(Epoch(4), BlockNumber(124)),
110                    ])
111                    .unwrap(),
112                )
113                .unwrap();
114
115            assert_eq!(Vec::<SignedBeaconRecord>::new(), stored_records);
116        }
117
118        #[test]
119        fn with_empty_list() {
120            let connection = main_db_connection().unwrap();
121            let records = SignedBeaconRecord::fakes(&[
122                (
123                    Epoch(3),
124                    vec![SignedEntityType::MithrilStakeDistribution(Epoch(3))],
125                ),
126                (
127                    Epoch(4),
128                    vec![SignedEntityType::CardanoStakeDistribution(Epoch(4))],
129                ),
130            ]);
131            insert_signed_beacons(&connection, records.clone());
132
133            let stored_records: Vec<SignedBeaconRecord> = connection
134                .fetch_collect(GetSignedBeaconQuery::by_signed_entities(&[]).unwrap())
135                .unwrap();
136
137            assert_eq!(Vec::<SignedBeaconRecord>::new(), stored_records);
138        }
139
140        #[test]
141        fn with_one_matching() {
142            let connection = main_db_connection().unwrap();
143            let records = SignedBeaconRecord::fakes(&[
144                (
145                    Epoch(974),
146                    vec![SignedEntityType::MithrilStakeDistribution(Epoch(3))],
147                ),
148                (
149                    Epoch(975),
150                    vec![SignedEntityType::CardanoStakeDistribution(Epoch(4))],
151                ),
152            ]);
153            insert_signed_beacons(&connection, records.clone());
154
155            let stored_records: Vec<SignedBeaconRecord> = connection
156                .fetch_collect(
157                    GetSignedBeaconQuery::by_signed_entities(&[
158                        SignedEntityType::MithrilStakeDistribution(Epoch(3)),
159                    ])
160                    .unwrap(),
161                )
162                .unwrap();
163
164            assert_eq!(
165                vec![SignedBeaconRecord::fake(
166                    Epoch(974),
167                    SignedEntityType::MithrilStakeDistribution(Epoch(3))
168                )],
169                stored_records
170            );
171        }
172
173        #[test]
174        fn with_multiple_matching_over_several_epochs() {
175            let connection = main_db_connection().unwrap();
176            let records = SignedBeaconRecord::fakes(&[
177                (
178                    Epoch(329),
179                    vec![
180                        SignedEntityType::MithrilStakeDistribution(Epoch(3)),
181                        SignedEntityType::CardanoStakeDistribution(Epoch(3)),
182                    ],
183                ),
184                (
185                    Epoch(330),
186                    vec![
187                        SignedEntityType::CardanoStakeDistribution(Epoch(4)),
188                        SignedEntityType::MithrilStakeDistribution(Epoch(4)),
189                        SignedEntityType::CardanoTransactions(Epoch(4), BlockNumber(109)),
190                    ],
191                ),
192                (
193                    Epoch(331),
194                    vec![
195                        SignedEntityType::CardanoTransactions(Epoch(5), BlockNumber(124)),
196                        SignedEntityType::CardanoTransactions(Epoch(5), BlockNumber(133)),
197                    ],
198                ),
199            ]);
200            insert_signed_beacons(&connection, records.clone());
201
202            let stored_records: Vec<SignedBeaconRecord> = connection
203                .fetch_collect(
204                    GetSignedBeaconQuery::by_signed_entities(&[
205                        SignedEntityType::MithrilStakeDistribution(Epoch(3)),
206                        SignedEntityType::MithrilStakeDistribution(Epoch(4)),
207                        SignedEntityType::CardanoTransactions(Epoch(4), BlockNumber(109)),
208                        SignedEntityType::CardanoTransactions(Epoch(5), BlockNumber(133)),
209                    ])
210                    .unwrap(),
211                )
212                .unwrap();
213
214            assert_eq!(
215                SignedBeaconRecord::fakes(&[
216                    (
217                        Epoch(331),
218                        vec![SignedEntityType::CardanoTransactions(Epoch(5), BlockNumber(133)),],
219                    ),
220                    (
221                        Epoch(330),
222                        vec![
223                            SignedEntityType::CardanoTransactions(Epoch(4), BlockNumber(109)),
224                            SignedEntityType::MithrilStakeDistribution(Epoch(4)),
225                        ],
226                    ),
227                    (
228                        Epoch(329),
229                        vec![SignedEntityType::MithrilStakeDistribution(Epoch(3)),],
230                    ),
231                ]),
232                stored_records
233            );
234        }
235
236        #[test]
237        fn duplicate_entities_in_parameter_should_not_yield_duplicate_matching() {
238            let connection = main_db_connection().unwrap();
239            let records = SignedBeaconRecord::fakes(&[(
240                Epoch(242),
241                vec![SignedEntityType::MithrilStakeDistribution(Epoch(3))],
242            )]);
243            insert_signed_beacons(&connection, records.clone());
244
245            let stored_records: Vec<SignedBeaconRecord> = connection
246                .fetch_collect(
247                    GetSignedBeaconQuery::by_signed_entities(&[
248                        SignedEntityType::MithrilStakeDistribution(Epoch(3)),
249                        SignedEntityType::MithrilStakeDistribution(Epoch(3)),
250                    ])
251                    .unwrap(),
252                )
253                .unwrap();
254
255            assert_eq!(
256                vec![SignedBeaconRecord::fake(
257                    Epoch(242),
258                    SignedEntityType::MithrilStakeDistribution(Epoch(3))
259                )],
260                stored_records
261            );
262        }
263    }
264}