1use std::borrow::Cow;
2use std::fmt;
3
4use tokio_postgres::types::ToSql;
5use types::time::{Date, DateTime, Timeout};
6use types::uid::UniqueId;
7
8mod whr;
9
10pub type SqlStr = Cow<'static, str>;
11
12#[derive(Debug)]
13#[non_exhaustive]
14pub struct Filter<'a> {
15 pub whr: Where,
16 pub order_by: OrderBy,
17 pub limit: Limit,
18 pub offset: Offset,
19 pub params: Params<'a>,
20}
21
22impl<'a> Filter<'a> {
23 pub fn new() -> Self {
24 Self {
25 whr: Where::new(),
26 order_by: OrderBy::new(),
27 limit: Limit::new(),
28 offset: Offset::new(),
29 params: Params::new(),
30 }
31 }
32
33 pub(crate) fn to_formatter(&'a self) -> FilterFormatter<'a> {
34 FilterFormatter {
35 whr: &self.whr,
36 order_by: &self.order_by,
37 limit: &self.limit,
38 offset: &self.offset,
39 params: &self.params,
40 }
41 }
42}
43
44impl fmt::Display for Filter<'_> {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 write!(f, "{}", self.to_formatter())
47 }
48}
49
50#[derive(Debug)]
51#[non_exhaustive]
52pub(crate) struct FilterFormatter<'a> {
53 pub whr: &'a Where,
54 pub order_by: &'a OrderBy,
55 pub limit: &'a Limit,
56 pub offset: &'a Offset,
57 pub params: &'a Params<'a>,
58}
59
60impl fmt::Display for FilterFormatter<'_> {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 self.whr.fmt(f)?;
63
64 self.order_by.fmt(f)?;
65
66 let offset_has_param = matches!(self.offset, Offset::Param);
67 let param_count =
68 self.params.len() - if offset_has_param { 1 } else { 0 };
69
70 match &self.limit {
71 Limit::Fixed(value) => write!(f, " LIMIT {}", value)?,
72 Limit::Param => {
73 write!(f, " LIMIT ${}", param_count)?;
74 }
75 Limit::All => {}
76 }
77
78 match &self.offset {
79 Offset::Zero => {}
80 Offset::Fixed(value) => write!(f, " OFFSET {}", value)?,
81 Offset::Param => {
82 write!(f, " OFFSET ${}", self.params.len())?;
83 }
84 }
85
86 Ok(())
87 }
88}
89
90#[derive(Debug)]
91#[non_exhaustive]
92pub struct WhereFilter<'a> {
93 pub whr: Where,
94 pub params: Params<'a>,
95}
96
97impl<'a> WhereFilter<'a> {
98 pub fn new() -> Self {
99 Self {
100 whr: Where::new(),
101 params: Params::new(),
102 }
103 }
104}
105
106impl fmt::Display for WhereFilter<'_> {
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 self.whr.fmt(f)
109 }
110}
111
112#[derive(Debug, Default)]
113pub struct Where {
114 inner: Vec<WherePart>,
115}
116
117#[derive(Debug)]
118#[non_exhaustive]
119pub enum WherePart {
120 Operation(WhereOperation),
121 And,
122 Or,
123 Nested(Where),
124}
125
126#[derive(Debug)]
127pub struct WhereOperation {
128 pub kind: Operator,
129 pub column: Cow<'static, str>,
130}
131
132#[derive(Debug)]
133#[non_exhaustive]
134pub enum Operator {
135 Eq,
136 Ne,
137 Lt,
138 Lte,
139 Gt,
140 Gte,
141 Like,
142 In { length: usize },
143
144 IsNull,
146 IsNotNull,
148}
149
150#[derive(Debug)]
151#[non_exhaustive]
152pub enum WhereIdent {
153 Param,
154 Name(Cow<'static, str>),
155}
156
157impl Where {
158 pub fn new() -> Self {
159 Self { inner: vec![] }
160 }
161
162 pub fn push(&mut self, part: impl Into<WherePart>) {
163 self.inner.push(part.into());
164 }
165
166 fn is_empty(&self) -> bool {
167 self.inner.is_empty()
168 }
169
170 pub(crate) fn to_formatter<'a>(&'a self) -> WhereFormatter<'a> {
171 WhereFormatter {
172 whr: &self,
173 param_start: 0,
174 }
175 }
176}
177
178impl<'a> fmt::Display for Where {
179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180 self.to_formatter().fmt(f)
181 }
182}
183
184pub(crate) struct WhereFormatter<'a> {
185 pub whr: &'a Where,
186 pub param_start: usize,
188}
189
190impl<'a> WhereFormatter<'a> {
191 fn fmt_inner(
193 &self,
194 f: &mut fmt::Formatter<'_>,
195 ) -> Result<usize, fmt::Error> {
196 let mut param_num = self.param_start;
197
198 for part in &self.whr.inner {
199 match part {
200 WherePart::And => f.write_str(" AND ")?,
201 WherePart::Or => f.write_str(" OR ")?,
202 WherePart::Nested(inner) => {
203 let mut inner = inner.to_formatter();
204 inner.param_start = param_num;
205 f.write_str("(")?;
206 param_num = inner.fmt_inner(f)?;
207 f.write_str(")")?;
208 }
209 WherePart::Operation(op) => match &op.kind {
210 Operator::IsNull | Operator::IsNotNull => {
211 write!(f, "\"{}\" {}", op.column, op.kind.as_str())?;
212 }
213 Operator::In { length } if *length == 0 => {
216 write!(f, "1=0")?;
217 }
218 Operator::In { length } => {
219 write!(f, "\"{}\" IN (", op.column)?;
220
221 for i in 0..*length {
222 if i != 0 {
223 f.write_str(", ")?;
224 }
225
226 param_num += 1;
227 write!(f, "${}", param_num)?;
228 }
229
230 f.write_str(")")?;
231 }
232 o => {
233 param_num += 1;
234
235 write!(
236 f,
237 "\"{}\" {} ${}",
238 op.column,
239 o.as_str(),
240 param_num
241 )?;
242 }
243 },
244 }
245 }
246
247 Ok(param_num)
248 }
249}
250
251impl<'a> fmt::Display for WhereFormatter<'a> {
252 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253 if self.whr.is_empty() {
254 return Ok(());
255 }
256
257 f.write_str(" WHERE ")?;
258
259 self.fmt_inner(f)?;
260
261 Ok(())
262 }
263}
264
265impl From<WhereOperation> for WherePart {
266 fn from(op: WhereOperation) -> Self {
267 Self::Operation(op)
268 }
269}
270
271impl Operator {
272 fn as_str(&self) -> &str {
273 match self {
274 Operator::Eq => "=",
275 Operator::Ne => "!=",
276 Operator::Lt => "<",
277 Operator::Lte => "<=",
278 Operator::Gt => ">",
279 Operator::Gte => ">=",
280 Operator::Like => "LIKE",
281 Operator::In { .. } => "IN",
282 Operator::IsNull => "IS NULL",
283 Operator::IsNotNull => "IS NOT NULL",
284 }
285 }
286}
287
288#[derive(Debug)]
289pub struct OrderBy {
290 inner: Vec<OrderByPart>,
291}
292
293#[derive(Debug)]
294pub enum OrderByPart {
295 Asc(Cow<'static, str>),
296 Desc(Cow<'static, str>),
297}
298
299impl OrderBy {
300 pub fn new() -> Self {
301 Self { inner: vec![] }
302 }
303
304 pub fn push_asc(&mut self, column: impl Into<Cow<'static, str>>) {
305 self.inner.push(OrderByPart::Asc(column.into()));
306 }
307
308 pub fn push_desc(&mut self, column: impl Into<Cow<'static, str>>) {
309 self.inner.push(OrderByPart::Desc(column.into()));
310 }
311
312 fn is_empty(&self) -> bool {
313 self.inner.is_empty()
314 }
315}
316
317impl fmt::Display for OrderBy {
318 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
319 if self.is_empty() {
320 return Ok(());
321 }
322
323 f.write_str(" ORDER BY ")?;
324
325 for (i, part) in self.inner.iter().enumerate() {
326 if i != 0 {
327 f.write_str(", ")?;
328 }
329
330 match part {
331 OrderByPart::Asc(column) => write!(f, "\"{}\" ASC", column)?,
332 OrderByPart::Desc(column) => write!(f, "\"{}\" DESC", column)?,
333 }
334 }
335
336 Ok(())
337 }
338}
339
340#[derive(Debug)]
341pub enum Limit {
342 Fixed(usize),
343 Param,
344 All,
345}
346
347impl Limit {
348 pub fn new() -> Self {
349 Self::All
350 }
351
352 pub fn set_param(&mut self) {
353 *self = Self::Param;
354 }
355
356 pub fn set_fixed(&mut self, value: usize) {
357 *self = Self::Fixed(value);
358 }
359}
360
361#[derive(Debug)]
362pub enum Offset {
363 Zero,
364 Fixed(usize),
365 Param,
366}
367
368impl Offset {
369 pub fn new() -> Self {
370 Self::Zero
371 }
372
373 pub fn set_param(&mut self) {
374 *self = Self::Param;
375 }
376
377 pub fn set_fixed(&mut self, value: usize) {
378 *self = Self::Fixed(value);
379 }
380}
381
382#[derive(Debug)]
383pub struct Params<'a> {
384 inner: Vec<Param<'a>>,
385}
386
387impl<'a> Params<'a> {
388 pub fn new() -> Self {
389 Self { inner: vec![] }
390 }
391
392 pub fn push(&mut self, param: Param<'a>) {
393 self.inner.push(param);
394 }
395
396 pub fn len(&self) -> usize {
397 self.inner.len()
398 }
399
400 pub fn is_empty(&self) -> bool {
401 self.inner.is_empty()
402 }
403
404 pub fn iter_to_sql(
405 &self,
406 ) -> impl ExactSizeIterator<Item = &(dyn ToSql + Sync)> {
407 self.inner.iter().map(|p| p.data.as_ref())
408 }
409}
410
411#[derive(Debug)]
412#[non_exhaustive]
413pub struct Param<'a> {
414 pub name: &'static str,
416 pub data: CowParamData<'a>,
417 is_null: bool,
418}
419
420impl<'a> Param<'a> {
421 pub fn new<T>(name: &'static str, data: &'a T) -> Self
422 where
423 T: ParamData + ToSql + Send + Sync,
424 {
425 Self {
426 name,
427 is_null: data.is_null(),
428 data: CowParamData::Borrowed(data),
429 }
430 }
431
432 pub fn new_owned<T>(name: &'static str, data: T) -> Self
433 where
434 T: ParamData + ToSql + Send + Sync + 'static,
435 {
436 Self {
437 name,
438 is_null: data.is_null(),
439 data: CowParamData::Owned(Box::new(data)),
440 }
441 }
442
443 pub fn is_null(&self) -> bool {
444 self.is_null
445 }
446}
447
448#[derive(Debug)]
449pub enum CowParamData<'a> {
450 Borrowed(&'a (dyn ToSql + Send + Sync)),
451 Owned(Box<dyn ToSql + Send + Sync>),
452}
453
454impl<'a> CowParamData<'a> {
455 pub fn as_ref(&self) -> &(dyn ToSql + Sync) {
456 match self {
457 CowParamData::Borrowed(data) => *data,
458 CowParamData::Owned(data) => &**data,
459 }
460 }
461}
462
463pub trait ParamData {
464 fn is_null(&self) -> bool;
465}
466
467impl<T> ParamData for &T
468where
469 T: ParamData + ?Sized,
470{
471 fn is_null(&self) -> bool {
472 (**self).is_null()
473 }
474}
475
476impl<T> ParamData for &mut T
477where
478 T: ParamData + ?Sized,
479{
480 fn is_null(&self) -> bool {
481 (**self).is_null()
482 }
483}
484
485impl<T> ParamData for Option<T> {
486 fn is_null(&self) -> bool {
487 self.is_none()
488 }
489}
490
491impl<T> ParamData for Vec<T> {
492 fn is_null(&self) -> bool {
493 false
495 }
496}
497
498impl<T> ParamData for [T] {
499 fn is_null(&self) -> bool {
500 false
502 }
503}
504
505impl<'a, T> ParamData for Cow<'a, T>
506where
507 T: ToOwned + ParamData,
508{
509 fn is_null(&self) -> bool {
510 (**self).is_null()
511 }
512}
513
514#[macro_export]
515macro_rules! param_not_null {
516 ($impl_for:ty) => {
517 impl $crate::filter::ParamData for $impl_for {
518 fn is_null(&self) -> bool {
519 false
520 }
521 }
522 };
523
524 ($( $impl_for:ty ),*) => {
525 $(
526 $crate::param_not_null!($impl_for);
527 )*
528 };
529}
530
531param_not_null!(
532 String, str, bool, f64, f32, i64, i32, i16, i8, UniqueId, DateTime, Date,
533 Timeout
534);
535
536#[cfg(feature = "email")]
537impl ParamData for email_address::EmailAddress {
538 fn is_null(&self) -> bool {
539 false
540 }
541}