hiero_sdk/
transaction_record_query.rs1use hiero_sdk_proto::services;
4use hiero_sdk_proto::services::crypto_service_client::CryptoServiceClient;
5use hiero_sdk_proto::services::response::Response;
6use tonic::transport::Channel;
7
8use crate::ledger_id::RefLedgerId;
9use crate::query::{
10 AnyQueryData,
11 QueryExecute,
12 ToQueryProtobuf,
13};
14use crate::{
15 BoxGrpcFuture,
16 Error,
17 FromProtobuf,
18 Query,
19 Status,
20 ToProtobuf,
21 TransactionId,
22 TransactionRecord,
23 ValidateChecksums,
24};
25
26pub type TransactionRecordQuery = Query<TransactionRecordQueryData>;
29
30#[derive(Default, Clone, Debug)]
31pub struct TransactionRecordQueryData {
32 transaction_id: Option<TransactionId>,
33 include_children: bool,
34 include_duplicates: bool,
35 validate_status: bool,
36}
37
38impl From<TransactionRecordQueryData> for AnyQueryData {
39 #[inline]
40 fn from(data: TransactionRecordQueryData) -> Self {
41 Self::TransactionRecord(data)
42 }
43}
44
45impl TransactionRecordQuery {
46 #[must_use]
48 pub fn get_transaction_id(&self) -> Option<TransactionId> {
49 self.data.transaction_id
50 }
51
52 pub fn transaction_id(&mut self, transaction_id: TransactionId) -> &mut Self {
54 self.data.transaction_id = Some(transaction_id);
55 self
56 }
57
58 #[must_use]
61 pub fn get_include_children(&self) -> bool {
62 self.data.include_children
63 }
64
65 pub fn include_children(&mut self, include: bool) -> &mut Self {
68 self.data.include_children = include;
69 self
70 }
71
72 #[must_use]
74 pub fn get_include_duplicates(&self) -> bool {
75 self.data.include_duplicates
76 }
77
78 pub fn include_duplicates(&mut self, include: bool) -> &mut Self {
80 self.data.include_duplicates = include;
81 self
82 }
83
84 #[must_use]
86 pub fn get_validate_status(&self) -> bool {
87 self.data.validate_status
88 }
89
90 pub fn validate_status(&mut self, validate: bool) -> &mut Self {
92 self.data.validate_status = validate;
93 self
94 }
95}
96
97impl ToQueryProtobuf for TransactionRecordQueryData {
98 fn to_query_protobuf(&self, header: services::QueryHeader) -> services::Query {
99 let transaction_id = self.transaction_id.to_protobuf();
100
101 services::Query {
102 query: Some(services::query::Query::TransactionGetRecord(
103 services::TransactionGetRecordQuery {
104 header: Some(header),
105 transaction_id,
106 include_child_records: self.include_children,
107 include_duplicates: self.include_duplicates,
108 },
109 )),
110 }
111 }
112}
113
114impl QueryExecute for TransactionRecordQueryData {
115 type Response = TransactionRecord;
116
117 fn transaction_id(&self) -> Option<TransactionId> {
118 self.transaction_id
119 }
120
121 fn execute(
122 &self,
123 channel: Channel,
124 request: services::Query,
125 ) -> BoxGrpcFuture<'_, services::Response> {
126 Box::pin(async { CryptoServiceClient::new(channel).get_tx_record_by_tx_id(request).await })
127 }
128
129 fn should_retry_pre_check(&self, status: Status) -> bool {
130 matches!(status, Status::ReceiptNotFound | Status::RecordNotFound)
131 }
132
133 fn make_response(&self, response: Response) -> crate::Result<Self::Response> {
134 let record = TransactionRecord::from_protobuf(response)?;
135
136 if self.validate_status && record.receipt.status != Status::Success {
137 return Err(Error::ReceiptStatus {
138 transaction_id: self.transaction_id.map(Box::new),
139 status: record.receipt.status,
140 });
141 }
142
143 Ok(record)
144 }
145}
146
147impl ValidateChecksums for TransactionRecordQueryData {
148 fn validate_checksums(&self, ledger_id: &RefLedgerId) -> Result<(), Error> {
149 self.transaction_id.validate_checksums(ledger_id)
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use expect_test::expect;
156
157 use crate::query::ToQueryProtobuf;
158 use crate::transaction::test_helpers::TEST_TX_ID;
159 use crate::TransactionRecordQuery;
160
161 #[test]
162 fn serialize() {
163 expect![[r#"
164 Query {
165 query: Some(
166 TransactionGetRecord(
167 TransactionGetRecordQuery {
168 header: Some(
169 QueryHeader {
170 payment: None,
171 response_type: AnswerOnly,
172 },
173 ),
174 transaction_id: Some(
175 TransactionId {
176 transaction_valid_start: Some(
177 Timestamp {
178 seconds: 1554158542,
179 nanos: 0,
180 },
181 ),
182 account_id: Some(
183 AccountId {
184 shard_num: 0,
185 realm_num: 0,
186 account: Some(
187 AccountNum(
188 5006,
189 ),
190 ),
191 },
192 ),
193 scheduled: false,
194 nonce: 0,
195 },
196 ),
197 include_duplicates: true,
198 include_child_records: true,
199 },
200 ),
201 ),
202 }
203 "#]]
204 .assert_debug_eq(
205 &TransactionRecordQuery::new()
206 .transaction_id(TEST_TX_ID)
207 .include_children(true)
208 .include_duplicates(true)
209 .data
210 .to_query_protobuf(Default::default()),
211 )
212 }
213
214 #[test]
215 fn get_set_transaction_id() {
216 let mut query = TransactionRecordQuery::new();
217 query.transaction_id(TEST_TX_ID);
218
219 assert_eq!(query.get_transaction_id(), Some(TEST_TX_ID));
220 }
221
222 #[test]
224 fn get_set_include_children() {
225 let mut query = TransactionRecordQuery::new();
226 query.include_children(true);
227
228 assert_eq!(query.get_include_children(), true);
229 }
230
231 #[test]
232 fn get_set_include_duplicates() {
233 let mut query = TransactionRecordQuery::new();
234 query.include_duplicates(true);
235
236 assert_eq!(query.get_include_duplicates(), true);
237 }
238
239 #[test]
240 fn get_set_validate_status() {
241 let mut query = TransactionRecordQuery::new();
242 query.validate_status(true);
243
244 assert_eq!(query.get_validate_status(), true);
245 }
246}