mithril_persistence/database/query/cardano_transaction/
get_cardano_transaction.rs1use std::ops::Range;
2
3use sqlite::Value;
4
5use mithril_common::entities::{BlockNumber, BlockRange, SlotNumber, TransactionHash};
6
7use crate::database::record::CardanoTransactionRecord;
8use crate::sqlite::{Query, SourceAlias, SqLiteEntity, WhereCondition};
9
10pub struct GetCardanoTransactionQuery {
12 condition: WhereCondition,
13}
14
15impl GetCardanoTransactionQuery {
16 pub fn all() -> Self {
17 Self {
18 condition: WhereCondition::default(),
19 }
20 }
21
22 pub fn by_transaction_hash(transaction_hash: &TransactionHash) -> Self {
24 Self {
25 condition: WhereCondition::new(
26 "transaction_hash = ?*",
27 vec![Value::String(transaction_hash.to_owned())],
28 ),
29 }
30 }
31
32 pub fn by_transaction_hashes(
33 transactions_hashes: Vec<TransactionHash>,
34 up_to_or_equal: BlockNumber,
35 ) -> Self {
36 let hashes_values = transactions_hashes.into_iter().map(Value::String).collect();
37 let condition = WhereCondition::where_in("transaction_hash", hashes_values).and_where(
38 WhereCondition::new(
39 "block_number <= ?*",
40 vec![Value::Integer(*up_to_or_equal as i64)],
41 ),
42 );
43
44 Self { condition }
45 }
46
47 pub fn by_block_ranges(block_ranges: Vec<BlockRange>) -> Self {
48 let mut condition = WhereCondition::default();
49 for block_range in block_ranges {
50 condition = condition.or_where(WhereCondition::new(
51 "(block_number >= ?* and block_number < ?*)",
52 vec![
53 Value::Integer(*block_range.start as i64),
54 Value::Integer(*block_range.end as i64),
55 ],
56 ))
57 }
58
59 Self { condition }
60 }
61
62 pub fn between_blocks(range: Range<BlockNumber>) -> Self {
63 let condition = WhereCondition::new(
64 "block_number >= ?*",
65 vec![Value::Integer(*range.start as i64)],
66 )
67 .and_where(WhereCondition::new(
68 "block_number < ?*",
69 vec![Value::Integer(*range.end as i64)],
70 ));
71
72 Self { condition }
73 }
74
75 pub fn with_highest_block_number_below_slot_number(slot_number: SlotNumber) -> Self {
76 Self {
77 condition: WhereCondition::new(
78 "block_number = (select max(block_number) from cardano_tx where slot_number <= ?*)",
79 vec![Value::Integer(*slot_number as i64)],
80 ),
81 }
82 }
83
84 pub fn with_highest_block_number() -> Self {
85 Self {
86 condition: WhereCondition::new(
87 "block_number = (select max(block_number) from cardano_tx)",
88 vec![],
89 ),
90 }
91 }
92}
93
94impl Query for GetCardanoTransactionQuery {
95 type Entity = CardanoTransactionRecord;
96
97 fn filters(&self) -> WhereCondition {
98 self.condition.clone()
99 }
100
101 fn get_definition(&self, condition: &str) -> String {
102 let aliases = SourceAlias::new(&[("{:cardano_tx:}", "cardano_tx")]);
103 let projection = Self::Entity::get_projection().expand(aliases);
104
105 format!("select {projection} from cardano_tx where {condition} order by block_number, transaction_hash")
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use crate::database::query::InsertCardanoTransactionQuery;
112 use crate::database::test_helper::cardano_tx_db_connection;
113 use crate::sqlite::{ConnectionExtensions, SqliteConnection};
114
115 use super::*;
116
117 fn insert_transactions(connection: &SqliteConnection, records: Vec<CardanoTransactionRecord>) {
118 connection
119 .fetch_first(InsertCardanoTransactionQuery::insert_many(records).unwrap())
120 .unwrap();
121 }
122
123 fn transaction_record(
124 block_number: BlockNumber,
125 slot_number: SlotNumber,
126 ) -> CardanoTransactionRecord {
127 CardanoTransactionRecord::new(
128 format!("tx-hash-{}", slot_number),
129 block_number,
130 slot_number,
131 format!("block-hash-{}", block_number),
132 )
133 }
134
135 #[test]
136 fn with_highest_block_number() {
137 let connection = cardano_tx_db_connection().unwrap();
138
139 let cursor = connection
140 .fetch(GetCardanoTransactionQuery::with_highest_block_number())
141 .unwrap();
142 assert_eq!(0, cursor.count());
143
144 insert_transactions(
145 &connection,
146 vec![
147 transaction_record(BlockNumber(10), SlotNumber(50)),
148 transaction_record(BlockNumber(10), SlotNumber(51)),
149 transaction_record(BlockNumber(11), SlotNumber(54)),
150 transaction_record(BlockNumber(11), SlotNumber(55)),
151 ],
152 );
153
154 let records: Vec<CardanoTransactionRecord> = connection
155 .fetch_collect(GetCardanoTransactionQuery::with_highest_block_number())
156 .unwrap();
157 assert_eq!(
158 vec![
159 transaction_record(BlockNumber(11), SlotNumber(54)),
160 transaction_record(BlockNumber(11), SlotNumber(55)),
161 ],
162 records
163 );
164 }
165
166 #[test]
167 fn with_highest_block_number_below_slot_number() {
168 let connection = cardano_tx_db_connection().unwrap();
169
170 let cursor = connection
171 .fetch(
172 GetCardanoTransactionQuery::with_highest_block_number_below_slot_number(
173 SlotNumber(51),
174 ),
175 )
176 .unwrap();
177 assert_eq!(0, cursor.count());
178
179 insert_transactions(
180 &connection,
181 vec![transaction_record(BlockNumber(2), SlotNumber(5))],
182 );
183
184 let records: Vec<CardanoTransactionRecord> = connection
185 .fetch_collect(
186 GetCardanoTransactionQuery::with_highest_block_number_below_slot_number(
187 SlotNumber(5),
188 ),
189 )
190 .unwrap();
191 assert_eq!(
192 vec![transaction_record(BlockNumber(2), SlotNumber(5)),],
193 records
194 );
195
196 insert_transactions(
197 &connection,
198 vec![
199 transaction_record(BlockNumber(10), SlotNumber(50)),
200 transaction_record(BlockNumber(11), SlotNumber(51)),
201 transaction_record(BlockNumber(14), SlotNumber(54)),
202 transaction_record(BlockNumber(15), SlotNumber(55)),
203 ],
204 );
205
206 let records: Vec<CardanoTransactionRecord> = connection
207 .fetch_collect(
208 GetCardanoTransactionQuery::with_highest_block_number_below_slot_number(
209 SlotNumber(53),
210 ),
211 )
212 .unwrap();
213 assert_eq!(
214 vec![transaction_record(BlockNumber(11), SlotNumber(51)),],
215 records
216 );
217
218 let records: Vec<CardanoTransactionRecord> = connection
219 .fetch_collect(
220 GetCardanoTransactionQuery::with_highest_block_number_below_slot_number(
221 SlotNumber(54),
222 ),
223 )
224 .unwrap();
225 assert_eq!(
226 vec![transaction_record(BlockNumber(14), SlotNumber(54)),],
227 records
228 );
229 }
230}