1use serde::{Deserialize, Serialize};
5
6use crate::client::Client;
7use crate::error::Error;
8use crate::models::transaction::{Transaction, TransactionFilter};
9use crate::models::{AccountId, DateTime, TransactionId};
10use crate::streaming::{
11 StreamConfig, StreamKind, TransactionKind, TransactionStream, stream_config_setters,
12};
13
14impl Client {
15 pub fn list_transactions(&self, account_id: impl Into<AccountId>) -> ListTransactionsRequest {
22 ListTransactionsRequest {
23 client: self.clone(),
24 account_id: account_id.into(),
25 params: Vec::new(),
26 }
27 }
28
29 pub async fn transaction(
33 &self,
34 account_id: impl Into<AccountId>,
35 transaction_id: impl Into<TransactionId>,
36 ) -> Result<TransactionResponse, Error> {
37 let account_id = account_id.into();
38 let transaction_id = transaction_id.into();
39 self.execute(self.get(&[
40 "accounts",
41 account_id.as_str(),
42 "transactions",
43 transaction_id.as_str(),
44 ]))
45 .await
46 }
47
48 pub fn transactions_id_range(
53 &self,
54 account_id: impl Into<AccountId>,
55 from: impl Into<TransactionId>,
56 to: impl Into<TransactionId>,
57 ) -> TransactionsIdRangeRequest {
58 TransactionsIdRangeRequest {
59 client: self.clone(),
60 account_id: account_id.into(),
61 from: from.into(),
62 to: to.into(),
63 types: None,
64 }
65 }
66
67 pub fn transaction_stream(&self, account_id: impl Into<AccountId>) -> TransactionStreamRequest {
103 TransactionStreamRequest {
104 client: self.clone(),
105 account_id: account_id.into(),
106 config: StreamConfig::default(),
107 }
108 }
109
110 pub async fn transactions_since_id(
118 &self,
119 account_id: impl Into<AccountId>,
120 id: impl Into<TransactionId>,
121 ) -> Result<TransactionsResponse, Error> {
122 let account_id = account_id.into();
123 let id = id.into();
124 let request = self
125 .get(&["accounts", account_id.as_str(), "transactions", "sinceid"])
126 .query(&[("id", id.as_str())]);
127 self.execute(request).await
128 }
129}
130
131#[derive(Debug)]
133pub struct TransactionStreamRequest {
134 client: Client,
135 account_id: AccountId,
136 config: StreamConfig,
137}
138
139impl TransactionStreamRequest {
140 stream_config_setters!();
141
142 pub async fn send(self) -> Result<TransactionStream, Error> {
145 let mut kind = TransactionKind {
146 client: self.client,
147 account_id: self.account_id,
148 last_seen: None,
149 };
150 let initial = kind.connect(false).await?;
151 Ok(TransactionStream::new(kind, self.config, initial))
152 }
153}
154
155#[derive(Debug)]
157pub struct ListTransactionsRequest {
158 client: Client,
159 account_id: AccountId,
160 params: Vec<(&'static str, String)>,
161}
162
163impl ListTransactionsRequest {
164 pub fn from(mut self, from: impl Into<DateTime>) -> Self {
167 self.params.push(("from", from.into().0));
168 self
169 }
170
171 pub fn to(mut self, to: impl Into<DateTime>) -> Self {
174 self.params.push(("to", to.into().0));
175 self
176 }
177
178 pub fn page_size(mut self, page_size: u32) -> Self {
181 self.params.push(("pageSize", page_size.to_string()));
182 self
183 }
184
185 pub fn types<I>(mut self, types: I) -> Self
187 where
188 I: IntoIterator<Item = TransactionFilter>,
189 {
190 let joined = types
191 .into_iter()
192 .map(|t| t.as_str().to_owned())
193 .collect::<Vec<_>>()
194 .join(",");
195 self.params.push(("type", joined));
196 self
197 }
198
199 pub async fn send(self) -> Result<ListTransactionsResponse, Error> {
201 let request = self
202 .client
203 .get(&["accounts", self.account_id.as_str(), "transactions"])
204 .query(&self.params);
205 self.client.execute(request).await
206 }
207}
208
209#[derive(Debug, Clone, Serialize, Deserialize)]
211#[non_exhaustive]
212pub struct ListTransactionsResponse {
213 #[serde(rename = "from", skip_serializing_if = "Option::is_none")]
215 pub from: Option<DateTime>,
216 #[serde(rename = "to", skip_serializing_if = "Option::is_none")]
218 pub to: Option<DateTime>,
219 #[serde(rename = "pageSize", skip_serializing_if = "Option::is_none")]
221 pub page_size: Option<i64>,
222 #[serde(rename = "type", default, skip_serializing_if = "Vec::is_empty")]
224 pub r#type: Vec<TransactionFilter>,
225 #[serde(rename = "count", skip_serializing_if = "Option::is_none")]
227 pub count: Option<i64>,
228 #[serde(rename = "pages", default, skip_serializing_if = "Vec::is_empty")]
231 pub pages: Vec<String>,
232 #[serde(rename = "lastTransactionID", skip_serializing_if = "Option::is_none")]
234 pub last_transaction_id: Option<TransactionId>,
235}
236
237#[derive(Debug, Clone, Serialize, Deserialize)]
239#[non_exhaustive]
240pub struct TransactionResponse {
241 #[serde(rename = "transaction")]
243 pub transaction: Transaction,
244 #[serde(rename = "lastTransactionID", skip_serializing_if = "Option::is_none")]
246 pub last_transaction_id: Option<TransactionId>,
247}
248
249#[derive(Debug)]
251pub struct TransactionsIdRangeRequest {
252 client: Client,
253 account_id: AccountId,
254 from: TransactionId,
255 to: TransactionId,
256 types: Option<Vec<TransactionFilter>>,
257}
258
259impl TransactionsIdRangeRequest {
260 pub fn types<I>(mut self, types: I) -> Self
262 where
263 I: IntoIterator<Item = TransactionFilter>,
264 {
265 self.types = Some(types.into_iter().collect());
266 self
267 }
268
269 pub async fn send(self) -> Result<TransactionsResponse, Error> {
271 let mut request = self
272 .client
273 .get(&[
274 "accounts",
275 self.account_id.as_str(),
276 "transactions",
277 "idrange",
278 ])
279 .query(&[("from", self.from.as_str()), ("to", self.to.as_str())]);
280 if let Some(types) = &self.types {
281 let joined = types
282 .iter()
283 .map(|t| t.as_str().to_owned())
284 .collect::<Vec<_>>()
285 .join(",");
286 request = request.query(&[("type", joined)]);
287 }
288 self.client.execute(request).await
289 }
290}
291
292#[derive(Debug, Clone, Serialize, Deserialize)]
295#[non_exhaustive]
296pub struct TransactionsResponse {
297 #[serde(
299 rename = "transactions",
300 default,
301 skip_serializing_if = "Vec::is_empty"
302 )]
303 pub transactions: Vec<Transaction>,
304 #[serde(rename = "lastTransactionID", skip_serializing_if = "Option::is_none")]
306 pub last_transaction_id: Option<TransactionId>,
307}