use jmap_types::Id;
#[derive(Debug, Default, Clone, PartialEq)]
pub struct QueryParams {
pub position: Option<i64>,
pub anchor: Option<Id>,
pub anchor_offset: Option<i64>,
pub limit: Option<u64>,
pub calculate_total: Option<bool>,
pub extra: serde_json::Map<String, serde_json::Value>,
}
impl QueryParams {
pub fn to_arguments(&self, account_id: &str) -> serde_json::Value {
let mut args = self.extra.clone();
args.insert("accountId".into(), account_id.into());
if let Some(p) = self.position {
args.insert("position".into(), p.into());
}
if let Some(a) = &self.anchor {
args.insert("anchor".into(), a.as_ref().into());
}
if let Some(o) = self.anchor_offset {
args.insert("anchorOffset".into(), o.into());
}
if let Some(l) = self.limit {
args.insert("limit".into(), l.into());
}
if let Some(c) = self.calculate_total {
args.insert("calculateTotal".into(), c.into());
}
serde_json::Value::Object(args)
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn all_fields_use_rfc8620_wire_names() {
let params = QueryParams {
position: Some(-5),
anchor: Some(Id::from("m1")),
anchor_offset: Some(-1),
limit: Some(20),
calculate_total: Some(true),
extra: serde_json::Map::new(),
};
assert_eq!(
params.to_arguments("acc1"),
json!({
"accountId": "acc1",
"position": -5,
"anchor": "m1",
"anchorOffset": -1,
"limit": 20,
"calculateTotal": true,
})
);
}
#[test]
fn default_sends_only_account_id() {
assert_eq!(
QueryParams::default().to_arguments("acc1"),
json!({ "accountId": "acc1" })
);
}
#[test]
fn extra_passes_through_and_typed_fields_win() {
let mut extra = serde_json::Map::new();
extra.insert("acmeCorpFoo".into(), json!(1));
extra.insert("limit".into(), json!(999));
extra.insert("accountId".into(), json!("evil"));
let params = QueryParams {
limit: Some(10),
extra,
..QueryParams::default()
};
assert_eq!(
params.to_arguments("acc1"),
json!({ "accountId": "acc1", "limit": 10, "acmeCorpFoo": 1 })
);
}
}