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!(
106 "select {projection} from cardano_tx where {condition} order by block_number, transaction_hash"
107 )
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use crate::database::query::InsertCardanoTransactionQuery;
114 use crate::database::test_helper::cardano_tx_db_connection;
115 use crate::sqlite::{ConnectionExtensions, SqliteConnection};
116
117 use super::*;
118
119 fn insert_transactions(connection: &SqliteConnection, records: Vec<CardanoTransactionRecord>) {
120 connection
121 .fetch_first(InsertCardanoTransactionQuery::insert_many(records).unwrap())
122 .unwrap();
123 }
124
125 fn transaction_record(
126 block_number: BlockNumber,
127 slot_number: SlotNumber,
128 ) -> CardanoTransactionRecord {
129 CardanoTransactionRecord::new(
130 format!("tx-hash-{slot_number}"),
131 block_number,
132 slot_number,
133 format!("block-hash-{block_number}"),
134 )
135 }
136
137 #[test]
138 fn with_highest_block_number() {
139 let connection = cardano_tx_db_connection().unwrap();
140
141 let cursor = connection
142 .fetch(GetCardanoTransactionQuery::with_highest_block_number())
143 .unwrap();
144 assert_eq!(0, cursor.count());
145
146 insert_transactions(
147 &connection,
148 vec![
149 transaction_record(BlockNumber(10), SlotNumber(50)),
150 transaction_record(BlockNumber(10), SlotNumber(51)),
151 transaction_record(BlockNumber(11), SlotNumber(54)),
152 transaction_record(BlockNumber(11), SlotNumber(55)),
153 ],
154 );
155
156 let records: Vec<CardanoTransactionRecord> = connection
157 .fetch_collect(GetCardanoTransactionQuery::with_highest_block_number())
158 .unwrap();
159 assert_eq!(
160 vec![
161 transaction_record(BlockNumber(11), SlotNumber(54)),
162 transaction_record(BlockNumber(11), SlotNumber(55)),
163 ],
164 records
165 );
166 }
167
168 #[test]
169 fn with_highest_block_number_below_slot_number() {
170 let connection = cardano_tx_db_connection().unwrap();
171
172 let cursor = connection
173 .fetch(
174 GetCardanoTransactionQuery::with_highest_block_number_below_slot_number(
175 SlotNumber(51),
176 ),
177 )
178 .unwrap();
179 assert_eq!(0, cursor.count());
180
181 insert_transactions(
182 &connection,
183 vec![transaction_record(BlockNumber(2), SlotNumber(5))],
184 );
185
186 let records: Vec<CardanoTransactionRecord> = connection
187 .fetch_collect(
188 GetCardanoTransactionQuery::with_highest_block_number_below_slot_number(
189 SlotNumber(5),
190 ),
191 )
192 .unwrap();
193 assert_eq!(
194 vec![transaction_record(BlockNumber(2), SlotNumber(5)),],
195 records
196 );
197
198 insert_transactions(
199 &connection,
200 vec![
201 transaction_record(BlockNumber(10), SlotNumber(50)),
202 transaction_record(BlockNumber(11), SlotNumber(51)),
203 transaction_record(BlockNumber(14), SlotNumber(54)),
204 transaction_record(BlockNumber(15), SlotNumber(55)),
205 ],
206 );
207
208 let records: Vec<CardanoTransactionRecord> = connection
209 .fetch_collect(
210 GetCardanoTransactionQuery::with_highest_block_number_below_slot_number(
211 SlotNumber(53),
212 ),
213 )
214 .unwrap();
215 assert_eq!(
216 vec![transaction_record(BlockNumber(11), SlotNumber(51)),],
217 records
218 );
219
220 let records: Vec<CardanoTransactionRecord> = connection
221 .fetch_collect(
222 GetCardanoTransactionQuery::with_highest_block_number_below_slot_number(
223 SlotNumber(54),
224 ),
225 )
226 .unwrap();
227 assert_eq!(
228 vec![transaction_record(BlockNumber(14), SlotNumber(54)),],
229 records
230 );
231 }
232}