cot/db/
query.rs

1//! Database query builder.
2
3use std::marker::PhantomData;
4
5use derive_more::with_trait::Debug;
6use sea_query::{ExprTrait, IntoColumnRef};
7
8use crate::db;
9use crate::db::{
10    Auto, Database, DatabaseBackend, DbFieldValue, DbValue, ForeignKey, FromDbValue, Identifier,
11    Model, StatementResult, ToDbFieldValue,
12};
13
14/// A query that can be executed on a database. Can be used to filter, update,
15/// or delete rows.
16///
17/// # Example
18///
19/// ```
20/// use cot::db::model;
21/// use cot::db::query::Query;
22///
23/// #[model]
24/// struct User {
25///     #[model(primary_key)]
26///     id: i32,
27///     name: String,
28///     age: i32,
29/// }
30///
31/// let query = Query::<User>::new();
32/// ```
33pub struct Query<T> {
34    filter: Option<Expr>,
35    limit: Option<u64>,
36    offset: Option<u64>,
37    phantom_data: PhantomData<fn() -> T>,
38}
39
40// manual implementation to avoid `T: Debug` in the trait bounds
41impl<T> Debug for Query<T> {
42    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43        f.debug_struct("Query")
44            .field("filter", &self.filter)
45            .field("limit", &self.limit)
46            .field("offset", &self.offset)
47            .field("phantom_data", &self.phantom_data)
48            .finish()
49    }
50}
51
52// manual implementation to avoid `T: Clone` in the trait bounds
53impl<T> Clone for Query<T> {
54    fn clone(&self) -> Self {
55        Self {
56            filter: self.filter.clone(),
57            limit: self.limit,
58            offset: self.offset,
59            phantom_data: PhantomData,
60        }
61    }
62}
63
64// manual implementation to avoid `T: PartialEq` in the trait bounds
65impl<T> PartialEq for Query<T> {
66    fn eq(&self, other: &Self) -> bool {
67        self.filter == other.filter
68    }
69}
70
71impl<T: Model> Default for Query<T> {
72    fn default() -> Self {
73        Self::new()
74    }
75}
76
77impl<T: Model> Query<T> {
78    /// Create a new query.
79    ///
80    /// # Example
81    ///
82    /// ```
83    /// use cot::db::model;
84    /// use cot::db::query::Query;
85    ///
86    /// #[model]
87    /// struct User {
88    ///     #[model(primary_key)]
89    ///     id: i32,
90    ///     name: String,
91    ///     age: i32,
92    /// }
93    ///
94    /// let query = Query::<User>::new();
95    /// ```
96    #[must_use]
97    pub fn new() -> Self {
98        Self {
99            filter: None,
100            limit: None,
101            offset: None,
102            phantom_data: PhantomData,
103        }
104    }
105
106    /// Set the filter expression for the query.
107    ///
108    /// # Example
109    ///
110    /// ```
111    /// use cot::db::model;
112    /// use cot::db::query::{Expr, Query};
113    ///
114    /// #[model]
115    /// struct User {
116    ///     #[model(primary_key)]
117    ///     id: i32,
118    ///     name: String,
119    ///     age: i32,
120    /// }
121    ///
122    /// let query = Query::<User>::new().filter(Expr::eq(Expr::field("name"), Expr::value("John")));
123    /// ```
124    pub fn filter(&mut self, filter: Expr) -> &mut Self {
125        self.filter = Some(filter);
126        self
127    }
128
129    /// Set the limit for the query.
130    ///
131    /// # Example
132    ///
133    /// ```
134    /// use cot::db::model;
135    /// use cot::db::query::{Expr, Query};
136    ///
137    /// #[model]
138    /// struct User {
139    ///     #[model(primary_key)]
140    ///     id: i32,
141    ///     name: String,
142    ///     age: i32,
143    /// }
144    ///
145    /// let query = Query::<User>::new().limit(10);
146    /// ```
147    pub fn limit(&mut self, limit: u64) -> &mut Self {
148        self.limit = Some(limit);
149        self
150    }
151
152    /// Set the offset for the query.
153    ///
154    /// # Example
155    ///
156    /// ```
157    /// use cot::db::model;
158    /// use cot::db::query::{Expr, Query};
159    ///
160    /// #[model]
161    /// struct User {
162    ///     #[model(primary_key)]
163    ///     id: i32,
164    ///     name: String,
165    ///     age: i32,
166    /// }
167    ///
168    /// let query = Query::<User>::new().offset(10);
169    /// ```
170    pub fn offset(&mut self, offset: u64) -> &mut Self {
171        self.offset = Some(offset);
172        self
173    }
174
175    /// Execute the query and return all results.
176    ///
177    /// # Errors
178    ///
179    /// Returns an error if the query fails.
180    pub async fn all<DB: DatabaseBackend>(&self, db: &DB) -> db::Result<Vec<T>> {
181        db.query(self).await
182    }
183
184    /// Execute the query and return the first result.
185    ///
186    /// # Errors
187    ///
188    /// Returns an error if the query fails.
189    pub async fn get<DB: DatabaseBackend>(&self, db: &DB) -> db::Result<Option<T>> {
190        // TODO panic/error if more than one result
191        db.get(self).await
192    }
193
194    /// Execute the query and return the number of results.
195    ///
196    /// # Errors
197    ///
198    /// Returns an error if the query fails.
199    pub async fn count(&self, db: &Database) -> db::Result<u64> {
200        let mut select = sea_query::Query::select();
201        select
202            .from(T::TABLE_NAME)
203            .expr(sea_query::Expr::col(sea_query::Asterisk).count());
204        self.add_filter_to_statement(&mut select);
205        let row = db.fetch_option(&select).await?;
206        let count = match row {
207            #[expect(clippy::cast_sign_loss)]
208            Some(row) => row.get::<i64>(0)? as u64,
209            None => 0,
210        };
211        Ok(count)
212    }
213
214    /// Execute the query and check if any results exist.
215    ///
216    /// # Errors
217    ///
218    /// Returns an error if the query fails.
219    pub async fn exists<DB: DatabaseBackend>(&self, db: &DB) -> db::Result<bool> {
220        db.exists(self).await
221    }
222
223    /// Delete all rows that match the query.
224    ///
225    /// # Errors
226    ///
227    /// Returns an error if the query fails.
228    pub async fn delete<DB: DatabaseBackend>(&self, db: &DB) -> db::Result<StatementResult> {
229        db.delete(self).await
230    }
231
232    pub(super) fn add_filter_to_statement<S: sea_query::ConditionalStatement>(
233        &self,
234        statement: &mut S,
235    ) {
236        if let Some(filter) = &self.filter {
237            statement.and_where(filter.as_sea_query_expr());
238        }
239    }
240
241    pub(super) fn add_limit_to_statement(&self, statement: &mut sea_query::SelectStatement) {
242        if let Some(limit) = self.limit {
243            statement.limit(limit);
244        }
245    }
246
247    pub(super) fn add_offset_to_statement(&self, statement: &mut sea_query::SelectStatement) {
248        if let Some(offset) = self.offset {
249            statement.offset(offset);
250        }
251    }
252}
253
254/// An expression that can be used to filter, update, or delete rows.
255///
256/// This is used to create complex queries with multiple conditions. Typically,
257/// it is only internally used by the [`cot::db::query!`] macro to create a
258/// [`Query`].
259///
260/// # Example
261///
262/// ```
263/// use cot::db::{model, query};
264/// use cot::db::query::{Expr, Query};
265///
266/// #[model]
267/// struct MyModel {
268///     #[model(primary_key)]
269///     id: i32,
270/// };
271///
272/// let expr = Expr::eq(Expr::field("id"), Expr::value(5));
273///
274/// assert_eq!(
275///     <Query<MyModel>>::new().filter(expr),
276///     query!(MyModel, $id == 5)
277/// );
278/// ```
279#[derive(Debug, Clone, PartialEq)]
280pub enum Expr {
281    /// An expression containing a reference to a column.
282    ///
283    /// # Example
284    ///
285    /// ```
286    /// use cot::db::{model, query};
287    /// use cot::db::query::{Expr, Query};
288    ///
289    /// #[model]
290    /// struct MyModel {
291    ///     #[model(primary_key)]
292    ///     id: i32,
293    /// };
294    ///
295    /// let expr = Expr::eq(Expr::field("id"), Expr::value(5));
296    ///
297    /// assert_eq!(
298    ///     <Query<MyModel>>::new().filter(expr),
299    ///     query!(MyModel, $id == 5)
300    /// );
301    /// ```
302    Field(Identifier),
303    /// An expression containing a literal value.
304    ///
305    /// # Example
306    ///
307    /// ```
308    /// use cot::db::{model, query};
309    /// use cot::db::query::{Expr, Query};
310    ///
311    /// #[model]
312    /// struct MyModel {
313    ///     #[model(primary_key)]
314    ///     id: i32,
315    /// };
316    ///
317    /// let expr = Expr::ne(Expr::field("id"), Expr::value(5));
318    ///
319    /// assert_eq!(
320    ///     <Query<MyModel>>::new().filter(expr),
321    ///     query!(MyModel, $id != 5)
322    /// );
323    /// ```
324    Value(DbValue),
325    /// An `AND` expression.
326    ///
327    /// # Example
328    ///
329    /// ```
330    /// use cot::db::{model, query};
331    /// use cot::db::query::{Expr, Query};
332    ///
333    /// #[model]
334    /// struct MyModel {
335    ///     #[model(primary_key)]
336    ///     id: i32,
337    /// };
338    ///
339    /// let expr = Expr::and(
340    ///     Expr::gt(Expr::field("id"), Expr::value(10)),
341    ///     Expr::lt(Expr::field("id"), Expr::value(20))
342    /// );
343    /// assert_eq!(
344    ///     <Query<MyModel>>::new().filter(expr),
345    ///     query!(MyModel, $id > 10 && $id < 20)
346    /// );
347    /// ```
348    And(Box<Expr>, Box<Expr>),
349    /// An `OR` expression.
350    ///
351    /// # Example
352    ///
353    /// ```
354    /// use cot::db::{model, query};
355    /// use cot::db::query::{Expr, Query};
356    ///
357    /// #[model]
358    /// struct MyModel {
359    ///     #[model(primary_key)]
360    ///     id: i32,
361    /// };
362    ///
363    /// let expr = Expr::or(
364    ///     Expr::gt(Expr::field("id"), Expr::value(10)),
365    ///     Expr::lt(Expr::field("id"), Expr::value(20))
366    /// );
367    /// assert_eq!(
368    ///     <Query<MyModel>>::new().filter(expr),
369    ///     query!(MyModel, $id > 10 || $id < 20)
370    /// );
371    /// ```
372    Or(Box<Expr>, Box<Expr>),
373    /// An `=` expression.
374    ///
375    /// # Example
376    ///
377    /// ```
378    /// use cot::db::{model, query};
379    /// use cot::db::query::{Expr, Query};
380    ///
381    /// #[model]
382    /// struct MyModel {
383    ///     #[model(primary_key)]
384    ///     id: i32,
385    /// };
386    ///
387    /// let expr = Expr::eq(Expr::field("id"), Expr::value(5));
388    ///
389    /// assert_eq!(
390    ///     <Query<MyModel>>::new().filter(expr),
391    ///     query!(MyModel, $id == 5)
392    /// );
393    /// ```
394    Eq(Box<Expr>, Box<Expr>),
395    /// A `!=` expression.
396    ///
397    /// # Example
398    ///
399    /// ```
400    /// use cot::db::{model, query};
401    /// use cot::db::query::{Expr, Query};
402    ///
403    /// #[model]
404    /// struct MyModel {
405    ///     #[model(primary_key)]
406    ///     id: i32,
407    /// };
408    ///
409    /// let expr = Expr::ne(Expr::field("id"), Expr::value(5));
410    ///
411    /// assert_eq!(
412    ///     <Query<MyModel>>::new().filter(expr),
413    ///     query!(MyModel, $id != 5)
414    /// );
415    /// ```
416    Ne(Box<Expr>, Box<Expr>),
417    /// A `<` expression.
418    ///
419    /// # Example
420    ///
421    /// ```
422    /// use cot::db::{model, query};
423    /// use cot::db::query::{Expr, Query};
424    ///
425    /// #[model]
426    /// struct MyModel {
427    ///     #[model(primary_key)]
428    ///     id: i32,
429    /// };
430    ///
431    /// let expr = Expr::lt(Expr::field("id"), Expr::value(5));
432    ///
433    /// assert_eq!(
434    ///     <Query<MyModel>>::new().filter(expr),
435    ///     query!(MyModel, $id < 5)
436    /// );
437    /// ```
438    Lt(Box<Expr>, Box<Expr>),
439    /// A `<=` expression.
440    ///
441    /// # Example
442    ///
443    /// ```
444    /// use cot::db::{model, query};
445    /// use cot::db::query::{Expr, Query};
446    ///
447    /// #[model]
448    /// struct MyModel {
449    ///     #[model(primary_key)]
450    ///     id: i32,
451    /// };
452    ///
453    /// let expr = Expr::lte(Expr::field("id"), Expr::value(5));
454    ///
455    /// assert_eq!(
456    ///     <Query<MyModel>>::new().filter(expr),
457    ///     query!(MyModel, $id <= 5)
458    /// );
459    /// ```
460    Lte(Box<Expr>, Box<Expr>),
461    /// A `>` expression.
462    ///
463    /// # Example
464    ///
465    /// ```
466    /// use cot::db::{model, query};
467    /// use cot::db::query::{Expr, Query};
468    ///
469    /// #[model]
470    /// struct MyModel {
471    ///     #[model(primary_key)]
472    ///     id: i32,
473    /// };
474    ///
475    /// let expr = Expr::gt(Expr::field("id"), Expr::value(5));
476    ///
477    /// assert_eq!(
478    ///     <Query<MyModel>>::new().filter(expr),
479    ///     query!(MyModel, $id > 5)
480    /// );
481    /// ```
482    Gt(Box<Expr>, Box<Expr>),
483    /// A `>=` expression.
484    ///
485    /// # Example
486    ///
487    /// ```
488    /// use cot::db::{model, query};
489    /// use cot::db::query::{Expr, Query};
490    ///
491    /// #[model]
492    /// struct MyModel {
493    ///     #[model(primary_key)]
494    ///     id: i32,
495    /// };
496    ///
497    /// let expr = Expr::gte(Expr::field("id"), Expr::value(5));
498    ///
499    /// assert_eq!(
500    ///     <Query<MyModel>>::new().filter(expr),
501    ///     query!(MyModel, $id >= 5)
502    /// );
503    /// ```
504    Gte(Box<Expr>, Box<Expr>),
505    /// A `+` expression.
506    ///
507    /// # Example
508    ///
509    /// ```
510    /// use cot::db::{model, query};
511    /// use cot::db::query::{Expr, Query};
512    ///
513    /// #[model]
514    /// struct MyModel {
515    ///     #[model(primary_key)]
516    ///     id: i32,
517    ///     id_2: i32,
518    /// };
519    ///
520    /// let expr = Expr::eq(Expr::field("id"), Expr::add(Expr::field("id_2"), Expr::value(5)));
521    ///
522    /// assert_eq!(
523    ///     <Query<MyModel>>::new().filter(expr),
524    ///     query!(MyModel, $id == $id_2 + 5)
525    /// );
526    /// ```
527    Add(Box<Expr>, Box<Expr>),
528    /// A `-` expression.
529    ///
530    /// # Example
531    ///
532    /// ```
533    /// use cot::db::{model, query};
534    /// use cot::db::query::{Expr, Query};
535    ///
536    /// #[model]
537    /// struct MyModel {
538    ///     #[model(primary_key)]
539    ///     id: i32,
540    ///     id_2: i32,
541    /// };
542    ///
543    /// let expr = Expr::eq(Expr::field("id"), Expr::sub(Expr::field("id_2"), Expr::value(5)));
544    ///
545    /// assert_eq!(
546    ///     <Query<MyModel>>::new().filter(expr),
547    ///     query!(MyModel, $id == $id_2 - 5)
548    /// );
549    /// ```
550    Sub(Box<Expr>, Box<Expr>),
551    /// A `*` expression.
552    ///
553    /// # Example
554    ///
555    /// ```
556    /// use cot::db::{model, query};
557    /// use cot::db::query::{Expr, Query};
558    ///
559    /// #[model]
560    /// struct MyModel {
561    ///     #[model(primary_key)]
562    ///     id: i32,
563    ///     id_2: i32,
564    /// };
565    ///
566    /// let expr = Expr::eq(Expr::field("id"), Expr::mul(Expr::field("id_2"), Expr::value(2)));
567    ///
568    /// assert_eq!(
569    ///     <Query<MyModel>>::new().filter(expr),
570    ///     query!(MyModel, $id == $id_2 * 2)
571    /// );
572    /// ```
573    Mul(Box<Expr>, Box<Expr>),
574    /// A `/` expression.
575    ///
576    /// # Example
577    ///
578    /// ```
579    /// use cot::db::{model, query};
580    /// use cot::db::query::{Expr, Query};
581    ///
582    /// #[model]
583    /// struct MyModel {
584    ///     #[model(primary_key)]
585    ///     id: i32,
586    ///     id_2: i32,
587    /// };
588    ///
589    /// let expr = Expr::eq(Expr::field("id"), Expr::div(Expr::field("id_2"), Expr::value(2)));
590    ///
591    /// assert_eq!(
592    ///     <Query<MyModel>>::new().filter(expr),
593    ///     query!(MyModel, $id == $id_2 / 2)
594    /// );
595    /// ```
596    Div(Box<Expr>, Box<Expr>),
597}
598
599impl Expr {
600    /// Create a new field expression. This represents a reference to a column
601    /// in the database.
602    ///
603    /// # Example
604    ///
605    /// ```
606    /// use cot::db::{model, query};
607    /// use cot::db::query::{Expr, Query};
608    ///
609    /// #[model]
610    /// struct MyModel {
611    ///     #[model(primary_key)]
612    ///     id: i32,
613    /// };
614    ///
615    /// let expr = Expr::eq(Expr::field("id"), Expr::value(5));
616    ///
617    /// assert_eq!(
618    ///     <Query<MyModel>>::new().filter(expr),
619    ///     query!(MyModel, $id == 5)
620    /// );
621    /// ```
622    #[must_use]
623    pub fn field<T: Into<Identifier>>(identifier: T) -> Self {
624        Self::Field(identifier.into())
625    }
626
627    /// Create a new value expression. This represents a literal value that gets
628    /// passed into the SQL query.
629    ///
630    /// # Panics
631    ///
632    /// If the value provided is a [`DbFieldValue::Auto`].
633    ///
634    /// # Example
635    ///
636    /// ```
637    /// use cot::db::{model, query};
638    /// use cot::db::query::{Expr, Query};
639    ///
640    /// #[model]
641    /// struct MyModel {
642    ///     #[model(primary_key)]
643    ///     id: i32,
644    /// };
645    ///
646    /// let expr = Expr::ne(Expr::field("id"), Expr::value(5));
647    ///
648    /// assert_eq!(
649    ///     <Query<MyModel>>::new().filter(expr),
650    ///     query!(MyModel, $id != 5)
651    /// );
652    /// ```
653    #[must_use]
654    #[expect(clippy::needless_pass_by_value)]
655    pub fn value<T: ToDbFieldValue>(value: T) -> Self {
656        match value.to_db_field_value() {
657            DbFieldValue::Value(value) => Self::Value(value),
658            DbFieldValue::Auto => panic!("Cannot create query with a non-value field"),
659        }
660    }
661
662    /// Create a new `AND` expression.
663    ///
664    /// # Example
665    ///
666    /// ```
667    /// use cot::db::{model, query};
668    /// use cot::db::query::{Expr, Query};
669    ///
670    /// #[model]
671    /// struct MyModel {
672    ///     #[model(primary_key)]
673    ///     id: i32,
674    /// };
675    ///
676    /// let expr = Expr::and(
677    ///     Expr::gt(Expr::field("id"), Expr::value(10)),
678    ///     Expr::lt(Expr::field("id"), Expr::value(20))
679    /// );
680    /// assert_eq!(
681    ///     <Query<MyModel>>::new().filter(expr),
682    ///     query!(MyModel, $id > 10 && $id < 20)
683    /// );
684    /// ```
685    #[must_use]
686    pub fn and(lhs: Self, rhs: Self) -> Self {
687        Self::And(Box::new(lhs), Box::new(rhs))
688    }
689
690    /// Create a new `OR` expression.
691    ///
692    /// # Example
693    ///
694    /// ```
695    /// use cot::db::{model, query};
696    /// use cot::db::query::{Expr, Query};
697    ///
698    /// #[model]
699    /// struct MyModel {
700    ///     #[model(primary_key)]
701    ///     id: i32,
702    /// };
703    ///
704    /// let expr = Expr::or(
705    ///     Expr::gt(Expr::field("id"), Expr::value(10)),
706    ///     Expr::lt(Expr::field("id"), Expr::value(20))
707    /// );
708    /// assert_eq!(
709    ///     <Query<MyModel>>::new().filter(expr),
710    ///     query!(MyModel, $id > 10 || $id < 20)
711    /// );
712    /// ```
713    #[must_use]
714    pub fn or(lhs: Self, rhs: Self) -> Self {
715        Self::Or(Box::new(lhs), Box::new(rhs))
716    }
717
718    /// Create a new `=` expression.
719    ///
720    /// # Example
721    ///
722    /// ```
723    /// use cot::db::{model, query};
724    /// use cot::db::query::{Expr, Query};
725    ///
726    /// #[model]
727    /// struct MyModel {
728    ///     #[model(primary_key)]
729    ///     id: i32,
730    /// };
731    ///
732    /// let expr = Expr::eq(Expr::field("id"), Expr::value(5));
733    ///
734    /// assert_eq!(
735    ///     <Query<MyModel>>::new().filter(expr),
736    ///     query!(MyModel, $id == 5)
737    /// );
738    /// ```
739    #[must_use]
740    pub fn eq(lhs: Self, rhs: Self) -> Self {
741        Self::Eq(Box::new(lhs), Box::new(rhs))
742    }
743
744    /// Create a new `!=` expression.
745    ///
746    /// # Example
747    ///
748    /// ```
749    /// use cot::db::{model, query};
750    /// use cot::db::query::{Expr, Query};
751    ///
752    /// #[model]
753    /// struct MyModel {
754    ///     #[model(primary_key)]
755    ///     id: i32,
756    /// };
757    ///
758    /// let expr = Expr::ne(Expr::field("id"), Expr::value(5));
759    ///
760    /// assert_eq!(
761    ///     <Query<MyModel>>::new().filter(expr),
762    ///     query!(MyModel, $id != 5)
763    /// );
764    /// ```
765    #[must_use]
766    pub fn ne(lhs: Self, rhs: Self) -> Self {
767        Self::Ne(Box::new(lhs), Box::new(rhs))
768    }
769
770    /// Create a new `<` expression.
771    ///
772    /// # Example
773    ///
774    /// ```
775    /// use cot::db::{model, query};
776    /// use cot::db::query::{Expr, Query};
777    ///
778    /// #[model]
779    /// struct MyModel {
780    ///     #[model(primary_key)]
781    ///     id: i32,
782    /// };
783    ///
784    /// let expr = Expr::lt(Expr::field("id"), Expr::value(5));
785    ///
786    /// assert_eq!(
787    ///     <Query<MyModel>>::new().filter(expr),
788    ///     query!(MyModel, $id < 5)
789    /// );
790    /// ```
791    #[must_use]
792    pub fn lt(lhs: Self, rhs: Self) -> Self {
793        Self::Lt(Box::new(lhs), Box::new(rhs))
794    }
795
796    /// Create a new `<=` expression.
797    ///
798    /// # Example
799    ///
800    /// ```
801    /// use cot::db::{model, query};
802    /// use cot::db::query::{Expr, Query};
803    ///
804    /// #[model]
805    /// struct MyModel {
806    ///     #[model(primary_key)]
807    ///     id: i32,
808    /// };
809    ///
810    /// let expr = Expr::lte(Expr::field("id"), Expr::value(5));
811    ///
812    /// assert_eq!(
813    ///     <Query<MyModel>>::new().filter(expr),
814    ///     query!(MyModel, $id <= 5)
815    /// );
816    /// ```
817    #[must_use]
818    pub fn lte(lhs: Self, rhs: Self) -> Self {
819        Self::Lte(Box::new(lhs), Box::new(rhs))
820    }
821
822    /// Create a new `>` expression.
823    ///
824    /// # Example
825    ///
826    /// ```
827    /// use cot::db::{model, query};
828    /// use cot::db::query::{Expr, Query};
829    ///
830    /// #[model]
831    /// struct MyModel {
832    ///     #[model(primary_key)]
833    ///     id: i32,
834    /// };
835    ///
836    /// let expr = Expr::gt(Expr::field("id"), Expr::value(5));
837    ///
838    /// assert_eq!(
839    ///     <Query<MyModel>>::new().filter(expr),
840    ///     query!(MyModel, $id > 5)
841    /// );
842    /// ```
843    #[must_use]
844    pub fn gt(lhs: Self, rhs: Self) -> Self {
845        Self::Gt(Box::new(lhs), Box::new(rhs))
846    }
847
848    /// Create a new `>=` expression.
849    ///
850    /// # Example
851    ///
852    /// ```
853    /// use cot::db::{model, query};
854    /// use cot::db::query::{Expr, Query};
855    ///
856    /// #[model]
857    /// struct MyModel {
858    ///     #[model(primary_key)]
859    ///     id: i32,
860    /// };
861    ///
862    /// let expr = Expr::gte(Expr::field("id"), Expr::value(5));
863    ///
864    /// assert_eq!(
865    ///     <Query<MyModel>>::new().filter(expr),
866    ///     query!(MyModel, $id >= 5)
867    /// );
868    /// ```
869    #[must_use]
870    pub fn gte(lhs: Self, rhs: Self) -> Self {
871        Self::Gte(Box::new(lhs), Box::new(rhs))
872    }
873
874    /// Create a new `+` expression.
875    ///
876    /// # Example
877    ///
878    /// ```
879    /// use cot::db::{model, query};
880    /// use cot::db::query::{Expr, Query};
881    ///
882    /// #[model]
883    /// struct MyModel {
884    ///     #[model(primary_key)]
885    ///     id: i32,
886    ///     id_2: i32,
887    /// };
888    ///
889    /// let expr = Expr::eq(Expr::field("id"), Expr::add(Expr::field("id_2"), Expr::value(5)));
890    ///
891    /// assert_eq!(
892    ///     <Query<MyModel>>::new().filter(expr),
893    ///     query!(MyModel, $id == $id_2 + 5)
894    /// );
895    /// ```
896    #[expect(clippy::should_implement_trait)]
897    #[must_use]
898    pub fn add(lhs: Self, rhs: Self) -> Self {
899        Self::Add(Box::new(lhs), Box::new(rhs))
900    }
901
902    /// Create a new `-` expression.
903    ///
904    /// # Example
905    ///
906    /// ```
907    /// use cot::db::{model, query};
908    /// use cot::db::query::{Expr, Query};
909    ///
910    /// #[model]
911    /// struct MyModel {
912    ///     #[model(primary_key)]
913    ///     id: i32,
914    ///     id_2: i32,
915    /// };
916    ///
917    /// let expr = Expr::eq(Expr::field("id"), Expr::sub(Expr::field("id_2"), Expr::value(5)));
918    ///
919    /// assert_eq!(
920    ///     <Query<MyModel>>::new().filter(expr),
921    ///     query!(MyModel, $id == $id_2 - 5)
922    /// );
923    /// ```
924    #[expect(clippy::should_implement_trait)]
925    #[must_use]
926    pub fn sub(lhs: Self, rhs: Self) -> Self {
927        Self::Sub(Box::new(lhs), Box::new(rhs))
928    }
929
930    /// Create a new `*` expression.
931    ///
932    /// # Example
933    ///
934    /// ```
935    /// use cot::db::{model, query};
936    /// use cot::db::query::{Expr, Query};
937    ///
938    /// #[model]
939    /// struct MyModel {
940    ///     #[model(primary_key)]
941    ///     id: i32,
942    ///     id_2: i32,
943    /// };
944    ///
945    /// let expr = Expr::eq(Expr::field("id"), Expr::mul(Expr::field("id_2"), Expr::value(2)));
946    ///
947    /// assert_eq!(
948    ///     <Query<MyModel>>::new().filter(expr),
949    ///     query!(MyModel, $id == $id_2 * 2)
950    /// );
951    /// ```
952    #[expect(clippy::should_implement_trait)]
953    #[must_use]
954    pub fn mul(lhs: Self, rhs: Self) -> Self {
955        Self::Mul(Box::new(lhs), Box::new(rhs))
956    }
957
958    /// Create a new `/` expression.
959    ///
960    /// # Example
961    ///
962    /// ```
963    /// use cot::db::{model, query};
964    /// use cot::db::query::{Expr, Query};
965    ///
966    /// #[model]
967    /// struct MyModel {
968    ///     #[model(primary_key)]
969    ///     id: i32,
970    ///     id_2: i32,
971    /// };
972    ///
973    /// let expr = Expr::eq(Expr::field("id"), Expr::div(Expr::field("id_2"), Expr::value(2)));
974    ///
975    /// assert_eq!(
976    ///     <Query<MyModel>>::new().filter(expr),
977    ///     query!(MyModel, $id == $id_2 / 2)
978    /// );
979    /// ```
980    #[expect(clippy::should_implement_trait)]
981    #[must_use]
982    pub fn div(lhs: Self, rhs: Self) -> Self {
983        Self::Div(Box::new(lhs), Box::new(rhs))
984    }
985
986    /// Returns the expression as a [`sea_query::SimpleExpr`].
987    ///
988    /// # Example
989    ///
990    /// ```
991    /// use cot::db::Identifier;
992    /// use cot::db::query::Expr;
993    /// use sea_query::IntoColumnRef;
994    ///
995    /// let expr = Expr::eq(Expr::field("id"), Expr::value(5));
996    ///
997    /// assert_eq!(
998    ///     expr.as_sea_query_expr(),
999    ///     sea_query::SimpleExpr::eq(
1000    ///         sea_query::SimpleExpr::Column(Identifier::new("id").into_column_ref()),
1001    ///         sea_query::SimpleExpr::Value(sea_query::Value::Int(Some(5)))
1002    ///     )
1003    /// );
1004    /// ```
1005    #[must_use]
1006    pub fn as_sea_query_expr(&self) -> sea_query::SimpleExpr {
1007        match self {
1008            Self::Field(identifier) => (*identifier).into_column_ref().into(),
1009            Self::Value(value) => (*value).clone().into(),
1010            Self::And(lhs, rhs) => lhs.as_sea_query_expr().and(rhs.as_sea_query_expr()),
1011            Self::Or(lhs, rhs) => lhs.as_sea_query_expr().or(rhs.as_sea_query_expr()),
1012            Self::Eq(lhs, rhs) => lhs.as_sea_query_expr().eq(rhs.as_sea_query_expr()),
1013            Self::Ne(lhs, rhs) => lhs.as_sea_query_expr().ne(rhs.as_sea_query_expr()),
1014            Self::Lt(lhs, rhs) => lhs.as_sea_query_expr().lt(rhs.as_sea_query_expr()),
1015            Self::Lte(lhs, rhs) => lhs.as_sea_query_expr().lte(rhs.as_sea_query_expr()),
1016            Self::Gt(lhs, rhs) => lhs.as_sea_query_expr().gt(rhs.as_sea_query_expr()),
1017            Self::Gte(lhs, rhs) => lhs.as_sea_query_expr().gte(rhs.as_sea_query_expr()),
1018            Self::Add(lhs, rhs) => lhs.as_sea_query_expr().add(rhs.as_sea_query_expr()),
1019            Self::Sub(lhs, rhs) => lhs.as_sea_query_expr().sub(rhs.as_sea_query_expr()),
1020            Self::Mul(lhs, rhs) => lhs.as_sea_query_expr().mul(rhs.as_sea_query_expr()),
1021            Self::Div(lhs, rhs) => lhs.as_sea_query_expr().div(rhs.as_sea_query_expr()),
1022        }
1023    }
1024}
1025
1026/// A reference to a field in a database table.
1027///
1028/// This is used to create expressions that reference a specific column in a
1029/// table with a specific type. This allows for type-safe creation of queries
1030/// with some common operators like `=`, `!=`, `+`, `-`, `*`, and `/`.
1031#[derive(Debug)]
1032pub struct FieldRef<T> {
1033    identifier: Identifier,
1034    phantom_data: PhantomData<T>,
1035}
1036
1037impl<T: FromDbValue + ToDbFieldValue> FieldRef<T> {
1038    /// Create a new field reference.
1039    #[must_use]
1040    pub const fn new(identifier: Identifier) -> Self {
1041        Self {
1042            identifier,
1043            phantom_data: PhantomData,
1044        }
1045    }
1046}
1047
1048impl<T> FieldRef<T> {
1049    /// Returns the field reference as an [`Expr`].
1050    #[must_use]
1051    pub fn as_expr(&self) -> Expr {
1052        Expr::Field(self.identifier)
1053    }
1054}
1055
1056/// A trait for types that can be compared in database expressions.
1057pub trait ExprEq<T> {
1058    /// Creates an expression that checks if the field is equal to the given
1059    /// value.
1060    ///
1061    /// # Examples
1062    ///
1063    /// ```
1064    /// use cot::db::query::{Expr, ExprEq, Query};
1065    /// use cot::db::{model, query};
1066    ///
1067    /// #[model]
1068    /// struct MyModel {
1069    ///     #[model(primary_key)]
1070    ///     id: i32,
1071    /// };
1072    ///
1073    /// let expr = <MyModel as cot::db::Model>::Fields::id.eq(5);
1074    ///
1075    /// assert_eq!(
1076    ///     <Query<MyModel>>::new().filter(expr),
1077    ///     query!(MyModel, $id == 5)
1078    /// );
1079    /// ```
1080    fn eq<V: IntoField<T>>(self, other: V) -> Expr;
1081
1082    /// Creates an expression that checks if the field is not equal to the given
1083    /// value.
1084    ///
1085    /// # Examples
1086    ///
1087    /// ```
1088    /// use cot::db::query::{Expr, ExprEq, Query};
1089    /// use cot::db::{model, query};
1090    ///
1091    /// #[model]
1092    /// struct MyModel {
1093    ///     #[model(primary_key)]
1094    ///     id: i32,
1095    /// };
1096    ///
1097    /// let expr = <MyModel as cot::db::Model>::Fields::id.ne(5);
1098    ///
1099    /// assert_eq!(
1100    ///     <Query<MyModel>>::new().filter(expr),
1101    ///     query!(MyModel, $id != 5)
1102    /// );
1103    /// ```
1104    fn ne<V: IntoField<T>>(self, other: V) -> Expr;
1105}
1106
1107impl<T: ToDbFieldValue + 'static> ExprEq<T> for FieldRef<T> {
1108    fn eq<V: IntoField<T>>(self, other: V) -> Expr {
1109        Expr::eq(self.as_expr(), Expr::value(other.into_field()))
1110    }
1111
1112    fn ne<V: IntoField<T>>(self, other: V) -> Expr {
1113        Expr::ne(self.as_expr(), Expr::value(other.into_field()))
1114    }
1115}
1116
1117/// A trait for database types that can be added to each other.
1118pub trait ExprAdd<T> {
1119    /// Creates an expression that adds the field to the given value.
1120    ///
1121    /// # Examples
1122    ///
1123    /// ```
1124    /// use cot::db::query::{Expr, ExprAdd, Query};
1125    /// use cot::db::{model, query};
1126    ///
1127    /// #[model]
1128    /// struct MyModel {
1129    ///     #[model(primary_key)]
1130    ///     id: i32,
1131    /// };
1132    ///
1133    /// let expr = <MyModel as cot::db::Model>::Fields::id.add(5);
1134    ///
1135    /// assert_eq!(
1136    ///     <Query<MyModel>>::new().filter(Expr::eq(Expr::field("id"), expr)),
1137    ///     query!(MyModel, $id == $id + 5)
1138    /// );
1139    /// ```
1140    fn add<V: Into<T>>(self, other: V) -> Expr;
1141}
1142
1143/// A trait for database types that can be subtracted from each other.
1144pub trait ExprSub<T> {
1145    /// Creates an expression that subtracts the field from the given value.
1146    ///
1147    /// # Examples
1148    ///
1149    /// ```
1150    /// use cot::db::query::{Expr, ExprSub, Query};
1151    /// use cot::db::{model, query};
1152    ///
1153    /// #[model]
1154    /// struct MyModel {
1155    ///     #[model(primary_key)]
1156    ///     id: i32,
1157    /// };
1158    ///
1159    /// let expr = <MyModel as cot::db::Model>::Fields::id.sub(5);
1160    ///
1161    /// assert_eq!(
1162    ///     <Query<MyModel>>::new().filter(Expr::eq(Expr::field("id"), expr)),
1163    ///     query!(MyModel, $id == $id - 5)
1164    /// );
1165    /// ```
1166    fn sub<V: Into<T>>(self, other: V) -> Expr;
1167}
1168
1169/// A trait for database types that can be multiplied by each other.
1170pub trait ExprMul<T> {
1171    /// Creates an expression that multiplies the field by the given value.
1172    ///
1173    /// # Examples
1174    ///
1175    /// ```
1176    /// use cot::db::query::{Expr, ExprMul, Query};
1177    /// use cot::db::{model, query};
1178    ///
1179    /// #[model]
1180    /// struct MyModel {
1181    ///     #[model(primary_key)]
1182    ///     id: i32,
1183    /// };
1184    ///
1185    /// let expr = <MyModel as cot::db::Model>::Fields::id.mul(2);
1186    ///
1187    /// assert_eq!(
1188    ///     <Query<MyModel>>::new().filter(Expr::eq(Expr::field("id"), expr)),
1189    ///     query!(MyModel, $id == $id * 2)
1190    /// );
1191    /// ```
1192    fn mul<V: Into<T>>(self, other: V) -> Expr;
1193}
1194
1195/// A trait for database types that can be divided by each other.
1196pub trait ExprDiv<T> {
1197    /// Creates an expression that divides the field by the given value.
1198    ///
1199    /// # Examples
1200    ///
1201    /// ```
1202    /// use cot::db::query::{Expr, ExprDiv, Query};
1203    /// use cot::db::{model, query};
1204    ///
1205    /// #[model]
1206    /// struct MyModel {
1207    ///     #[model(primary_key)]
1208    ///     id: i32,
1209    /// };
1210    ///
1211    /// let expr = <MyModel as cot::db::Model>::Fields::id.div(2);
1212    ///
1213    /// assert_eq!(
1214    ///     <Query<MyModel>>::new().filter(Expr::eq(Expr::field("id"), expr)),
1215    ///     query!(MyModel, $id == $id / 2)
1216    /// );
1217    /// ```
1218    fn div<V: Into<T>>(self, other: V) -> Expr;
1219}
1220
1221/// A trait for database types that can be ordered.
1222pub trait ExprOrd<T> {
1223    /// Creates an expression that checks if the field is less than the given
1224    /// value.
1225    ///
1226    /// # Examples
1227    ///
1228    /// ```
1229    /// use cot::db::query::{Expr, ExprOrd, Query};
1230    /// use cot::db::{model, query};
1231    ///
1232    /// #[model]
1233    /// struct MyModel {
1234    ///     #[model(primary_key)]
1235    ///     id: i32,
1236    /// };
1237    ///
1238    /// let expr = <MyModel as cot::db::Model>::Fields::id.lt(5);
1239    ///
1240    /// assert_eq!(
1241    ///     <Query<MyModel>>::new().filter(expr),
1242    ///     query!(MyModel, $id < 5)
1243    /// );
1244    /// ```
1245    fn lt<V: IntoField<T>>(self, other: V) -> Expr;
1246    /// Creates an expression that checks if the field is less than or equal to
1247    /// the given value.
1248    ///
1249    /// # Examples
1250    ///
1251    /// ```
1252    /// use cot::db::query::{Expr, ExprOrd, Query};
1253    /// use cot::db::{model, query};
1254    ///
1255    /// #[model]
1256    /// struct MyModel {
1257    ///     #[model(primary_key)]
1258    ///     id: i32,
1259    /// };
1260    ///
1261    /// let expr = <MyModel as cot::db::Model>::Fields::id.lte(5);
1262    ///
1263    /// assert_eq!(
1264    ///     <Query<MyModel>>::new().filter(expr),
1265    ///     query!(MyModel, $id <= 5)
1266    /// );
1267    /// ```
1268    fn lte<V: IntoField<T>>(self, other: V) -> Expr;
1269
1270    /// Creates an expression that checks if the field is greater than the given
1271    /// value.
1272    ///
1273    /// # Examples
1274    ///
1275    /// ```
1276    /// use cot::db::query::{Expr, ExprOrd, Query};
1277    /// use cot::db::{model, query};
1278    ///
1279    /// #[model]
1280    /// struct MyModel {
1281    ///     #[model(primary_key)]
1282    ///     id: i32,
1283    /// };
1284    ///
1285    /// let expr = <MyModel as cot::db::Model>::Fields::id.gt(5);
1286    ///
1287    /// assert_eq!(
1288    ///     <Query<MyModel>>::new().filter(expr),
1289    ///     query!(MyModel, $id > 5)
1290    /// );
1291    /// ```
1292    fn gt<V: IntoField<T>>(self, other: V) -> Expr;
1293
1294    /// Creates an expression that checks if the field is greater than or equal
1295    /// to the given value.
1296    ///
1297    /// # Examples
1298    ///
1299    /// ```
1300    /// use cot::db::query::{Expr, ExprOrd, Query};
1301    /// use cot::db::{model, query};
1302    ///
1303    /// #[model]
1304    /// struct MyModel {
1305    ///     #[model(primary_key)]
1306    ///     id: i32,
1307    /// };
1308    ///
1309    /// let expr = <MyModel as cot::db::Model>::Fields::id.gte(5);
1310    ///
1311    /// assert_eq!(
1312    ///     <Query<MyModel>>::new().filter(expr),
1313    ///     query!(MyModel, $id >= 5)
1314    /// );
1315    /// ```
1316    fn gte<V: IntoField<T>>(self, other: V) -> Expr;
1317}
1318
1319impl<T: ToDbFieldValue + Ord + 'static> ExprOrd<T> for FieldRef<T> {
1320    fn lt<V: IntoField<T>>(self, other: V) -> Expr {
1321        Expr::lt(self.as_expr(), Expr::value(other.into_field()))
1322    }
1323
1324    fn lte<V: IntoField<T>>(self, other: V) -> Expr {
1325        Expr::lte(self.as_expr(), Expr::value(other.into_field()))
1326    }
1327
1328    fn gt<V: IntoField<T>>(self, other: V) -> Expr {
1329        Expr::gt(self.as_expr(), Expr::value(other.into_field()))
1330    }
1331
1332    fn gte<V: IntoField<T>>(self, other: V) -> Expr {
1333        Expr::gte(self.as_expr(), Expr::value(other.into_field()))
1334    }
1335}
1336
1337macro_rules! impl_expr {
1338    ($ty:ty, $trait:ident, $method:ident) => {
1339        impl $trait<$ty> for FieldRef<$ty> {
1340            fn $method<V: Into<$ty>>(self, other: V) -> Expr {
1341                Expr::$method(self.as_expr(), Expr::value(other.into()))
1342            }
1343        }
1344    };
1345}
1346
1347macro_rules! impl_num_expr {
1348    ($ty:ty) => {
1349        impl_expr!($ty, ExprAdd, add);
1350        impl_expr!($ty, ExprSub, sub);
1351        impl_expr!($ty, ExprMul, mul);
1352        impl_expr!($ty, ExprDiv, div);
1353    };
1354}
1355
1356impl_num_expr!(i8);
1357impl_num_expr!(i16);
1358impl_num_expr!(i32);
1359impl_num_expr!(i64);
1360impl_num_expr!(u8);
1361impl_num_expr!(u16);
1362impl_num_expr!(u32);
1363impl_num_expr!(u64);
1364impl_num_expr!(f32);
1365impl_num_expr!(f64);
1366
1367/// A trait for database types that can be converted to the field type.
1368///
1369/// This trait is mostly a helper trait to make comparisons like `$id == 5`
1370/// where `id` is of type [`Auto`] or [`ForeignKey`] easier to write and more
1371/// readable.
1372///
1373/// # Example
1374///
1375/// ```
1376/// use cot::db::query::{Expr, ExprEq, Query};
1377/// use cot::db::{Auto, model, query};
1378///
1379/// #[model]
1380/// struct MyModel {
1381///     #[model(primary_key)]
1382///     id: Auto<i32>,
1383/// };
1384///
1385/// // uses the `IntoField` trait to convert the `5` to `Auto<i32>`
1386/// let expr = <MyModel as cot::db::Model>::Fields::id.eq(5);
1387/// ```
1388pub trait IntoField<T> {
1389    /// Converts the type to the field type.
1390    fn into_field(self) -> T;
1391}
1392
1393impl<T: ToDbFieldValue> IntoField<T> for T {
1394    fn into_field(self) -> T {
1395        self
1396    }
1397}
1398
1399impl<T> IntoField<Auto<T>> for T {
1400    fn into_field(self) -> Auto<T> {
1401        Auto::fixed(self)
1402    }
1403}
1404
1405impl IntoField<String> for &str {
1406    fn into_field(self) -> String {
1407        self.to_string()
1408    }
1409}
1410
1411impl<T: Model + Send + Sync> IntoField<ForeignKey<T>> for T {
1412    fn into_field(self) -> ForeignKey<T> {
1413        ForeignKey::from(self)
1414    }
1415}
1416
1417impl<T: Model + Send + Sync> IntoField<ForeignKey<T>> for &T {
1418    fn into_field(self) -> ForeignKey<T> {
1419        ForeignKey::from(self)
1420    }
1421}
1422
1423#[cfg(test)]
1424mod tests {
1425    use cot_macros::model;
1426
1427    use super::*;
1428    use crate::db::{MockDatabaseBackend, RowsNum};
1429
1430    #[model]
1431    #[derive(std::fmt::Debug, PartialEq, Eq)]
1432    struct MockModel {
1433        #[model(primary_key)]
1434        id: i32,
1435    }
1436
1437    #[test]
1438    fn query_new() {
1439        let query: Query<MockModel> = Query::new();
1440
1441        assert!(query.filter.is_none());
1442        assert!(query.limit.is_none());
1443        assert!(query.offset.is_none());
1444    }
1445
1446    #[test]
1447    fn query_default() {
1448        let query: Query<MockModel> = Query::default();
1449
1450        assert!(query.filter.is_none());
1451        assert!(query.limit.is_none());
1452        assert!(query.offset.is_none());
1453    }
1454
1455    #[test]
1456    fn query_filter() {
1457        let mut query: Query<MockModel> = Query::new();
1458
1459        query.filter(Expr::eq(Expr::field("name"), Expr::value("John")));
1460
1461        assert!(query.filter.is_some());
1462    }
1463
1464    #[test]
1465    fn query_limit() {
1466        let mut query: Query<MockModel> = Query::new();
1467        query.limit(10);
1468        assert!(query.limit.is_some());
1469        assert_eq!(query.limit.unwrap(), 10);
1470    }
1471
1472    #[test]
1473    fn query_offset() {
1474        let mut query: Query<MockModel> = Query::new();
1475        query.offset(10);
1476        assert!(query.offset.is_some());
1477        assert_eq!(query.offset.unwrap(), 10);
1478    }
1479
1480    #[cot::test]
1481    async fn query_all() {
1482        let mut db = MockDatabaseBackend::new();
1483        db.expect_query().returning(|_| Ok(Vec::<MockModel>::new()));
1484        let query: Query<MockModel> = Query::new();
1485
1486        let result = query.all(&db).await;
1487
1488        assert_eq!(result.unwrap(), Vec::<MockModel>::new());
1489    }
1490
1491    #[cot::test]
1492    async fn query_get() {
1493        let mut db = MockDatabaseBackend::new();
1494        db.expect_get().returning(|_| Ok(Option::<MockModel>::None));
1495        let query: Query<MockModel> = Query::new();
1496
1497        let result = query.get(&db).await;
1498
1499        assert_eq!(result.unwrap(), Option::<MockModel>::None);
1500    }
1501
1502    #[cot::test]
1503    async fn query_exists() {
1504        let mut db = MockDatabaseBackend::new();
1505        db.expect_exists()
1506            .returning(|_: &Query<MockModel>| Ok(false));
1507
1508        let query: Query<MockModel> = Query::new();
1509
1510        let result = query.exists(&db).await;
1511        assert!(result.is_ok());
1512    }
1513
1514    #[cot::test]
1515    async fn query_delete() {
1516        let mut db = MockDatabaseBackend::new();
1517        db.expect_delete()
1518            .returning(|_: &Query<MockModel>| Ok(StatementResult::new(RowsNum(0))));
1519        let query: Query<MockModel> = Query::new();
1520
1521        let result = query.delete(&db).await;
1522
1523        assert!(result.is_ok());
1524    }
1525
1526    #[test]
1527    fn expr_field() {
1528        let expr = Expr::field("name");
1529        if let Expr::Field(identifier) = expr {
1530            assert_eq!(identifier.to_string(), "name");
1531        } else {
1532            panic!("Expected Expr::Field");
1533        }
1534    }
1535
1536    #[test]
1537    fn expr_value() {
1538        let expr = Expr::value(30);
1539        if let Expr::Value(value) = expr {
1540            assert_eq!(value.to_string(), "30");
1541        } else {
1542            panic!("Expected Expr::Value");
1543        }
1544    }
1545
1546    macro_rules! test_expr_constructor {
1547        ($test_name:ident, $match:ident, $constructor:ident) => {
1548            #[test]
1549            fn $test_name() {
1550                let expr = Expr::$constructor(Expr::field("name"), Expr::value("John"));
1551                if let Expr::$match(lhs, rhs) = expr {
1552                    assert!(matches!(*lhs, Expr::Field(_)));
1553                    assert!(matches!(*rhs, Expr::Value(_)));
1554                } else {
1555                    panic!(concat!("Expected Expr::", stringify!($match)));
1556                }
1557            }
1558        };
1559    }
1560
1561    test_expr_constructor!(expr_and, And, and);
1562    test_expr_constructor!(expr_or, Or, or);
1563    test_expr_constructor!(expr_eq, Eq, eq);
1564    test_expr_constructor!(expr_ne, Ne, ne);
1565    test_expr_constructor!(expr_lt, Lt, lt);
1566    test_expr_constructor!(expr_lte, Lte, lte);
1567    test_expr_constructor!(expr_gt, Gt, gt);
1568    test_expr_constructor!(expr_gte, Gte, gte);
1569    test_expr_constructor!(expr_add, Add, add);
1570    test_expr_constructor!(expr_sub, Sub, sub);
1571    test_expr_constructor!(expr_mul, Mul, mul);
1572    test_expr_constructor!(expr_div, Div, div);
1573}