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