mithril_aggregator/database/query/signed_entity/
get_signed_entity.rs

1use sqlite::Value;
2
3use mithril_common::entities::{Epoch, SignedEntityTypeDiscriminants};
4use mithril_common::StdResult;
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 cardano_stake_distribution_by_epoch(epoch: Epoch) -> Self {
65        let signed_entity_type_id =
66            SignedEntityTypeDiscriminants::CardanoStakeDistribution.index() as i64;
67        let epoch = *epoch as i64;
68
69        Self {
70            condition: WhereCondition::new(
71                "signed_entity_type_id = ?* and beacon = ?*",
72                vec![Value::Integer(signed_entity_type_id), Value::Integer(epoch)],
73            ),
74        }
75    }
76}
77
78impl Query for GetSignedEntityRecordQuery {
79    type Entity = SignedEntityRecord;
80
81    fn filters(&self) -> WhereCondition {
82        self.condition.clone()
83    }
84
85    fn get_definition(&self, condition: &str) -> String {
86        let aliases = SourceAlias::new(&[("{:signed_entity:}", "se")]);
87        let projection = Self::Entity::get_projection().expand(aliases);
88        format!(
89            "select {projection} from signed_entity as se where {condition} order by ROWID desc"
90        )
91    }
92}
93
94#[cfg(test)]
95mod tests {
96    use chrono::DateTime;
97    use mithril_common::{
98        entities::{CardanoDbBeacon, SignedEntityType},
99        test_utils::fake_data,
100    };
101    use mithril_persistence::sqlite::ConnectionExtensions;
102    use sqlite::ConnectionThreadSafe;
103
104    use crate::database::test_helper::{insert_signed_entities, main_db_connection};
105
106    use super::*;
107
108    fn create_database_with_cardano_stake_distributions<T: Into<SignedEntityRecord>>(
109        cardano_stake_distributions: Vec<T>,
110    ) -> (ConnectionThreadSafe, Vec<SignedEntityRecord>) {
111        let records = cardano_stake_distributions
112            .into_iter()
113            .map(|cardano_stake_distribution| cardano_stake_distribution.into())
114            .collect::<Vec<_>>();
115
116        let connection = create_database(&records);
117
118        (connection, records)
119    }
120
121    fn create_database(records: &[SignedEntityRecord]) -> ConnectionThreadSafe {
122        let connection = main_db_connection().unwrap();
123        insert_signed_entities(&connection, records.to_vec()).unwrap();
124        connection
125    }
126
127    #[test]
128    fn cardano_stake_distribution_by_epoch_returns_records_filtered_by_epoch() {
129        let mut cardano_stake_distributions = fake_data::cardano_stake_distributions(3);
130        cardano_stake_distributions[0].epoch = Epoch(3);
131        cardano_stake_distributions[1].epoch = Epoch(4);
132        cardano_stake_distributions[2].epoch = Epoch(5);
133
134        let (connection, records) =
135            create_database_with_cardano_stake_distributions(cardano_stake_distributions);
136
137        let records_retrieved: Vec<SignedEntityRecord> = connection
138            .fetch_collect(
139                GetSignedEntityRecordQuery::cardano_stake_distribution_by_epoch(Epoch(4)),
140            )
141            .unwrap();
142
143        assert_eq!(vec![records[1].clone()], records_retrieved);
144    }
145
146    #[test]
147    fn cardano_stake_distribution_by_epoch_returns_records_returns_only_cardano_stake_distribution_records(
148    ) {
149        let cardano_stake_distributions_record: SignedEntityRecord = {
150            let mut cardano_stake_distribution = fake_data::cardano_stake_distribution(Epoch(4));
151            cardano_stake_distribution.hash = "hash-123".to_string();
152            cardano_stake_distribution.into()
153        };
154
155        let snapshots_record = {
156            let mut snapshot = fake_data::snapshots(1)[0].clone();
157            snapshot.beacon.epoch = Epoch(4);
158            SignedEntityRecord::from_snapshot(snapshot, "whatever".to_string(), DateTime::default())
159        };
160
161        let mithril_stake_distribution_record: SignedEntityRecord = {
162            let mithril_stake_distributions = fake_data::mithril_stake_distributions(1);
163            let mut mithril_stake_distribution = mithril_stake_distributions[0].clone();
164            mithril_stake_distribution.epoch = Epoch(4);
165            mithril_stake_distribution.into()
166        };
167
168        let connection = create_database(&[
169            cardano_stake_distributions_record.clone(),
170            snapshots_record,
171            mithril_stake_distribution_record,
172        ]);
173
174        let records_retrieved: Vec<SignedEntityRecord> = connection
175            .fetch_collect(
176                GetSignedEntityRecordQuery::cardano_stake_distribution_by_epoch(Epoch(4)),
177            )
178            .unwrap();
179
180        assert_eq!(
181            vec![cardano_stake_distributions_record.clone()],
182            records_retrieved,
183        );
184    }
185
186    #[test]
187    fn test_get_signed_entity_records() {
188        let signed_entity_records = SignedEntityRecord::fake_records(5);
189
190        let connection = main_db_connection().unwrap();
191        insert_signed_entities(&connection, signed_entity_records.clone()).unwrap();
192
193        let first_signed_entity_type = signed_entity_records.first().unwrap().to_owned();
194        let signed_entity_records: Vec<SignedEntityRecord> = connection
195            .fetch_collect(GetSignedEntityRecordQuery::by_signed_entity_id(
196                &first_signed_entity_type.signed_entity_id,
197            ))
198            .unwrap();
199        assert_eq!(vec![first_signed_entity_type], signed_entity_records);
200
201        let signed_entity_records: Vec<SignedEntityRecord> = connection
202            .fetch_collect(
203                GetSignedEntityRecordQuery::by_signed_entity_type(
204                    &SignedEntityTypeDiscriminants::CardanoImmutableFilesFull,
205                )
206                .unwrap(),
207            )
208            .unwrap();
209        let expected_signed_entity_records: Vec<SignedEntityRecord> = signed_entity_records
210            .iter()
211            .filter_map(|se| {
212                (se.signed_entity_type.index()
213                    == SignedEntityType::CardanoImmutableFilesFull(CardanoDbBeacon::default())
214                        .index())
215                .then_some(se.to_owned())
216            })
217            .collect();
218        assert_eq!(expected_signed_entity_records, signed_entity_records);
219
220        let signed_entity_records: Vec<SignedEntityRecord> = connection
221            .fetch_collect(GetSignedEntityRecordQuery::all())
222            .unwrap();
223        let expected_signed_entity_records: Vec<SignedEntityRecord> =
224            signed_entity_records.iter().map(|c| c.to_owned()).collect();
225        assert_eq!(expected_signed_entity_records, signed_entity_records);
226    }
227}