jmap-client/src/core/query.rs

250 lines
5.7 KiB
Rust

use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize)]
pub struct QueryRequest<F, S, A: Default> {
#[serde(rename = "accountId")]
account_id: String,
#[serde(rename = "filter")]
#[serde(skip_serializing_if = "Option::is_none")]
filter: Option<Filter<F>>,
#[serde(rename = "sort")]
#[serde(skip_serializing_if = "Option::is_none")]
sort: Option<Vec<Comparator<S>>>,
#[serde(rename = "position")]
#[serde(skip_serializing_if = "Option::is_none")]
position: Option<i32>,
#[serde(rename = "anchor")]
#[serde(skip_serializing_if = "Option::is_none")]
anchor: Option<String>,
#[serde(rename = "anchorOffset")]
#[serde(skip_serializing_if = "Option::is_none")]
anchor_offset: Option<i32>,
#[serde(rename = "limit")]
#[serde(skip_serializing_if = "Option::is_none")]
limit: Option<usize>,
#[serde(rename = "calculateTotal")]
#[serde(skip_serializing_if = "Option::is_none")]
calculate_total: Option<bool>,
#[serde(flatten)]
arguments: A,
}
#[derive(Debug, Clone, Serialize)]
#[serde(untagged)]
pub enum Filter<T> {
FilterOperator(FilterOperator<T>),
FilterCondition(T),
}
#[derive(Debug, Clone, Serialize)]
pub struct FilterOperator<T> {
operator: Operator,
conditions: Vec<Filter<T>>,
}
#[derive(Debug, Clone, Serialize)]
pub enum Operator {
#[serde(rename = "AND")]
And,
#[serde(rename = "OR")]
Or,
#[serde(rename = "NOT")]
Not,
}
#[derive(Debug, Clone, Serialize)]
pub struct Comparator<A> {
#[serde(rename = "isAscending")]
is_ascending: bool,
#[serde(skip_serializing_if = "Option::is_none")]
collation: Option<String>,
#[serde(flatten)]
arguments: A,
}
#[derive(Debug, Clone, Deserialize)]
pub struct QueryResponse {
#[serde(rename = "accountId")]
account_id: String,
#[serde(rename = "queryState")]
query_state: String,
#[serde(rename = "canCalculateChanges")]
can_calculate_changes: Option<bool>,
#[serde(rename = "position")]
position: i32,
#[serde(rename = "ids")]
ids: Vec<String>,
#[serde(rename = "total")]
total: Option<usize>,
#[serde(rename = "limit")]
limit: Option<usize>,
}
impl<F, S, A: Default> QueryRequest<F, S, A> {
pub fn new(account_id: String) -> Self {
QueryRequest {
account_id,
filter: None,
sort: None,
position: None,
anchor: None,
anchor_offset: None,
limit: None,
calculate_total: None,
arguments: A::default(),
}
}
pub fn account_id(&mut self, account_id: impl Into<String>) -> &mut Self {
self.account_id = account_id.into();
self
}
pub fn filter(&mut self, filter: impl Into<Filter<F>>) -> &mut Self {
self.filter = Some(filter.into());
self
}
pub fn sort(&mut self, sort: impl IntoIterator<Item = Comparator<S>>) -> &mut Self {
self.sort = Some(sort.into_iter().collect());
self
}
pub fn position(&mut self, position: i32) -> &mut Self {
self.position = position.into();
self
}
pub fn anchor(&mut self, anchor: impl Into<String>) -> &mut Self {
self.anchor = Some(anchor.into());
self
}
pub fn anchor_offset(&mut self, anchor_offset: i32) -> &mut Self {
self.anchor_offset = anchor_offset.into();
self
}
pub fn limit(&mut self, limit: usize) -> &mut Self {
self.limit = Some(limit);
self
}
pub fn arguments(&mut self) -> &mut A {
&mut self.arguments
}
}
impl QueryResponse {
pub fn account_id(&self) -> &str {
&self.account_id
}
pub fn ids(&self) -> &[String] {
&self.ids
}
pub fn total(&self) -> Option<usize> {
self.total
}
pub fn limit(&self) -> Option<usize> {
self.limit
}
pub fn position(&self) -> i32 {
self.position
}
pub fn query_state(&self) -> &str {
&self.query_state
}
pub fn can_calculate_changes(&self) -> bool {
self.can_calculate_changes.unwrap_or(false)
}
}
impl<A> Comparator<A> {
pub fn new(arguments: A) -> Self {
Comparator {
is_ascending: true,
collation: None,
arguments,
}
}
pub fn is_ascending(mut self, is_ascending: bool) -> Self {
self.is_ascending = is_ascending;
self
}
pub fn collation(mut self, collation: String) -> Self {
self.collation = Some(collation);
self
}
}
impl<T> From<FilterOperator<T>> for Filter<T> {
fn from(filter: FilterOperator<T>) -> Self {
Filter::FilterOperator(filter)
}
}
impl<T> From<T> for Filter<T> {
fn from(filter: T) -> Self {
Filter::FilterCondition(filter)
}
}
impl<T> Filter<T> {
pub fn and<U, V>(conditions: U) -> Self
where
U: IntoIterator<Item = V>,
V: Into<Filter<T>>,
{
Filter::FilterOperator(FilterOperator {
operator: Operator::And,
conditions: conditions.into_iter().map(|t| t.into()).collect(),
})
}
pub fn or<U, V>(conditions: U) -> Self
where
U: IntoIterator<Item = V>,
V: Into<Filter<T>>,
{
Filter::FilterOperator(FilterOperator {
operator: Operator::Or,
conditions: conditions.into_iter().map(|t| t.into()).collect(),
})
}
pub fn not<U, V>(conditions: U) -> Self
where
U: IntoIterator<Item = V>,
V: Into<Filter<T>>,
{
Filter::FilterOperator(FilterOperator {
operator: Operator::Not,
conditions: conditions.into_iter().map(|t| t.into()).collect(),
})
}
}