Skip to main content

sqlxo/web/
mod.rs

1use serde::{
2	Deserialize,
3	Serialize,
4};
5use sqlxo_traits::{
6	QueryContext,
7	WebJoinPayload,
8	WebLeaf,
9	WebQueryModel,
10	WebSortField,
11};
12use utoipa::{
13	IntoParams,
14	ToSchema,
15};
16
17use crate::select::HavingPredicate;
18
19mod builder;
20mod page;
21pub use page::{
22	WebPage,
23	WebPagination,
24};
25
26#[derive(Clone, Serialize, Deserialize, ToSchema, Debug, IntoParams)]
27#[serde(bound(deserialize = "Q: WebLeaf + Deserialize<'de>, S: \
28                             WebSortField + Deserialize<'de>, A: WebLeaf + \
29                             Deserialize<'de>, J: WebJoinPayload + \
30                             Deserialize<'de>"))]
31#[into_params(parameter_in = Query)]
32pub struct GenericWebFilter<Q, S, A, J>
33where
34	Q: WebLeaf + Serialize,
35	S: WebSortField + Serialize,
36	A: WebLeaf + Serialize,
37	J: WebJoinPayload + Serialize,
38{
39	#[schema(nullable)]
40	pub joins:  Option<Vec<JoinPayload<J>>>,
41	#[schema(no_recursion, nullable)]
42	pub filter: Option<GenericWebExpression<Q>>,
43	#[schema(no_recursion, nullable)]
44	pub having: Option<GenericWebExpression<A>>,
45	#[schema(no_recursion, nullable)]
46	pub sort:   Option<Vec<GenericWebSort<S>>>,
47	#[schema(no_recursion, nullable)]
48	pub search: Option<WebSearch>,
49	#[schema(nullable)]
50	pub page:   Option<WebPagination>,
51}
52
53#[derive(Clone, Serialize, Deserialize, ToSchema, Debug)]
54#[serde(bound(deserialize = "Q: WebLeaf + Deserialize<'de>"))]
55#[serde(untagged)]
56pub enum GenericWebExpression<Q>
57where
58	Q: WebLeaf + Serialize,
59{
60	#[schema(no_recursion)]
61	And {
62		and: Vec<GenericWebExpression<Q>>,
63	},
64	#[schema(no_recursion)]
65	Or {
66		or: Vec<GenericWebExpression<Q>>,
67	},
68	Leaf(Q),
69}
70
71#[derive(Clone, Serialize, Deserialize, ToSchema, Debug)]
72#[serde(bound(deserialize = "S: WebSortField + Deserialize<'de>"))]
73#[serde(transparent)]
74pub struct GenericWebSort<S>(pub S)
75where
76	S: WebSortField + Serialize;
77
78#[derive(Clone, Serialize, Deserialize, ToSchema, Debug)]
79#[serde(rename_all = "camelCase")]
80pub struct WebSearch {
81	pub query:        String,
82	#[serde(default, skip_serializing_if = "Option::is_none")]
83	pub language:     Option<String>,
84	#[serde(default, skip_serializing_if = "Option::is_none")]
85	pub include_rank: Option<bool>,
86}
87
88pub type WebExpression<T> = GenericWebExpression<<T as WebQueryModel>::Leaf>;
89pub type WebAggregateExpression<T> =
90	GenericWebExpression<<T as WebQueryModel>::AggregateLeaf>;
91pub type WebSort<T> = GenericWebSort<<T as WebQueryModel>::SortField>;
92pub type WebFilter<T> = GenericWebFilter<
93	<T as WebQueryModel>::Leaf,
94	<T as WebQueryModel>::SortField,
95	<T as WebQueryModel>::AggregateLeaf,
96	<T as WebQueryModel>::JoinPath,
97>;
98
99pub trait AggregateBindable<C>: WebQueryModel
100where
101	C: QueryContext,
102{
103	fn map_aggregate_leaf(
104		leaf: &<Self as WebQueryModel>::AggregateLeaf,
105	) -> HavingPredicate;
106}
107
108#[derive(Clone, Serialize, Deserialize, ToSchema, Debug)]
109pub enum NoJoins {}
110
111impl WebJoinPayload for NoJoins {
112	fn flatten(&self, _prefix: &mut Vec<String>, _out: &mut Vec<Vec<String>>) {
113		match *self {}
114	}
115}
116
117#[derive(Clone, Serialize, Deserialize, ToSchema, Debug)]
118#[serde(transparent)]
119pub struct JoinPayload<J>(pub J);
120
121impl<J> JoinPayload<J> {
122	pub fn inner(&self) -> &J {
123		&self.0
124	}
125}