mithril_aggregator/database/query/signed_entity/
get_signed_entity.rs

1use sqlite::Value;
2
3use mithril_common::StdResult;
4use mithril_common::entities::{Epoch, SignedEntityTypeDiscriminants};
5use mithril_persistence::sqlite::{Query, SourceAlias, SqLiteEntity, WhereCondition};
6
7use crate::database::record::SignedEntityRecord;
8
9/// Simple queries to retrieve [SignedEntityRecord] from the sqlite database.
10pub struct GetSignedEntityRecordQuery {
11    condition: WhereCondition,
12}
13
14impl GetSignedEntityRecordQuery {
15    #[cfg(test)]
16    pub fn all() -> Self {
17        Self {
18            condition: WhereCondition::default(),
19        }
20    }
21
22    pub fn by_signed_entity_id(signed_entity_id: &str) -> Self {
23        Self {
24            condition: WhereCondition::new(
25                "signed_entity_id = ?*",
26                vec![Value::String(signed_entity_id.to_owned())],
27            ),
28        }
29    }
30
31    pub fn by_certificate_id(certificate_id: &str) -> Self {
32        Self {
33            condition: WhereCondition::new(
34                "certificate_id = ?*",
35                vec![Value::String(certificate_id.to_owned())],
36            ),
37        }
38    }
39
40    pub fn by_certificates_ids(certificates_ids: &[&str]) -> Self {
41        let ids_values = certificates_ids
42            .iter()
43            .map(|id| Value::String(id.to_string()))
44            .collect();
45
46        Self {
47            condition: WhereCondition::where_in("certificate_id", ids_values),
48        }
49    }
50
51    pub fn by_signed_entity_type(
52        signed_entity_type: &SignedEntityTypeDiscriminants,
53    ) -> StdResult<Self> {
54        let signed_entity_type_id: i64 = signed_entity_type.index() as i64;
55
56        Ok(Self {
57            condition: WhereCondition::new(
58                "signed_entity_type_id = ?*",
59                vec![Value::Integer(signed_entity_type_id)],
60            ),
61        })
62    }
63
64    pub fn by_signed_entity_type_and_epoch(
65        signed_entity_type: &SignedEntityTypeDiscriminants,
66        epoch: Epoch,
67    ) -> Self {
68        let signed_entity_type_id = signed_entity_type.index() as i64;
69        let epoch = *epoch as i64;
70
71        Self {
72            condition: WhereCondition::new(
73                "signed_entity_type_id = ?* and epoch = ?*",
74                vec![Value::Integer(signed_entity_type_id), Value::Integer(epoch)],
75            ),
76        }
77    }
78}
79
80impl Query for GetSignedEntityRecordQuery {
81    type Entity = SignedEntityRecord;
82
83    fn filters(&self) -> WhereCondition {
84        self.condition.clone()
85    }
86
87    fn get_definition(&self, condition: &str) -> String {
88        let aliases = SourceAlias::new(&[("{:signed_entity:}", "se")]);
89        let projection = Self::Entity::get_projection().expand(aliases);
90        format!(
91            "select {projection} from signed_entity as se where {condition} order by ROWID desc"
92        )
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use mithril_common::entities::{BlockNumber, CardanoDbBeacon, SignedEntityType};
99    use mithril_persistence::sqlite::ConnectionExtensions;
100    use sqlite::ConnectionThreadSafe;
101
102    use crate::database::test_helper::{insert_signed_entities, main_db_connection};
103
104    use super::*;
105
106    fn create_database(records: &[SignedEntityRecord]) -> ConnectionThreadSafe {
107        let connection = main_db_connection().unwrap();
108        insert_signed_entities(&connection, records.to_vec()).unwrap();
109
110        connection
111    }
112
113    #[test]
114    fn by_signed_entity_and_epoch_returns_records_filtered_by_epoch() {
115        let records = vec![
116            SignedEntityRecord::fake_with_signed_entity(
117                SignedEntityType::CardanoStakeDistribution(Epoch(3)),
118            ),
119            SignedEntityRecord::fake_with_signed_entity(
120                SignedEntityType::CardanoStakeDistribution(Epoch(4)),
121            ),
122            SignedEntityRecord::fake_with_signed_entity(
123                SignedEntityType::CardanoStakeDistribution(Epoch(5)),
124            ),
125        ];
126
127        let connection = create_database(&records);
128
129        let records_retrieved: Vec<SignedEntityRecord> = connection
130            .fetch_collect(GetSignedEntityRecordQuery::by_signed_entity_type_and_epoch(
131                &SignedEntityTypeDiscriminants::CardanoStakeDistribution,
132                Epoch(4),
133            ))
134            .unwrap();
135
136        assert_eq!(vec![records[1].clone()], records_retrieved);
137    }
138
139    #[test]
140    fn by_signed_entity_and_epoch_returns_records_filtered_by_discriminant() {
141        let records = vec![
142            SignedEntityRecord::fake_with_signed_entity(
143                SignedEntityType::CardanoStakeDistribution(Epoch(3)),
144            ),
145            SignedEntityRecord::fake_with_signed_entity(
146                SignedEntityType::MithrilStakeDistribution(Epoch(3)),
147            ),
148            SignedEntityRecord::fake_with_signed_entity(SignedEntityType::CardanoDatabase(
149                CardanoDbBeacon::new(3, 98),
150            )),
151        ];
152
153        let connection = create_database(&records);
154
155        let fetched_msd_records: Vec<SignedEntityRecord> = connection
156            .fetch_collect(GetSignedEntityRecordQuery::by_signed_entity_type_and_epoch(
157                &SignedEntityTypeDiscriminants::MithrilStakeDistribution,
158                Epoch(3),
159            ))
160            .unwrap();
161        assert_eq!(vec![records[1].clone()], fetched_msd_records);
162
163        let fetched_cdb_records: Vec<SignedEntityRecord> = connection
164            .fetch_collect(GetSignedEntityRecordQuery::by_signed_entity_type_and_epoch(
165                &SignedEntityTypeDiscriminants::CardanoDatabase,
166                Epoch(3),
167            ))
168            .unwrap();
169        assert_eq!(vec![records[2].clone()], fetched_cdb_records);
170    }
171
172    #[test]
173    fn test_get_record_by_id() {
174        let signed_entity_records = vec![
175            SignedEntityRecord::fake_with_signed_entity(
176                SignedEntityType::CardanoStakeDistribution(Epoch(3)),
177            ),
178            SignedEntityRecord::fake_with_signed_entity(SignedEntityType::CardanoTransactions(
179                Epoch(4),
180                BlockNumber(5),
181            )),
182        ];
183
184        let connection = main_db_connection().unwrap();
185        insert_signed_entities(&connection, signed_entity_records.clone()).unwrap();
186
187        let first_signed_entity_type = signed_entity_records[0].clone();
188        let fetched_record = connection
189            .fetch_first(GetSignedEntityRecordQuery::by_signed_entity_id(
190                &first_signed_entity_type.signed_entity_id,
191            ))
192            .unwrap();
193        assert_eq!(Some(first_signed_entity_type), fetched_record);
194    }
195
196    #[test]
197    fn test_get_record_by_signed_entity_type() {
198        let signed_entity_records = vec![
199            SignedEntityRecord::fake_with_signed_entity(
200                SignedEntityType::MithrilStakeDistribution(Epoch(2)),
201            ),
202            SignedEntityRecord::fake_with_signed_entity(SignedEntityType::CardanoTransactions(
203                Epoch(4),
204                BlockNumber(5),
205            )),
206            SignedEntityRecord::fake_with_signed_entity(SignedEntityType::CardanoTransactions(
207                Epoch(5),
208                BlockNumber(9),
209            )),
210        ];
211
212        let connection = main_db_connection().unwrap();
213        insert_signed_entities(&connection, signed_entity_records.clone()).unwrap();
214
215        let fetched_tx_records: Vec<SignedEntityRecord> = connection
216            .fetch_collect(
217                GetSignedEntityRecordQuery::by_signed_entity_type(
218                    &SignedEntityTypeDiscriminants::CardanoTransactions,
219                )
220                .unwrap(),
221            )
222            .unwrap();
223        let expected_tx_records: Vec<SignedEntityRecord> =
224            vec![signed_entity_records[2].clone(), signed_entity_records[1].clone()];
225        assert_eq!(expected_tx_records, fetched_tx_records);
226    }
227
228    #[test]
229    fn test_get_all_records() {
230        let signed_entity_records = SignedEntityRecord::fake_records(5);
231
232        let connection = main_db_connection().unwrap();
233        insert_signed_entities(&connection, signed_entity_records.clone()).unwrap();
234
235        let fetched_records: Vec<SignedEntityRecord> =
236            connection.fetch_collect(GetSignedEntityRecordQuery::all()).unwrap();
237        let expected_signed_entity_records: Vec<_> =
238            signed_entity_records.into_iter().rev().collect();
239        assert_eq!(expected_signed_entity_records, fetched_records);
240    }
241}