1use serde::{
2 Deserialize,
3 Serialize,
4};
5use utoipa::{
6 IntoParams,
7 PartialSchema,
8 ToSchema,
9};
10
11pub trait WebQueryModel {
12 type Leaf: ToSchema
13 + Clone
14 + serde::Serialize
15 + for<'de> serde::Deserialize<'de>;
16 type SortField: ToSchema
17 + Clone
18 + serde::Serialize
19 + for<'de> serde::Deserialize<'de>;
20}
21
22pub trait WebSortAccess: WebQueryModel {
23 fn sort_field(s: &DtoSort<Self>) -> <Self as WebQueryModel>::SortField;
24 fn sort_dir(s: &DtoSort<Self>) -> DtoSortDir;
25}
26
27#[derive(Clone, Serialize, Deserialize, ToSchema, Debug)]
28#[serde(untagged)]
29pub enum GenericDtoExpression<Q> {
30 #[schema(no_recursion)]
31 And {
32 and: Vec<GenericDtoExpression<Q>>,
33 },
34 #[schema(no_recursion)]
35 Or {
36 or: Vec<GenericDtoExpression<Q>>,
37 },
38 Leaf(Q),
39}
40
41#[derive(Clone, Serialize, Deserialize, ToSchema, Debug)]
42#[schema(bound = "S: ToSchema")]
43#[serde(transparent)]
44pub struct GenericDtoSort<S>(pub S);
45
46#[derive(Clone, Copy, Serialize, Deserialize, ToSchema, Debug)]
47#[serde(rename_all = "lowercase")]
48pub enum DtoSortDir {
49 Asc,
50 Desc,
51}
52
53#[derive(Clone, Copy, Serialize, Deserialize, ToSchema, Debug)]
54#[serde(rename_all = "camelCase")]
55pub struct DtoPage {
56 pub page_size: u32,
57 pub page_no: u32,
58}
59
60impl Default for DtoPage {
61 fn default() -> Self {
62 Self {
63 page_size: u32::MAX,
64 page_no: 0,
65 }
66 }
67}
68
69#[derive(Clone, Serialize, Deserialize, ToSchema, Debug, IntoParams)]
70pub struct GenericDtoFilter<Q, S>
71where
72 Q: PartialSchema + ToSchema,
73 S: PartialSchema + ToSchema,
74{
75 #[schema(no_recursion)]
76 pub filter: Option<GenericDtoExpression<Q>>,
77 #[schema(no_recursion)]
78 pub sort: Option<Vec<GenericDtoSort<S>>>,
79 pub page: Option<DtoPage>,
80}
81
82pub type DtoExpression<T> = GenericDtoExpression<<T as WebQueryModel>::Leaf>;
83
84pub type DtoSort<T> = GenericDtoSort<<T as WebQueryModel>::SortField>;
85
86pub type DtoFilter<T> = GenericDtoFilter<
87 <T as WebQueryModel>::Leaf,
88 <T as WebQueryModel>::SortField,
89>;