use schemars::JsonSchema;
use serde::{Deserialize, Deserializer, Serialize, de::Error as _};
use crate::{NativeId, StatusCategory};
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
pub struct TaskQuery {
pub text: Option<TextQuery>,
pub labels: LabelFilter,
pub statuses: Vec<StatusCategory>,
pub project: ProjectFilter,
}
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
pub struct ProjectQuery {
pub text: Option<TextQuery>,
pub labels: LabelFilter,
pub statuses: Vec<StatusCategory>,
}
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
pub struct DocumentQuery {
pub text: Option<TextQuery>,
pub labels: LabelFilter,
pub project: ProjectFilter,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct TextQuery {
pub terms: String,
pub fields: TextFields,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "kebab-case")]
pub enum TextFields {
Title,
Content,
TitleOrContent,
}
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
pub struct LabelFilter {
pub any_of: Vec<String>,
pub all_of: Vec<String>,
pub none_of: Vec<String>,
}
impl LabelFilter {
#[must_use]
pub fn is_empty(&self) -> bool {
self.any_of.is_empty() && self.all_of.is_empty() && self.none_of.is_empty()
}
}
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "kebab-case")]
pub enum ProjectFilter {
#[default]
Any,
Orphans,
Is(NativeId),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct PageRequest {
pub cursor: Option<Cursor>,
#[serde(deserialize_with = "non_zero_limit")]
pub limit: u32,
}
fn non_zero_limit<'de, D: Deserializer<'de>>(deserializer: D) -> Result<u32, D::Error> {
let value = u32::deserialize(deserializer)?;
if value == 0 {
return Err(D::Error::custom(
"limit must be at least 1; a page of no rows is not a page",
));
}
Ok(value)
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct Page<T> {
pub items: Vec<T>,
pub next: Option<Cursor>,
}
impl<T> Page<T> {
#[must_use]
pub fn last(items: Vec<T>) -> Self {
Self { items, next: None }
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(transparent)]
pub struct Cursor(pub String);