1use std::fmt;
2
3use crate::{DataModelError, QueryField, require_non_empty};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub enum SortDirection {
7 Asc,
8 Desc,
9}
10
11impl fmt::Display for SortDirection {
12 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
13 match self {
14 Self::Asc => f.write_str("asc"),
15 Self::Desc => f.write_str("desc"),
16 }
17 }
18}
19
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct QuerySort {
22 pub field: QueryField,
23 pub direction: SortDirection,
24}
25
26impl QuerySort {
27 pub fn ascending(field: impl Into<String>) -> Result<Self, DataModelError> {
28 Ok(Self {
29 field: QueryField::new(field)?,
30 direction: SortDirection::Asc,
31 })
32 }
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum FilterOperator {
37 Eq,
38 Prefix,
39 Range,
40 In,
41}
42
43impl fmt::Display for FilterOperator {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 match self {
46 Self::Eq => f.write_str("eq"),
47 Self::Prefix => f.write_str("prefix"),
48 Self::Range => f.write_str("range"),
49 Self::In => f.write_str("in"),
50 }
51 }
52}
53
54#[derive(Debug, Clone, PartialEq, Eq)]
55pub struct QueryFilter {
56 pub field: QueryField,
57 pub operator: FilterOperator,
58 pub values: Vec<String>,
59}
60
61impl QueryFilter {
62 pub fn new(
63 field: impl Into<String>,
64 operator: FilterOperator,
65 values: Vec<String>,
66 ) -> Result<Self, DataModelError> {
67 Ok(Self {
68 field: QueryField::new(field)?,
69 operator,
70 values: values
71 .into_iter()
72 .map(|value| require_non_empty("filter_value", value))
73 .collect::<Result<Vec<_>, _>>()?,
74 })
75 }
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79pub struct PageRequest {
80 pub number: u32,
81 pub size: u16,
82}
83
84impl PageRequest {
85 pub fn new(number: u32, size: u16) -> Result<Self, DataModelError> {
86 if size == 0 {
87 return Err(DataModelError::InvalidPageSize);
88 }
89
90 Ok(Self { number, size })
91 }
92
93 pub fn offset(&self) -> usize {
94 self.number as usize * self.size as usize
95 }
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq)]
99pub enum PublicationVisibility {
100 PublishedOnly,
101 IncludeDrafts,
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105pub enum QueryCacheScope {
106 Public,
107 LocaleScoped,
108 UserScoped,
109 Uncacheable,
110}
111
112#[derive(Debug, Clone, PartialEq, Eq)]
113pub struct QueryContext {
114 pub locale: Option<String>,
115 pub principal_id: Option<String>,
116 pub publication_visibility: PublicationVisibility,
117 pub cache_scope: QueryCacheScope,
118}
119
120#[derive(Debug, Clone, PartialEq, Eq)]
121pub struct QuerySpec {
122 pub filters: Vec<QueryFilter>,
123 pub sort: Vec<QuerySort>,
124 pub page: PageRequest,
125 pub context: QueryContext,
126}
127
128impl QuerySpec {
129 pub fn new(page: PageRequest, context: QueryContext) -> Self {
130 Self {
131 filters: Vec::new(),
132 sort: Vec::new(),
133 page,
134 context,
135 }
136 }
137
138 pub fn with_filter(mut self, filter: QueryFilter) -> Self {
139 self.filters.push(filter);
140 self
141 }
142
143 pub fn with_sort(mut self, sort: QuerySort) -> Self {
144 self.sort.push(sort);
145 self
146 }
147}
148
149#[derive(Debug, Clone, PartialEq, Eq)]
150pub enum DataValue {
151 String(String),
152 Int(i64),
153 UInt(u64),
154 Bool(bool),
155}
156
157impl From<&str> for DataValue {
158 fn from(value: &str) -> Self {
159 Self::String(value.to_string())
160 }
161}
162
163impl From<String> for DataValue {
164 fn from(value: String) -> Self {
165 Self::String(value)
166 }
167}
168
169impl From<i64> for DataValue {
170 fn from(value: i64) -> Self {
171 Self::Int(value)
172 }
173}
174
175impl From<u64> for DataValue {
176 fn from(value: u64) -> Self {
177 Self::UInt(value)
178 }
179}
180
181impl From<bool> for DataValue {
182 fn from(value: bool) -> Self {
183 Self::Bool(value)
184 }
185}
186
187#[derive(Debug, Clone, PartialEq, Eq)]
188pub struct CompiledStatement {
189 pub sql: String,
190 pub bind_values: Vec<DataValue>,
191}
192
193#[derive(Debug, Clone, PartialEq, Eq)]
194pub struct CompiledQuery {
195 pub sql: String,
196 pub bind_values: Vec<DataValue>,
197 pub page: PageRequest,
198 pub context: QueryContext,
199}