1use crate::person::{NamedPerson, PersonId};
2use crate::team::{TeamId};
3use crate::types::{Copyright, NaiveDateRange, MLB_API_DATE_FORMAT};
4use crate::request::RequestURL;
5use bon::Builder;
6use chrono::NaiveDate;
7use itertools::Itertools;
8use serde::{Deserialize, Deserializer};
9use std::fmt::{Display, Formatter};
10use std::ops::{Deref, DerefMut};
11use crate::sport::SportId;
12use crate::team::NamedTeam;
13
14#[derive(Debug, Deserialize, PartialEq, Eq, Clone)]
15#[serde(rename_all = "camelCase")]
16pub struct TransactionsResponse {
17 pub copyright: Copyright,
18 pub transactions: Vec<Transaction>,
19}
20
21#[derive(Debug, Deserialize, PartialEq, Eq, Clone)]
22#[serde(rename_all = "camelCase")]
23pub struct TransactionCommon {
24 pub id: TransactionId,
25 #[serde(default)]
26 pub description: String,
27 #[serde(flatten)]
28 pub dates: TransactionDates,
29}
30
31#[derive(Debug, Deserialize, PartialEq, Eq, Clone)]
32#[serde(rename_all = "camelCase")]
33pub struct TransactionDates {
34 pub date: NaiveDate,
35 pub effective_date: Option<NaiveDate>,
36 pub resolution_date: Option<NaiveDate>,
37}
38
39#[derive(Debug, Deserialize, PartialEq, Eq, Clone)]
41#[serde(tag = "typeCode")]
42pub enum Transaction {
43 #[serde(rename = "ASG", rename_all = "camelCase")]
44 Assigned {
45 #[serde(flatten)]
46 common: TransactionCommon,
47 #[serde(deserialize_with = "deserialize_named_person")]
48 #[serde(default = "NamedPerson::unknown_person")]
49 person: NamedPerson,
50 #[serde(rename = "fromTeam")]
51 #[serde(deserialize_with = "deserialize_named_team_opt")]
52 #[serde(default)]
53 source_team: Option<NamedTeam>,
54 #[serde(default = "NamedTeam::unknown_team")]
55 #[serde(rename = "toTeam")]
56 #[serde(deserialize_with = "deserialize_named_team")]
57 destination_team: NamedTeam,
58 },
59 #[serde(rename = "SC", rename_all = "camelCase")]
60 StatusChange {
61 #[serde(flatten)]
62 common: TransactionCommon,
63 #[serde(deserialize_with = "deserialize_named_person")]
64 #[serde(default = "NamedPerson::unknown_person")]
65 person: NamedPerson,
66 #[serde(default = "NamedTeam::unknown_team")]
67 #[serde(rename = "toTeam")]
68 #[serde(deserialize_with = "deserialize_named_team")]
69 team: NamedTeam,
70 },
71 #[serde(rename = "SFA", rename_all = "camelCase")]
72 SignedAsFreeAgent {
73 #[serde(flatten)]
74 common: TransactionCommon,
75 #[serde(deserialize_with = "deserialize_named_person")]
76 #[serde(default = "NamedPerson::unknown_person")]
77 person: NamedPerson,
78 #[serde(default = "NamedTeam::unknown_team")]
79 #[serde(rename = "toTeam")]
80 #[serde(deserialize_with = "deserialize_named_team")]
81 team: NamedTeam,
82 },
83 #[serde(rename = "DES", rename_all = "camelCase")]
84 DesignatedForAssignment {
85 #[serde(flatten)]
86 common: TransactionCommon,
87 #[serde(deserialize_with = "deserialize_named_person")]
88 #[serde(default = "NamedPerson::unknown_person")]
89 person: NamedPerson,
90 #[serde(default = "NamedTeam::unknown_team")]
91 #[serde(rename = "toTeam")]
92 #[serde(deserialize_with = "deserialize_named_team")]
93 team: NamedTeam,
94 },
95 #[serde(rename = "TR", rename_all = "camelCase")]
96 Trade {
97 #[serde(flatten)]
98 common: TransactionCommon,
99 #[serde(deserialize_with = "deserialize_named_person_opt")]
101 #[serde(default)]
102 person: Option<NamedPerson>,
103 #[serde(default = "NamedTeam::unknown_team")]
104 #[serde(rename = "fromTeam")]
105 #[serde(deserialize_with = "deserialize_named_team")]
106 source_team: NamedTeam,
107 #[serde(default = "NamedTeam::unknown_team")]
108 #[serde(rename = "toTeam")]
109 #[serde(deserialize_with = "deserialize_named_team")]
110 destination_team: NamedTeam,
111 },
112 #[serde(rename = "NUM", rename_all = "camelCase")]
113 NumberChange {
114 #[serde(flatten)]
115 common: TransactionCommon,
116 #[serde(deserialize_with = "deserialize_named_person")]
117 #[serde(default = "NamedPerson::unknown_person")]
118 person: NamedPerson,
119 #[serde(default = "NamedTeam::unknown_team")]
120 #[serde(rename = "toTeam")]
121 #[serde(deserialize_with = "deserialize_named_team")]
122 team: NamedTeam,
123 },
124 #[serde(rename = "OUT", rename_all = "camelCase")]
125 Outrighted {
126 #[serde(flatten)]
127 common: TransactionCommon,
128 #[serde(deserialize_with = "deserialize_named_person")]
129 #[serde(default = "NamedPerson::unknown_person")]
130 person: NamedPerson,
131 #[serde(default = "NamedTeam::unknown_team")]
132 #[serde(rename = "fromTeam")]
133 #[serde(deserialize_with = "deserialize_named_team")]
134 source_team: NamedTeam,
135 #[serde(default = "NamedTeam::unknown_team")]
136 #[serde(rename = "toTeam")]
137 #[serde(deserialize_with = "deserialize_named_team")]
138 destination_team: NamedTeam,
139 },
140 #[serde(rename = "CLW", rename_all = "camelCase")]
141 ClaimedOffWaivers {
142 #[serde(flatten)]
143 common: TransactionCommon,
144 #[serde(deserialize_with = "deserialize_named_person")]
145 #[serde(default = "NamedPerson::unknown_person")]
146 person: NamedPerson,
147 #[serde(default = "NamedTeam::unknown_team")]
148 #[serde(rename = "fromTeam")]
149 #[serde(deserialize_with = "deserialize_named_team")]
150 source_team: NamedTeam,
151 #[serde(default = "NamedTeam::unknown_team")]
152 #[serde(rename = "toTeam")]
153 #[serde(deserialize_with = "deserialize_named_team")]
154 destination_team: NamedTeam,
155 },
156 #[serde(rename = "SGN", rename_all = "camelCase")]
157 Signed {
158 #[serde(flatten)]
159 common: TransactionCommon,
160 #[serde(deserialize_with = "deserialize_named_person")]
161 #[serde(default = "NamedPerson::unknown_person")]
162 person: NamedPerson,
163 #[serde(rename = "toTeam")]
164 #[serde(deserialize_with = "deserialize_named_team")]
165 team: NamedTeam,
166 },
167 #[serde(rename = "REL", rename_all = "camelCase")]
168 Released {
169 #[serde(flatten)]
170 common: TransactionCommon,
171 #[serde(deserialize_with = "deserialize_named_person")]
172 #[serde(default = "NamedPerson::unknown_person")]
173 person: NamedPerson,
174 #[serde(default = "NamedTeam::unknown_team")]
175 #[serde(rename = "toTeam")]
176 #[serde(deserialize_with = "deserialize_named_team")]
177 team: NamedTeam,
178 },
179 #[serde(rename = "DFA", rename_all = "camelCase")]
180 DeclaredFreeAgency {
181 #[serde(flatten)]
182 common: TransactionCommon,
183 #[serde(deserialize_with = "deserialize_named_person")]
184 #[serde(default = "NamedPerson::unknown_person")]
185 person: NamedPerson,
186 #[serde(default = "NamedTeam::unknown_team")]
187 #[serde(rename = "toTeam")]
188 #[serde(deserialize_with = "deserialize_named_team")]
189 source_team: NamedTeam,
190 },
191 #[serde(rename = "OPT", rename_all = "camelCase")]
192 Optioned {
193 #[serde(flatten)]
194 common: TransactionCommon,
195 #[serde(deserialize_with = "deserialize_named_person")]
196 #[serde(default = "NamedPerson::unknown_person")]
197 person: NamedPerson,
198 #[serde(default = "NamedTeam::unknown_team")]
199 #[serde(rename = "fromTeam")]
200 #[serde(deserialize_with = "deserialize_named_team")]
201 source_team: NamedTeam,
202 #[serde(default = "NamedTeam::unknown_team")]
203 #[serde(rename = "toTeam")]
204 #[serde(deserialize_with = "deserialize_named_team")]
205 destination_team: NamedTeam,
206 },
207 #[serde(rename = "RTN", rename_all = "camelCase")]
208 Returned {
209 #[serde(flatten)]
210 common: TransactionCommon,
211 #[serde(deserialize_with = "deserialize_named_person")]
212 #[serde(default = "NamedPerson::unknown_person")]
213 person: NamedPerson,
214 #[serde(default = "NamedTeam::unknown_team")]
215 #[serde(rename = "fromTeam")]
216 #[serde(deserialize_with = "deserialize_named_team")]
217 source_team: NamedTeam,
218 #[serde(default = "NamedTeam::unknown_team")]
219 #[serde(rename = "toTeam")]
220 #[serde(deserialize_with = "deserialize_named_team")]
221 destination_team: NamedTeam,
222 },
223 #[serde(rename = "SE", rename_all = "camelCase")]
224 Selected {
225 #[serde(flatten)]
226 common: TransactionCommon,
227 #[serde(deserialize_with = "deserialize_named_person")]
228 #[serde(default = "NamedPerson::unknown_person")]
229 person: NamedPerson,
230 #[serde(rename = "fromTeam")]
231 #[serde(deserialize_with = "deserialize_named_team_opt")]
232 #[serde(default)]
233 source_team: Option<NamedTeam>,
234 #[serde(default = "NamedTeam::unknown_team")]
235 #[serde(rename = "toTeam")]
236 #[serde(deserialize_with = "deserialize_named_team")]
237 destination_team: NamedTeam,
238 },
239 #[serde(rename = "CU", rename_all = "camelCase")]
240 Recalled {
241 #[serde(flatten)]
242 common: TransactionCommon,
243 #[serde(deserialize_with = "deserialize_named_person")]
244 #[serde(default = "NamedPerson::unknown_person")]
245 person: NamedPerson,
246 #[serde(rename = "fromTeam")]
247 #[serde(deserialize_with = "deserialize_named_team_opt")]
248 #[serde(default)]
249 source_team: Option<NamedTeam>,
250 #[serde(default = "NamedTeam::unknown_team")]
251 #[serde(rename = "toTeam")]
252 #[serde(deserialize_with = "deserialize_named_team")]
253 destination_team: NamedTeam,
254 },
255 #[serde(rename = "SU", rename_all = "camelCase")]
256 Suspension {
257 #[serde(flatten)]
258 common: TransactionCommon,
259 #[serde(deserialize_with = "deserialize_named_person")]
260 #[serde(default = "NamedPerson::unknown_person")]
261 person: NamedPerson,
262 #[serde(default = "NamedTeam::unknown_team")]
263 #[serde(rename = "toTeam")]
264 #[serde(deserialize_with = "deserialize_named_team")]
265 team: NamedTeam,
266 },
267 #[serde(rename = "RET", rename_all = "camelCase")]
268 Retired {
269 #[serde(flatten)]
270 common: TransactionCommon,
271 #[serde(deserialize_with = "deserialize_named_person")]
272 #[serde(default = "NamedPerson::unknown_person")]
273 person: NamedPerson,
274 #[serde(default = "NamedTeam::unknown_team")]
275 #[serde(rename = "toTeam")]
276 #[serde(deserialize_with = "deserialize_named_team")]
277 team: NamedTeam,
278 },
279 #[serde(rename = "PUR", rename_all = "camelCase")]
280 Purchase {
281 #[serde(flatten)]
282 common: TransactionCommon,
283 #[serde(deserialize_with = "deserialize_named_person")]
284 #[serde(default = "NamedPerson::unknown_person")]
285 person: NamedPerson,
286 #[serde(rename = "fromTeam")]
287 #[serde(deserialize_with = "deserialize_named_team_opt")]
288 #[serde(default)]
289 source_team: Option<NamedTeam>,
290 #[serde(default = "NamedTeam::unknown_team")]
291 #[serde(rename = "toTeam")]
292 #[serde(deserialize_with = "deserialize_named_team")]
293 destination_team: NamedTeam,
294 },
295 #[serde(rename = "R5", rename_all = "camelCase")]
296 RuleFiveDraft {
297 #[serde(flatten)]
298 common: TransactionCommon,
299 #[serde(deserialize_with = "deserialize_named_person")]
300 #[serde(default = "NamedPerson::unknown_person")]
301 person: NamedPerson,
302 #[serde(default = "NamedTeam::unknown_team")]
303 #[serde(rename = "fromTeam")]
304 #[serde(deserialize_with = "deserialize_named_team")]
305 source_team: NamedTeam,
306 #[serde(default = "NamedTeam::unknown_team")]
307 #[serde(rename = "toTeam")]
308 #[serde(deserialize_with = "deserialize_named_team")]
309 destination_team: NamedTeam,
310 },
311 #[serde(rename = "RE", rename_all = "camelCase")]
312 Reinstated {
313 #[serde(flatten)]
314 common: TransactionCommon,
315 #[serde(deserialize_with = "deserialize_named_person")]
316 #[serde(default = "NamedPerson::unknown_person")]
317 person: NamedPerson,
318 #[serde(default = "NamedTeam::unknown_team")]
319 #[serde(rename = "toTeam")]
320 #[serde(deserialize_with = "deserialize_named_team")]
321 team: NamedTeam,
322 },
323 #[serde(rename = "LON", rename_all = "camelCase")]
324 Loan {
325 #[serde(flatten)]
326 common: TransactionCommon,
327 #[serde(deserialize_with = "deserialize_named_person")]
328 #[serde(default = "NamedPerson::unknown_person")]
329 person: NamedPerson,
330 #[serde(default = "NamedTeam::unknown_team")]
331 #[serde(rename = "fromTeam")]
332 #[serde(deserialize_with = "deserialize_named_team")]
333 source_team: NamedTeam,
334 #[serde(default = "NamedTeam::unknown_team")]
335 #[serde(rename = "toTeam")]
336 #[serde(deserialize_with = "deserialize_named_team")]
337 destination_team: NamedTeam,
338 },
339 #[serde(rename = "CP", rename_all = "camelCase")]
340 ContractPurchased {
341 #[serde(flatten)]
342 common: TransactionCommon,
343 #[serde(deserialize_with = "deserialize_named_person")]
344 #[serde(default = "NamedPerson::unknown_person")]
345 person: NamedPerson,
346 #[serde(default = "NamedTeam::unknown_team")]
347 #[serde(rename = "toTeam")]
348 #[serde(deserialize_with = "deserialize_named_team")]
349 team: NamedTeam,
350 },
351 #[serde(rename = "DR", rename_all = "camelCase")]
352 Drafted {
353 #[serde(flatten)]
354 common: TransactionCommon,
355 #[serde(deserialize_with = "deserialize_named_person")]
356 #[serde(default = "NamedPerson::unknown_person")]
357 person: NamedPerson,
358 #[serde(default = "NamedTeam::unknown_team")]
359 #[serde(rename = "toTeam")]
360 #[serde(deserialize_with = "deserialize_named_team")]
361 team: NamedTeam,
362 },
363 #[serde(rename = "DEI", rename_all = "camelCase")]
364 DeclaredIneligible {
365 #[serde(flatten)]
366 common: TransactionCommon,
367 #[serde(deserialize_with = "deserialize_named_person")]
368 #[serde(default = "NamedPerson::unknown_person")]
369 person: NamedPerson,
370 #[serde(default = "NamedTeam::unknown_team")]
371 #[serde(rename = "toTeam")]
372 #[serde(deserialize_with = "deserialize_named_team")]
373 team: NamedTeam,
374 },
375 #[serde(rename = "R5M", rename_all = "camelCase")]
376 RuleFiveDraftMinors {
377 #[serde(flatten)]
378 common: TransactionCommon,
379 #[serde(deserialize_with = "deserialize_named_person")]
380 #[serde(default = "NamedPerson::unknown_person")]
381 person: NamedPerson,
382 #[serde(default = "NamedTeam::unknown_team")]
383 #[serde(rename = "fromTeam")]
384 #[serde(deserialize_with = "deserialize_named_team")]
385 source_team: NamedTeam,
386 #[serde(default = "NamedTeam::unknown_team")]
387 #[serde(rename = "toTeam")]
388 #[serde(deserialize_with = "deserialize_named_team")]
389 destination_team: NamedTeam,
390 },
391 #[serde(rename = "RES", rename_all = "camelCase")]
392 Reserved {
393 #[serde(flatten)]
394 common: TransactionCommon,
395 #[serde(deserialize_with = "deserialize_named_person")]
396 #[serde(default = "NamedPerson::unknown_person")]
397 person: NamedPerson,
398 #[serde(default = "NamedTeam::unknown_team")]
399 #[serde(rename = "toTeam")]
400 #[serde(deserialize_with = "deserialize_named_team")]
401 team: NamedTeam,
402 },
403}
404
405impl Deref for Transaction {
406 type Target = TransactionCommon;
407
408 #[rustfmt::skip]
409 fn deref(&self) -> &Self::Target {
410 match self {
411 Self::Assigned { common, .. }
412 | Self::StatusChange { common, .. }
413 | Self::SignedAsFreeAgent { common, .. }
414 | Self::DesignatedForAssignment { common, .. }
415 | Self::Trade { common, .. }
416 | Self::NumberChange { common, .. }
417 | Self::Outrighted { common, .. }
418 | Self::ClaimedOffWaivers { common, .. }
419 | Self::Signed { common, .. }
420 | Self::Released { common, .. }
421 | Self::DeclaredFreeAgency { common, .. }
422 | Self::Optioned { common, .. }
423 | Self::Returned { common, .. }
424 | Self::Selected { common, .. }
425 | Self::Recalled { common, .. }
426 | Self::Suspension { common, .. }
427 | Self::Retired { common, .. }
428 | Self::Purchase { common, .. }
429 | Self::RuleFiveDraft { common, .. }
430 | Self::Reinstated { common, .. }
431 | Self::Loan { common, .. }
432 | Self::ContractPurchased { common, .. }
433 | Self::Drafted { common, .. }
434 | Self::DeclaredIneligible { common, .. }
435 | Self::RuleFiveDraftMinors { common, .. }
436 | Self::Reserved { common, .. } => common,
437 }
438 }
439}
440
441impl DerefMut for Transaction {
442 #[rustfmt::skip]
443 fn deref_mut(&mut self) -> &mut Self::Target {
444 match self {
445 Self::Assigned { common, .. }
446 | Self::StatusChange { common, .. }
447 | Self::SignedAsFreeAgent { common, .. }
448 | Self::DesignatedForAssignment { common, .. }
449 | Self::Trade { common, .. }
450 | Self::NumberChange { common, .. }
451 | Self::Outrighted { common, .. }
452 | Self::ClaimedOffWaivers { common, .. }
453 | Self::Signed { common, .. }
454 | Self::Released { common, .. }
455 | Self::DeclaredFreeAgency { common, .. }
456 | Self::Optioned { common, .. }
457 | Self::Returned { common, .. }
458 | Self::Selected { common, .. }
459 | Self::Recalled { common, .. }
460 | Self::Suspension { common, .. }
461 | Self::Retired { common, .. }
462 | Self::Purchase { common, .. }
463 | Self::RuleFiveDraft { common, .. }
464 | Self::Reinstated { common, .. }
465 | Self::Loan { common, .. }
466 | Self::ContractPurchased { common, .. }
467 | Self::Drafted { common, .. }
468 | Self::DeclaredIneligible { common, .. }
469 | Self::RuleFiveDraftMinors { common, .. }
470 | Self::Reserved { common, .. } => common,
471 }
472 }
473}
474
475impl Display for Transaction {
476 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
477 write!(f, "{}", self.description)
478 }
479}
480
481id!(TransactionId { id: u32 });
482
483fn deserialize_named_person<'de, D: Deserializer<'de>>(deserializer: D) -> Result<NamedPerson, D::Error> {
484 #[derive(Deserialize)]
485 #[serde(rename = "camelCase")]
486 struct NamedPersonWrapper {
487 #[serde(alias = "name")]
488 full_name: Option<String>,
489 #[serde(flatten)]
490 id: Option<PersonId>,
491 }
492
493 let NamedPersonWrapper { full_name, id } = NamedPersonWrapper::deserialize(deserializer)?;
494 Ok(NamedPerson {
495 full_name: full_name.unwrap_or(String::new()),
496 id: id.unwrap_or(PersonId::new(0))
497 })
498}
499
500fn deserialize_named_person_opt<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Option<NamedPerson>, D::Error> {
501 #[derive(Deserialize)]
502 #[serde(rename = "camelCase")]
503 struct NamedPersonWrapper {
504 #[serde(alias = "name")]
505 full_name: Option<String>,
506 #[serde(flatten)]
507 id: Option<PersonId>,
508 }
509
510 let wrapped = NamedPersonWrapper::deserialize(deserializer)?;
511 match wrapped {
512 NamedPersonWrapper { full_name, id: Some(id) } => Ok(Some(NamedPerson { full_name: full_name.unwrap_or(String::new()), id })),
513 _ => Ok(None)
514 }
515}
516
517fn deserialize_named_team<'de, D: Deserializer<'de>>(deserializer: D) -> Result<NamedTeam, D::Error> {
518 #[derive(Deserialize)]
519 #[serde(rename = "camelCase")]
520 struct NamedTeamWrapper {
521 #[serde(alias = "name")]
522 full_name: Option<String>,
523 #[serde(flatten)]
524 id: Option<TeamId>,
525 }
526
527 let NamedTeamWrapper { full_name, id } = NamedTeamWrapper::deserialize(deserializer)?;
528 Ok(NamedTeam {
529 full_name: full_name.unwrap_or(String::new()),
530 id: id.unwrap_or(TeamId::new(0))
531 })
532}
533
534fn deserialize_named_team_opt<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Option<NamedTeam>, D::Error> {
535 #[derive(Deserialize)]
536 #[serde(rename = "camelCase")]
537 struct NamedTeamWrapper {
538 #[serde(alias = "name")]
539 full_name: Option<String>,
540 #[serde(flatten)]
541 id: Option<TeamId>,
542 }
543
544 let wrapped = NamedTeamWrapper::deserialize(deserializer)?;
545 match wrapped {
546 NamedTeamWrapper { full_name, id: Some(id) } => Ok(Some(NamedTeam { full_name: full_name.unwrap_or(String::new()), id })),
547 _ => Ok(None),
548 }
549}
550
551pub enum TransactionsRequestKind {
552 Team(TeamId),
553 Player(PersonId),
554 Transactions(Vec<TransactionId>),
555 DateRange(NaiveDateRange),
556}
557
558impl Display for TransactionsRequestKind {
559 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
560 match self {
561 Self::Team(team_id) => write!(f, "teamId={team_id}"),
562 Self::Player(person_id) => write!(f, "playerId={person_id}"),
563 Self::Transactions(transactions) => write!(f, "transactionIds={}", transactions.iter().join(",")),
564 Self::DateRange(range) => write!(f, "startDate={}&endDate={}", range.start().format(MLB_API_DATE_FORMAT), range.end().format(MLB_API_DATE_FORMAT)),
565 }
566 }
567}
568
569#[derive(Builder)]
577#[builder(derive(Into))]
578#[builder(start_fn(vis = "", name = "__builder_internal"))]
579pub struct TransactionsRequest {
580 #[builder(setters(vis = "", name = __kind_internal))]
581 kind: TransactionsRequestKind,
582 #[builder(into)]
583 sport_id: Option<SportId>,
584}
585
586impl TransactionsRequest {
587 pub fn for_team(team_id: impl Into<TeamId>) -> TransactionsRequestBuilder<transactions_request_builder::SetKind> {
588 Self::__builder_internal().__kind_internal(TransactionsRequestKind::Team(team_id.into()))
589 }
590
591 pub fn for_player(person_id: impl Into<PersonId>) -> TransactionsRequestBuilder<transactions_request_builder::SetKind> {
592 Self::__builder_internal().__kind_internal(TransactionsRequestKind::Player(person_id.into()))
593 }
594
595 pub fn for_ids(transactions: Vec<TransactionId>) -> TransactionsRequestBuilder<transactions_request_builder::SetKind> {
596 Self::__builder_internal().__kind_internal(TransactionsRequestKind::Transactions(transactions))
597 }
598
599 pub fn for_date_range(range: NaiveDateRange) -> TransactionsRequestBuilder<transactions_request_builder::SetKind> {
600 Self::__builder_internal().__kind_internal(TransactionsRequestKind::DateRange(range))
601 }
602}
603
604impl<S: transactions_request_builder::State + transactions_request_builder::IsComplete> crate::request::RequestURLBuilderExt for TransactionsRequestBuilder<S> {
605 type Built = TransactionsRequest;
606}
607
608impl Display for TransactionsRequest {
609 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
610 write!(
611 f,
612 "http://statsapi.mlb.com/api/v1/transactions{}",
613 gen_params! {
614 self.kind,
615 "sportId"?: self.sport_id,
616 }
617 )
618 }
619}
620
621impl RequestURL for TransactionsRequest {
622 type Response = TransactionsResponse;
623}
624
625#[cfg(test)]
626mod tests {
627 use crate::person::players::PlayersRequest;
628 use crate::team::teams::TeamsRequest;
629 use crate::transactions::TransactionsRequest;
630 use crate::TEST_YEAR;
631 use chrono::NaiveDate;
632 use crate::request::RequestURLBuilderExt;
633 use crate::sport::SportId;
634
635 #[tokio::test]
636 async fn parse_current_year() {
637 let _ = TransactionsRequest::for_date_range(NaiveDate::from_ymd_opt(TEST_YEAR.try_into().unwrap(), 1, 1).unwrap()..=NaiveDate::from_ymd_opt(TEST_YEAR.try_into().unwrap(), 12, 31).unwrap()).sport_id(SportId::MLB).build_and_get().await.unwrap();
638 }
639
640 #[tokio::test]
641 async fn test_single_transaction() {
642 let _ = TransactionsRequest::for_ids(vec![809_972.into()]).build_and_get().await.unwrap();
643 }
644
645 #[tokio::test]
646 async fn parse_sample_requests() {
647 let blue_jays = TeamsRequest::mlb_teams()
648 .season(TEST_YEAR)
649 .build_and_get()
650 .await
651 .unwrap()
652 .teams
653 .into_iter()
654 .find(|team| team.name.as_str() == "Toronto Blue Jays")
655 .unwrap();
656 let bo_bichette = PlayersRequest::builder()
657 .season(2024)
658 .build_and_get()
659 .await
660 .unwrap()
661 .people
662 .into_iter()
663 .find(|person| person.full_name == "Bo Bichette")
664 .unwrap();
665
666 let response = TransactionsRequest::for_date_range(NaiveDate::from_ymd_opt(TEST_YEAR.try_into().unwrap(), 1, 1).unwrap()..=NaiveDate::from_ymd_opt(TEST_YEAR.try_into().unwrap(), 12, 31).unwrap()).build_and_get().await.unwrap();
667 let transaction_ids = response.transactions.into_iter().take(20).map(|transaction| transaction.id).collect::<Vec<_>>();
668 let _response = TransactionsRequest::for_team(blue_jays.id).build_and_get().await.unwrap();
669 let _response = TransactionsRequest::for_player(bo_bichette.id).build_and_get().await.unwrap();
670 let _response = TransactionsRequest::for_ids(transaction_ids).build_and_get().await.unwrap();
671 }
672}