use crate::client::Client;
use crate::error::Result;
use crate::internal::apply_pagination;
use crate::Record;
use bon::Builder;
use std::collections::BTreeMap;
#[derive(Debug, Clone, Default, Builder, PartialEq, Eq)]
#[non_exhaustive]
pub struct ListApiKeysOptions {
#[builder(into)]
pub page: Option<u32>,
#[builder(into)]
pub limit: Option<u32>,
#[builder(into)]
pub cursor: Option<String>,
#[builder(into)]
pub shape: Option<String>,
#[builder(default)]
pub flat: bool,
#[builder(default)]
pub flat_lists: bool,
#[builder(default)]
pub extra: BTreeMap<String, String>,
}
impl ListApiKeysOptions {
fn to_query(&self) -> Vec<(String, String)> {
let mut q = Vec::new();
apply_pagination(
&mut q,
self.page,
self.limit,
self.cursor.as_deref(),
self.shape.as_deref(),
self.flat,
self.flat_lists,
);
for (k, v) in &self.extra {
if !v.is_empty() {
q.push((k.clone(), v.clone()));
}
}
q
}
}
impl Client {
pub async fn get_version(&self) -> Result<Record> {
self.get_json::<Record>("/api/version/", &[]).await
}
pub async fn list_api_keys(&self, opts: ListApiKeysOptions) -> Result<Record> {
let q = opts.to_query();
self.get_json::<Record>("/api/api-keys/", &q).await
}
}
#[cfg(test)]
mod tests {
use super::*;
fn get_q(q: &[(String, String)], k: &str) -> Option<String> {
q.iter().find(|(kk, _)| kk == k).map(|(_, v)| v.clone())
}
#[test]
fn api_keys_opts_emit_pagination() {
let opts = ListApiKeysOptions::builder()
.page(3u32)
.limit(25u32)
.build();
let q = opts.to_query();
assert_eq!(get_q(&q, "page").as_deref(), Some("3"));
assert_eq!(get_q(&q, "limit").as_deref(), Some("25"));
}
#[test]
fn api_keys_opts_empty_default() {
let opts = ListApiKeysOptions::default();
assert!(opts.to_query().is_empty());
}
#[test]
fn api_keys_opts_extra_passthrough() {
let mut extra = BTreeMap::new();
extra.insert("scope".into(), "read".into());
let opts = ListApiKeysOptions::builder().extra(extra).build();
let q = opts.to_query();
assert_eq!(get_q(&q, "scope").as_deref(), Some("read"));
}
}