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