1use crate::client::Client;
7use crate::error::Result;
8use crate::internal::apply_pagination;
9use crate::Record;
10use bon::Builder;
11use std::collections::BTreeMap;
12
13#[derive(Debug, Clone, Default, Builder, PartialEq, Eq)]
20#[non_exhaustive]
21pub struct ListApiKeysOptions {
22 #[builder(into)]
24 pub page: Option<u32>,
25 #[builder(into)]
27 pub limit: Option<u32>,
28 #[builder(into)]
30 pub cursor: Option<String>,
31 #[builder(into)]
33 pub shape: Option<String>,
34 #[builder(default)]
36 pub flat: bool,
37 #[builder(default)]
39 pub flat_lists: bool,
40
41 #[builder(default)]
43 pub extra: BTreeMap<String, String>,
44}
45
46impl ListApiKeysOptions {
47 fn to_query(&self) -> Vec<(String, String)> {
48 let mut q = Vec::new();
49 apply_pagination(
50 &mut q,
51 self.page,
52 self.limit,
53 self.cursor.as_deref(),
54 self.shape.as_deref(),
55 self.flat,
56 self.flat_lists,
57 );
58 for (k, v) in &self.extra {
59 if !v.is_empty() {
60 q.push((k.clone(), v.clone()));
61 }
62 }
63 q
64 }
65}
66
67impl Client {
68 pub async fn get_version(&self) -> Result<Record> {
74 self.get_json::<Record>("/api/version/", &[]).await
75 }
76
77 pub async fn list_api_keys(&self, opts: ListApiKeysOptions) -> Result<Record> {
84 let q = opts.to_query();
85 self.get_json::<Record>("/api/api-keys/", &q).await
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 fn get_q(q: &[(String, String)], k: &str) -> Option<String> {
94 q.iter().find(|(kk, _)| kk == k).map(|(_, v)| v.clone())
95 }
96
97 #[test]
98 fn api_keys_opts_emit_pagination() {
99 let opts = ListApiKeysOptions::builder()
100 .page(3u32)
101 .limit(25u32)
102 .build();
103 let q = opts.to_query();
104 assert_eq!(get_q(&q, "page").as_deref(), Some("3"));
105 assert_eq!(get_q(&q, "limit").as_deref(), Some("25"));
106 }
107
108 #[test]
109 fn api_keys_opts_empty_default() {
110 let opts = ListApiKeysOptions::default();
111 assert!(opts.to_query().is_empty());
112 }
113
114 #[test]
115 fn api_keys_opts_extra_passthrough() {
116 let mut extra = BTreeMap::new();
117 extra.insert("scope".into(), "read".into());
118 let opts = ListApiKeysOptions::builder().extra(extra).build();
119 let q = opts.to_query();
120 assert_eq!(get_q(&q, "scope").as_deref(), Some("read"));
121 }
122}