mithril_aggregator/database/query/signed_entity/
get_signed_entity.rs1use 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
9pub 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}