1use std::env;
31use std::error::Error;
32use std::process;
33
34use cdg_api::cdg_types::*;
35use cdg_api::endpoints::Endpoints;
36use cdg_api::param_models::{
37 AmendmentListParams, BillActionsParams, BillDetailsParams, BillListParams, CommitteeListParams,
38 LawParams, MemberDetailsParams, MemberListParams, NominationListParams, TreatyListParams,
39};
40use cdg_api::response_models::{
41 AmendmentsResponse, BillActionsResponse, BillDetailsResponse, BillsResponse,
42 CommitteesResponse, CongressDetailsResponse, LawsResponse, MemberDetailsResponse,
43 MembersResponse, NominationsResponse, PrimaryResponse, TreatiesResponse,
44};
45use cdg_api::CongressApiClient;
46
47fn main() {
48 if let Err(e) = run() {
49 eprintln!("Error: {}", e);
50 process::exit(1);
51 }
52}
53
54fn run() -> Result<(), Box<dyn Error>> {
57 let api_key = env::var("CDG_API_KEY").ok();
59 let client = CongressApiClient::new(api_key)?;
60
61 let args: Vec<String> = env::args().collect();
63
64 if args.len() < 2 {
65 print_usage();
66 return Err("No command provided.".into());
67 }
68
69 let command = args[1].to_lowercase();
71 let results_max = 1000;
72
73 match command.as_str() {
74 "list_bills" => {
75 if args.len() < 3 {
76 eprintln!("Usage: cargo run -- list_bills {{amount}}");
77 return Err("Missing amount for list_bills command.".into());
78 }
79 let bill_amount = args[2].parse::<u32>().unwrap_or(10);
80 println!("Searching for {} bills...", bill_amount);
81 let limit = 250;
82 let all_bills = fetch_all(
83 &client,
84 |offset, limit| {
85 Endpoints::BillList(
86 BillListParams::default()
87 .format(FormatType::Json)
88 .limit(limit as u32)
89 .offset(offset as u32),
90 )
91 },
92 |response: &BillsResponse| response.bills.clone(),
93 bill_amount as usize,
94 limit,
95 )?;
96 display_bills(&all_bills);
97 }
98 "current_congress" => {
99 let endpoint =
100 Endpoints::CongressCurrent(cdg_api::param_models::CongressCurrentParams::default());
101 let response: CongressDetailsResponse = client.fetch(endpoint)?;
102 display_congress_details(&response);
103 }
104 "list_nominations" => {
105 let limit = 250;
106 let all_nominations: Vec<cdg_api::response_models::NominationItem> = fetch_all(
107 &client,
108 |offset, limit| {
109 Endpoints::NominationList(
110 NominationListParams::default()
111 .format(FormatType::Json)
112 .limit(limit as u32)
113 .offset(offset as u32),
114 )
115 },
116 |response: &NominationsResponse| response.nominations.clone(),
117 results_max,
118 limit,
119 )
120 .unwrap_or_default();
121 display_nominations(&NominationsResponse {
122 nominations: all_nominations,
123 unknown: None,
124 });
125 }
126 "list_treaties" => {
127 let limit = 250;
128 let all_treaties = fetch_all(
129 &client,
130 |offset, limit| {
131 Endpoints::TreatyList(
132 TreatyListParams::default()
133 .format(FormatType::Json)
134 .limit(limit as u32)
135 .offset(offset as u32),
136 )
137 },
138 |response: &TreatiesResponse| response.treaty.clone(),
139 results_max,
140 limit,
141 )?;
142 display_treaties(&TreatiesResponse {
143 treaty: all_treaties,
144 unknown: None,
145 });
146 }
147 "member_details" => {
148 if args.len() < 3 {
149 eprintln!("Usage: cargo run -- member_details <bioguide_id>");
150 return Err("Missing bioguide_id for member_details command.".into());
151 }
152 let bioguide_id = &args[2];
153 let params = MemberDetailsParams::default();
154 let endpoint = Endpoints::MemberDetails(bioguide_id.clone(), params);
155 let response: MemberDetailsResponse = client.fetch(endpoint)?;
156 display_member_details(&response);
157 }
158 "bill_details" => {
159 if args.len() < 5 {
160 eprintln!("Usage: cargo run -- bill_details <congress> <bill_type> <bill_number>");
161 return Err("Missing arguments for bill_details command.".into());
162 }
163 let congress: u32 = args[2].parse()?;
164 let bill_type = BillType::from_str(&args[3]).unwrap_or_default();
165 let bill_number: u32 = args[4].parse()?;
166 let params = BillDetailsParams::default();
167 let endpoint = Endpoints::BillDetails(congress, bill_type, bill_number, params);
168 let response: BillDetailsResponse = client.fetch(endpoint)?;
169 display_bill_details(&response);
170 }
171 "bill_actions" => {
172 if args.len() < 5 {
173 eprintln!("Usage: cargo run -- bill_actions <congress> <bill_type> <bill_number>");
174 return Err("Missing arguments for bill_actions command.".into());
175 }
176 let congress: u32 = args[2].parse()?;
177 let bill_type = BillType::from_str(&args[3]).unwrap_or_default();
178 let bill_number: u32 = args[4].parse()?;
179 let params = BillActionsParams::default();
180 let endpoint = Endpoints::BillActions(congress, bill_type, bill_number, params);
181 let response: BillActionsResponse = client.fetch(endpoint)?;
182 display_billacts_details(&response);
183 }
184 "current_members" => {
185 let limit = 250;
186 let all_members = fetch_all(
187 &client,
188 |offset, limit| {
189 Endpoints::MemberList(
190 MemberListParams::default()
191 .format(FormatType::Json)
192 .limit(limit as u32)
193 .offset(offset as u32)
194 .current_member(true),
195 )
196 },
197 |response: &MembersResponse| response.members.clone(),
198 results_max,
199 limit,
200 )?;
201 display_members(&MembersResponse {
202 members: all_members,
203 unknown: None,
204 });
205 }
206 "list_committees" => {
207 let limit = 250;
208 let all_committees = fetch_all(
209 &client,
210 |offset, limit| {
211 Endpoints::CommitteeList(
212 CommitteeListParams::default()
213 .format(FormatType::Json)
214 .limit(limit as u32)
215 .offset(offset as u32),
216 )
217 },
218 |response: &CommitteesResponse| response.committees.clone(),
219 results_max,
220 limit,
221 )?;
222 display_committees(&CommitteesResponse {
223 committees: all_committees,
224 });
225 }
226 "list_laws" => {
227 let limit = 250;
228 let congress = 118; let all_laws = fetch_all(
230 &client,
231 |offset, limit| {
232 Endpoints::LawByCongress(
233 congress,
234 LawParams::default()
235 .format(FormatType::Json)
236 .limit(limit as u32)
237 .offset(offset as u32),
238 )
239 },
240 |response: &LawsResponse| response.bills.clone(),
241 results_max,
242 limit,
243 )?;
244 display_laws(&LawsResponse {
245 bills: all_laws,
246 unknown: None,
247 });
248 }
249 "list_amendments" => {
250 let limit = 250;
251 let all_amendments = fetch_all(
252 &client,
253 |offset, limit| {
254 Endpoints::AmendmentList(
255 AmendmentListParams::default()
256 .format(FormatType::Json)
257 .limit(limit as u32)
258 .offset(offset as u32),
259 )
260 },
261 |response: &AmendmentsResponse| response.amendments.clone(),
262 results_max,
263 limit,
264 )?;
265 display_amendments(&AmendmentsResponse {
266 amendments: all_amendments,
267 unknown: None,
268 });
269 }
270 _ => {
271 println!("Unknown command: {}", command);
272 print_usage();
273 return Err("Invalid command.".into());
274 }
275 }
276
277 Ok(())
278}
279
280fn fetch_all<T, U, F, G>(
294 client: &CongressApiClient,
295 endpoint_fn: F,
296 extract_fn: G,
297 max: usize,
298 page_limit: usize,
299) -> Result<Vec<U>, Box<dyn Error>>
300where
301 F: Fn(usize, usize) -> Endpoints,
302 G: Fn(&T) -> Vec<U>,
303 T: serde::de::DeserializeOwned + PrimaryResponse,
304{
305 let mut all_items = Vec::new();
306 let mut offset = 0;
307
308 loop {
309 let endpoint = endpoint_fn(offset, page_limit);
310 let response: T = client.fetch(endpoint.clone())?;
311 let items = extract_fn(&response);
312 let fetched_count = items.len();
313 all_items.extend(items);
314
315 if all_items.len() >= max {
316 all_items.truncate(max);
317 break;
318 }
319
320 if fetched_count < page_limit || all_items.len() >= max {
321 break;
322 }
323
324 offset += fetched_count;
325 }
326
327 Ok(all_items)
328}
329
330fn print_usage() {
332 println!("Usage: cargo run -- <command> [additional arguments]");
333 println!("\nAvailable commands:");
334 println!(" list_bills {{amount}} : List recent bills introduced in Congress.");
335 println!(" current_congress : Display information about the current congress session.");
336 println!(" list_nominations : List recent nominations.");
337 println!(" list_treaties : List recent treaties.");
338 println!(
339 " member_details {{bioguide_id}} : Get detailed information about a specific member."
340 );
341 println!(" bill_details : Get detailed information about a specific bill.");
342 println!(" {{congress}}");
343 println!(" {{bill_type}}");
344 println!(" {{bill_number}}");
345 println!(
346 " current_members : Fetch and display all current members of Congress."
347 );
348 println!(" list_committees : List all congressional committees.");
349 println!(" list_laws : List recently passed laws.");
350 println!(" list_amendments : List recent amendments.");
351}
352
353fn display_members(response: &MembersResponse) {
355 println!("Current Members of Congress:");
356 for member in &response.members {
357 println!("----------------------------------------");
358 println!(
359 "Name : {}",
360 member.name.clone().unwrap_or_else(|| "N/A".to_string())
361 );
362 println!(
363 "bioguideId : {}",
364 member
365 .bioguide_id
366 .clone()
367 .unwrap_or_else(|| "N/A".to_string())
368 );
369 println!(
370 "State : {}",
371 member.state.clone().unwrap_or_else(|| "N/A".to_string())
372 );
373 println!(
374 "Party : {}",
375 member
376 .party_name
377 .clone()
378 .unwrap_or_else(|| "N/A".to_string())
379 );
380 println!("District : {}", member.district.unwrap_or(0));
381 let depiction = member.depiction.clone().unwrap_or_default();
382 println!(
383 "Image URL : {}",
384 depiction.image_url.unwrap_or_else(|| "N/A".to_string())
385 );
386 println!(
387 "Attribution: {}",
388 depiction.attribution.unwrap_or_else(|| "N/A".to_string())
389 );
390 }
391 println!("----------------------------------------");
392 println!("Total Members: {}", response.members.len());
393}
394
395fn display_bills(all_bills: &[cdg_api::response_models::BillSummary]) {
397 println!("Recent Bills:");
398 for bill in all_bills {
399 println!("----------------------------------------");
400 println!(
401 "Bill Number : {}",
402 bill.number.clone().unwrap_or_else(|| "N/A".to_string())
403 );
404 println!(
405 "Title : {}",
406 bill.title.clone().unwrap_or_else(|| "N/A".to_string())
407 );
408 println!("Congress : {}", bill.congress.unwrap_or(0));
409 println!(
410 "Origin Chamber: {}",
411 bill.origin_chamber
412 .clone()
413 .unwrap_or_else(|| "N/A".to_string())
414 );
415 if let Some(action) = &bill.latest_action {
416 println!(
417 "Latest Action : {} on {}",
418 action.text.clone().unwrap_or_else(|| "N/A".to_string()),
419 action
420 .action_date
421 .clone()
422 .unwrap_or_else(|| "N/A".to_string())
423 );
424 } else {
425 println!("Latest Action : N/A");
426 }
427 println!(
428 "URL : {}",
429 bill.url.clone().unwrap_or_else(|| "N/A".to_string())
430 );
431 }
432 println!("----------------------------------------");
433 println!("Total Bills: {}", all_bills.len());
434}
435
436fn display_congress_details(response: &CongressDetailsResponse) {
438 let congress = &response.congress;
439 println!("Congress Details:");
440 println!("----------------------------------------");
441 println!(
442 "Name : {}",
443 congress.name.clone().unwrap_or_else(|| "N/A".to_string())
444 );
445 println!("Number : {}", congress.number.unwrap_or(0));
446 println!(
447 "Start Year : {}",
448 congress
449 .start_year
450 .clone()
451 .unwrap_or_else(|| "N/A".to_string())
452 );
453 println!(
454 "End Year : {}",
455 congress
456 .end_year
457 .clone()
458 .unwrap_or_else(|| "N/A".to_string())
459 );
460 println!("Sessions:");
461 if let Some(sessions) = &congress.sessions {
462 for session in sessions {
463 println!(
464 " - Session {}: {} to {}",
465 session.number.unwrap_or(0),
466 session
467 .start_date
468 .clone()
469 .unwrap_or_else(|| "N/A".to_string()),
470 session
471 .end_date
472 .clone()
473 .unwrap_or_else(|| "N/A".to_string())
474 );
475 }
476 }
477 if let Some(url) = &congress.url {
478 println!("URL : {}", url.clone());
479 } else {
480 println!("URL : N/A");
481 }
482 println!("----------------------------------------");
483}
484
485fn display_nominations(response: &NominationsResponse) {
487 println!("Recent Nominations:");
488 for nomination in &response.nominations {
489 println!("----------------------------------------");
490 println!(
491 "Number : {}",
492 nomination.number.clone().unwrap_or_else(|| 0000)
493 );
494 println!(
495 "Citation : {}",
496 nomination
497 .citation
498 .clone()
499 .unwrap_or_else(|| "N/A".to_string())
500 );
501 println!(
502 "Description : {}",
503 nomination
504 .description
505 .clone()
506 .unwrap_or_else(|| "N/A".to_string())
507 );
508 println!(
509 "Received Date : {}",
510 nomination
511 .received_date
512 .clone()
513 .unwrap_or_else(|| "N/A".to_string())
514 );
515 if let Some(nomination_type) = &nomination.nomination_type {
516 println!(
517 "Nomination Type : is_civilian: {}, is_military: {}",
518 nomination_type.is_civilian.unwrap_or(false),
519 nomination_type.is_military.unwrap_or(false)
520 );
521 } else {
522 println!("Nomination Type : N/A");
523 }
524 if let Some(latest_action) = &nomination.latest_action {
525 println!(
526 "Latest Action : {}",
527 latest_action
528 .text
529 .clone()
530 .unwrap_or_else(|| "N/A".to_string())
531 );
532 } else {
533 println!("Latest Action : N/A");
534 }
535 println!(
536 "Organization : {}",
537 nomination
538 .organization
539 .clone()
540 .unwrap_or_else(|| "N/A".to_string())
541 );
542 println!(
543 "URL : {}",
544 nomination.url.clone().unwrap_or_else(|| "N/A".to_string())
545 );
546 }
547 println!("----------------------------------------");
548 println!("Total Nominations: {}", response.nominations.len());
549}
550
551fn display_treaties(response: &TreatiesResponse) {
553 println!("Recent Treaties:");
554 for treaty in &response.treaty {
555 println!("----------------------------------------");
556 println!(
557 "Number : {}",
558 treaty.number.clone().unwrap_or_else(|| 0000)
559 );
560 println!(
561 "Suffix : {}",
562 treaty.suffix.clone().unwrap_or_else(|| "N/A".to_string())
563 );
564 println!(
565 "Topic : {}",
566 treaty.topic.clone().unwrap_or_else(|| "N/A".to_string())
567 );
568 println!(
569 "Transmitted Date : {}",
570 treaty
571 .transmitted_date
572 .clone()
573 .unwrap_or_else(|| "N/A".to_string())
574 );
575 println!(
576 "Resolution Text : {}",
577 treaty
578 .resolution_text
579 .clone()
580 .unwrap_or_else(|| "N/A".to_string())
581 );
582 println!(
583 "Congress Received : {}",
584 treaty.congress_received.clone().unwrap_or_else(|| 0000)
585 );
586 println!(
587 "Congress Considered : {}",
588 treaty.congress_considered.clone().unwrap_or_else(|| 0000)
589 );
590 let parts = treaty.parts.clone().unwrap_or_default();
591 println!("Parts Count : {}", parts.count.unwrap_or(0));
592 if let Some(urls) = &parts.urls {
593 println!("Parts URLs : {}", urls.join(", "));
594 } else {
595 println!("Parts URLs : N/A");
596 }
597 }
598 println!("----------------------------------------");
599 println!("Total Treaties: {}", response.treaty.len());
600}
601
602fn display_committees(response: &CommitteesResponse) {
604 println!("Congressional Committees:");
605 for committee in &response.committees {
606 println!("----------------------------------------");
607 println!(
608 "Name : {}",
609 committee.name.clone().unwrap_or_else(|| "N/A".to_string())
610 );
611 println!(
612 "Chamber : {}",
613 committee
614 .chamber
615 .clone()
616 .unwrap_or_else(|| "N/A".to_string())
617 );
618 println!(
619 "Type : {}",
620 committee
621 .committee_type_code
622 .clone()
623 .unwrap_or_else(|| "N/A".to_string())
624 );
625 println!(
626 "URL : {}",
627 committee.url.clone().unwrap_or_else(|| "N/A".to_string())
628 );
629 }
630 println!("----------------------------------------");
631 println!("Total Committees: {}", response.committees.len());
632}
633
634fn display_laws(response: &LawsResponse) {
636 println!("Recent Laws:");
637 for law in &response.bills {
638 println!("----------------------------------------");
639 println!(
640 "Law Number : {}",
641 law.number.clone().unwrap_or_else(|| "N/A".to_string())
642 );
643 println!(
644 "Title : {}",
645 law.title.clone().unwrap_or_else(|| "N/A".to_string())
646 );
647 println!("Congress : {}", law.congress.unwrap_or(0));
648 println!(
649 "Origin Chamber: {}",
650 law.origin_chamber
651 .clone()
652 .unwrap_or_else(|| "N/A".to_string())
653 );
654 if let Some(action) = &law.latest_action {
655 println!(
656 "Latest Action : {} on {}",
657 action.text.clone().unwrap_or_else(|| "N/A".to_string()),
658 action
659 .action_date
660 .clone()
661 .unwrap_or_else(|| "N/A".to_string())
662 );
663 } else {
664 println!("Latest Action : N/A");
665 }
666 println!(
667 "URL : {}",
668 law.url.clone().unwrap_or_else(|| "N/A".to_string())
669 );
670 }
671 println!("----------------------------------------");
672 println!("Total Laws: {}", response.bills.len());
673}
674
675fn display_amendments(response: &AmendmentsResponse) {
677 println!("Recent Amendments:");
678 for amendment in &response.amendments {
679 println!("----------------------------------------");
680 println!(
681 "Amendment Number : {}",
682 amendment
683 .number
684 .clone()
685 .unwrap_or_else(|| "N/A".to_string())
686 );
687 println!(
688 "Type : {}",
689 amendment
690 .amendment_type
691 .clone()
692 .unwrap_or_else(|| "N/A".to_string())
693 );
694 println!("Congress : {}", amendment.congress.unwrap_or(0));
695 println!(
696 "Purpose : {}",
697 amendment
698 .purpose
699 .clone()
700 .unwrap_or_else(|| "N/A".to_string())
701 );
702 println!(
703 "Update Date : {}",
704 amendment
705 .update_date
706 .clone()
707 .unwrap_or_else(|| "N/A".to_string())
708 );
709 if let Some(action) = &amendment.latest_action {
710 println!(
711 "Latest Action : {} on {}",
712 action.text.clone().unwrap_or_else(|| "N/A".to_string()),
713 action
714 .action_date
715 .clone()
716 .unwrap_or_else(|| "N/A".to_string())
717 );
718 } else {
719 println!("Latest Action : N/A");
720 }
721 println!(
722 "URL : {}",
723 amendment.url.clone().unwrap_or_else(|| "N/A".to_string())
724 );
725 }
726 println!("----------------------------------------");
727 println!("Total Amendments: {}", response.amendments.len());
728}
729
730fn display_member_details(response: &MemberDetailsResponse) {
732 let member = &response.member;
733 println!("Member Details:");
734 println!("----------------------------------------");
735 println!(
736 "Name : {} {} {}",
737 member.first_name.clone().unwrap_or_else(|| "".to_string()),
738 member.middle_name.clone().unwrap_or_else(|| "".to_string()),
739 member.last_name.clone().unwrap_or_else(|| "".to_string())
740 );
741 println!(
742 "Suffix : {}",
743 member
744 .suffix_name
745 .clone()
746 .unwrap_or_else(|| "N/A".to_string())
747 );
748 println!(
749 "Nickname : {}",
750 member
751 .nick_name
752 .clone()
753 .unwrap_or_else(|| "N/A".to_string())
754 );
755 println!(
756 "Honorific Name : {}",
757 member
758 .honorific_name
759 .clone()
760 .unwrap_or_else(|| "N/A".to_string())
761 );
762 println!(
763 "Bioguide ID : {}",
764 member
765 .bioguide_id
766 .clone()
767 .unwrap_or_else(|| "N/A".to_string())
768 );
769 println!(
770 "Official URL : {}",
771 member
772 .official_website_url
773 .clone()
774 .unwrap_or_else(|| "N/A".to_string())
775 );
776 if let Some(address) = &member.address_information {
777 println!(
778 "Office Address : {}",
779 address
780 .office_address
781 .clone()
782 .unwrap_or_else(|| "N/A".to_string())
783 );
784 println!(
785 "City : {}",
786 address.city.clone().unwrap_or_else(|| "N/A".to_string())
787 );
788 println!(
789 "District : {}",
790 address
791 .district
792 .clone()
793 .unwrap_or_else(|| "N/A".to_string())
794 );
795 println!("ZIP Code : {}", address.zip_code.unwrap_or(00000));
796 println!(
797 "Phone Number : {}",
798 address
799 .phone_number
800 .clone()
801 .unwrap_or_else(|| "N/A".to_string())
802 );
803 } else {
804 println!("Address Information: N/A");
805 }
806 if let Some(depiction) = &member.depiction {
807 println!(
808 "Image URL : {}",
809 depiction
810 .image_url
811 .clone()
812 .unwrap_or_else(|| "N/A".to_string())
813 );
814 println!(
815 "Attribution : {}",
816 depiction
817 .attribution
818 .clone()
819 .unwrap_or_else(|| "N/A".to_string())
820 );
821 } else {
822 println!("Depiction : N/A");
823 }
824 println!("\nParty Affiliation:");
825 if let Some(party_history) = &member.party_history {
826 for party in party_history {
827 println!("----------------------------------------");
828 println!(
829 " - Party: {}",
830 party
831 .party_name
832 .clone()
833 .unwrap_or_else(|| "N/A".to_string())
834 );
835 println!(" Start: {}", party.start_year.unwrap_or(0));
836 println!(" End : {}", party.end_year.unwrap_or(0));
837 }
838 } else {
839 println!("Party: N/A");
840 }
841 println!("\nTerms of Service:");
842 if let Some(terms) = &member.terms {
843 for term in terms {
844 println!("----------------------------------------");
845 println!(
846 " - Chamber: {}",
847 term.chamber.clone().unwrap_or_else(|| "N/A".to_string())
848 );
849 println!(" Congress: {}", term.congress.unwrap_or(0));
850 println!(
851 " State: {} ({})",
852 term.state_name.clone().unwrap_or_else(|| "N/A".to_string()),
853 term.state_code.clone().unwrap_or_else(|| "N/A".to_string())
854 );
855 println!(
856 " Party: {} ({})",
857 term.party_name.clone().unwrap_or_else(|| "N/A".to_string()),
858 term.party_code.clone().unwrap_or_else(|| "N/A".to_string())
859 );
860 println!(
861 " Term: {} - {}",
862 term.start_year.unwrap_or(0),
863 term.end_year.unwrap_or(0)
864 );
865 }
866 } else {
867 println!("Terms: N/A");
868 }
869 println!("\n");
870 println!(
871 "Sponsored Legislation: {} bills",
872 member
873 .sponsored_legislation
874 .clone()
875 .unwrap_or_default()
876 .count
877 .unwrap_or(0)
878 );
879 println!(
880 "Cosponsored Legislation: {} bills",
881 member
882 .cosponsored_legislation
883 .clone()
884 .unwrap_or_default()
885 .count
886 .unwrap_or(0)
887 );
888 println!("----------------------------------------");
889}
890
891fn display_billacts_details(response: &BillActionsResponse) {
892 println!("Bill Actions:");
893 for action in &response.actions {
894 println!("----------------------------------------");
895 println!(
896 "Action Code: {}",
897 action
898 .action_code
899 .clone()
900 .unwrap_or_else(|| "N/A".to_string())
901 );
902 println!(
903 "Action Date: {}",
904 action
905 .action_date
906 .clone()
907 .unwrap_or_else(|| "N/A".to_string())
908 );
909 println!(
910 "Action Time: {}",
911 action
912 .action_time
913 .clone()
914 .unwrap_or_else(|| "N/A".to_string())
915 );
916 println!(
917 "Action Type: {}",
918 action
919 .action_type
920 .clone()
921 .unwrap_or_else(|| "N/A".to_string())
922 );
923 println!(
924 "Text : {}",
925 action.text.clone().unwrap_or_else(|| "N/A".to_string())
926 );
927 if let Some(ref source_system) = action.source_system {
928 println!("---> Source System Details");
929 println!(
930 "source system : {}",
931 source_system.name.clone().unwrap_or_default()
932 );
933 println!(
934 "source system code : {}",
935 source_system.code.clone().unwrap_or_default()
936 );
937 }
938 if let Some(ref committees) = action.committees {
939 println!("---> Committees Details");
940 for committee in committees {
941 println!(
942 "committee name : {}",
943 committee.name.clone().unwrap_or_default()
944 );
945 println!(
946 "committee code : {}",
947 committee.system_code.clone().unwrap_or_default()
948 );
949 println!(
950 "committee chamber : {}",
951 committee.chamber.clone().unwrap_or_default()
952 );
953 println!(
954 "committee type : {}",
955 committee.committee_type.clone().unwrap_or_default()
956 );
957 if let Some(activities) = &committee.activities {
958 println!("---> Committee Activities Details");
959 for activity in activities {
960 println!(
961 "activity name : {}",
962 activity.name.clone().unwrap_or_default()
963 );
964 println!(
965 "activity date : {}",
966 activity.date.clone().unwrap_or_default()
967 );
968 }
969 }
970 println!("url : {}", committee.url.clone().unwrap_or_default());
971 }
972 }
973 if let Some(recorded_votes) = &action.recorded_votes {
974 println!("---> Recorded Votes Details");
975 for vote in recorded_votes {
976 println!(
977 "vote chamber : {}",
978 vote.chamber.clone().unwrap_or_default()
979 );
980 println!(
981 "vote congress : {}",
982 vote.congress.clone().unwrap_or_default()
983 );
984 println!(
985 "vote session : {}",
986 vote.session_number.clone().unwrap_or_default()
987 );
988 println!(
989 "roll call number : {}",
990 vote.roll_number.clone().unwrap_or_default()
991 );
992 println!(
993 "vote date : {}",
994 vote.date.clone().unwrap_or_default()
995 );
996 println!("url : {}", vote.url.clone().unwrap_or_default());
997 }
998 }
999 if let Some(unknown) = &action.unknown {
1000 println!("---> Unknown Details");
1001 println!("{:#?}", unknown);
1002 }
1003 }
1004 println!("----------------------------------------");
1005}
1006
1007fn display_bill_details(response: &BillDetailsResponse) {
1009 let bill = &response.bill;
1010 println!("\nBill Details:");
1011 println!("----------------------------------------");
1012 println!(
1013 "Number : {}",
1014 bill.number.clone().unwrap_or_else(|| "N/A".to_string())
1015 );
1016 println!(
1017 "Title : {}",
1018 bill.title.clone().unwrap_or_else(|| "N/A".to_string())
1019 );
1020 println!("Congress : {}", bill.congress.unwrap_or(0));
1021 println!(
1022 "Origin Chamber : {}",
1023 bill.origin_chamber
1024 .clone()
1025 .unwrap_or_else(|| "N/A".to_string())
1026 );
1027 println!(
1028 "Last Update Date : {}",
1029 bill.update_date
1030 .clone()
1031 .unwrap_or_else(|| "N/A".to_string())
1032 );
1033 println!(
1034 "Laws Associated : {} laws",
1035 bill.related_bills
1036 .clone()
1037 .unwrap_or_default()
1038 .count
1039 .unwrap_or(0)
1040 );
1041 println!("Latest Action:");
1042 if let Some(action) = &bill.latest_action {
1043 println!(
1044 " - Text : {}",
1045 action.text.clone().unwrap_or_else(|| "N/A".to_string())
1046 );
1047 println!(
1048 " - Action Date: {}",
1049 action
1050 .action_date
1051 .clone()
1052 .unwrap_or_else(|| "N/A".to_string())
1053 );
1054 } else {
1055 println!(" - Latest Action: N/A");
1056 }
1057 println!("----------------------------------------");
1058
1059 println!("Raw JSON Response:");
1060 println!("{:#?}", response);
1061}