alpaca_data/corporate_actions/
response.rs1use crate::{Error, transport::pagination::PaginatedResponse};
2
3use super::CorporateActions;
4
5#[derive(Clone, Debug, Default, PartialEq, serde::Deserialize)]
6pub struct ListResponse {
7 pub corporate_actions: CorporateActions,
8 pub next_page_token: Option<String>,
9}
10
11impl PaginatedResponse for ListResponse {
12 fn next_page_token(&self) -> Option<&str> {
13 self.next_page_token.as_deref()
14 }
15
16 fn merge_page(&mut self, next: Self) -> Result<(), Error> {
17 self.corporate_actions.merge(next.corporate_actions);
18 self.next_page_token = next.next_page_token;
19 Ok(())
20 }
21
22 fn clear_next_page_token(&mut self) {
23 self.next_page_token = None;
24 }
25}
26
27#[cfg(test)]
28mod tests {
29 use super::ListResponse;
30 use crate::transport::pagination::PaginatedResponse;
31
32 #[test]
33 fn list_response_deserializes_official_bucketed_wrapper_shape() {
34 let response: ListResponse = serde_json::from_str(
35 r#"{"corporate_actions":{"cash_dividends":[{"id":"e2b597ca-c2cb-47af-9315-cafb8708766d","symbol":"640CVR031","cusip":"640CVR031","rate":0.055284,"special":false,"foreign":false,"process_date":"2024-08-14","ex_date":"2024-08-07","record_date":"2024-08-07","payable_date":"2024-08-15"}],"name_changes":[{"id":"564620f3-dac4-4558-a227-5c8dd6f4d82e","old_symbol":"007975113","old_cusip":"007975113","new_symbol":"22112H119","new_cusip":"22112H119","process_date":"2024-08-13"}],"contract_adjustments":[{"id":"ca-undocumented","memo":"undocumented family"}],"mystery_bucket":[{"id":"mystery-1","field":"value"}]},"next_page_token":"page-2"}"#,
36 )
37 .expect("response should deserialize");
38
39 assert_eq!(response.corporate_actions.cash_dividends.len(), 1);
40 assert_eq!(response.corporate_actions.name_changes.len(), 1);
41 assert_eq!(response.corporate_actions.contract_adjustments.len(), 1);
42 assert_eq!(
43 response
44 .corporate_actions
45 .other
46 .get("mystery_bucket")
47 .map(Vec::len),
48 Some(1)
49 );
50 assert_eq!(response.next_page_token.as_deref(), Some("page-2"));
51 }
52
53 #[test]
54 fn list_response_merge_appends_bucketed_pages_and_clears_next_page_token() {
55 let mut first: ListResponse = serde_json::from_str(
56 r#"{"corporate_actions":{"cash_dividends":[{"id":"ca-1","symbol":"AAA","cusip":"111111111","rate":0.1,"special":false,"foreign":false,"process_date":"2024-08-01","ex_date":"2024-08-01"}],"contract_adjustments":[{"id":"undoc-1"}],"mystery_bucket":[{"id":"mystery-1"}]},"next_page_token":"page-2"}"#,
57 )
58 .expect("first response should deserialize");
59 let second: ListResponse = serde_json::from_str(
60 r#"{"corporate_actions":{"cash_dividends":[{"id":"ca-2","symbol":"BBB","cusip":"222222222","rate":0.2,"special":false,"foreign":false,"process_date":"2024-08-02","ex_date":"2024-08-02"}],"name_changes":[{"id":"name-1","old_symbol":"OLD","old_cusip":"333333333","new_symbol":"NEW","new_cusip":"444444444","process_date":"2024-08-02"}],"contract_adjustments":[{"id":"undoc-2"}],"mystery_bucket":[{"id":"mystery-2"}]},"next_page_token":null}"#,
61 )
62 .expect("second response should deserialize");
63
64 first
65 .merge_page(second)
66 .expect("merge should append bucketed corporate action pages");
67 first.clear_next_page_token();
68
69 assert_eq!(first.corporate_actions.cash_dividends.len(), 2);
70 assert_eq!(first.corporate_actions.name_changes.len(), 1);
71 assert_eq!(first.corporate_actions.contract_adjustments.len(), 2);
72 assert_eq!(
73 first
74 .corporate_actions
75 .other
76 .get("mystery_bucket")
77 .map(Vec::len),
78 Some(2)
79 );
80 assert_eq!(first.next_page_token, None);
81 }
82}