1use std::{marker::PhantomData, fmt::Debug, ops::{BitAnd, BitOr}};
2
3use rusqlite::ToSql;
4
5use crate::{connection::{Queryable, RawQuery, IntoInsertable, Insertable, Executable}, IntoSqlite};
6
7use super::{Model, column::Column};
8
9pub struct CountQuery;
11
12pub struct ModelQuery<M> {
25 model: PhantomData<M>,
26 table_name: String,
27 query: String,
28 joins: Vec<String>,
29 params: Vec<Box<dyn ToSql>>,
30}
31
32impl<M: Model> Debug for ModelQuery<M> {
33 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34 f.debug_struct("ModelQuery")
35 .field("query", &self.query)
36 .finish()
37 }
38}
39
40impl<M> Default for ModelQuery<M> {
41 fn default() -> Self {
42 Self {
43 model: Default::default(),
44 table_name: "unknown".to_string(),
45 query: String::new(),
46 joins: Vec::new(),
47 params: Vec::new(),
48 }
49 }
50}
51
52impl<M: Model> ModelQuery<M> {
54 pub fn select() -> Self {
56 let query = format!("SELECT * FROM {}", M::table_name());
57 ModelQuery {
58 model: PhantomData,
59 table_name: M::table_name().to_string(),
60 query,
61 ..Default::default()
62 }
63 }
64
65 pub fn count() -> ModelQuery<CountQuery> {
66 let query = format!("SELECT COUNT(*) FROM {}", M::table_name());
67 ModelQuery {
68 model: PhantomData,
69 table_name: M::table_name().to_string(),
70 query,
71 ..Default::default()
72 }
73 }
74}
75
76impl<M> ModelQuery<M> {
78
79 pub fn combine(self, query: String, params: Vec<Box<dyn ToSql>>) -> Self {
81 let mut params_old = self.params;
82 params_old.extend(params);
83 ModelQuery {
84 model: PhantomData,
85 table_name: self.table_name,
86 query: format!("{} {}", self.query, query),
87 joins: self.joins,
88 params: params_old,
89 }
90 }
91
92 pub fn filter(self, mut filter: impl ModelQueryFilter) -> Self {
105 let filter_query = filter.get_query();
106 ModelQuery::combine(self, format!("WHERE {}", filter_query.sql), filter_query.params)
107 }
108
109 pub fn with_id(self, id: i64) -> Self {
124 let table_name = self.table_name.clone();
125 ModelQuery::combine(self, format!("WHERE {}.id = ? LIMIT 1", table_name), vec![Box::new(id)])
126 }
127
128 pub fn limit(self, limit: u32) -> Self {
140 ModelQuery::combine(self, "LIMIT ?".to_string(), vec![Box::new(limit)])
141 }
142
143 pub fn offset(self, offset: u32) -> Self {
155 ModelQuery::combine(self, "OFFSET ?".to_string(), vec![Box::new(offset)])
156 }
157
158 pub fn order_by(self, order: ColumnQueryOrder) -> Self {
170 ModelQuery::combine(self, format!("ORDER BY {}", order.into_sqlite()), Vec::new())
171 }
172
173 pub fn join_relation(mut self, relation: Column<'static>) -> Self {
186 match relation.get_relation() {
188 Some(relation) => {
189 let query = format!("{} LEFT JOIN {} ON {}.{} = {}.{}", self.query, relation.table, relation.table, relation.foreign_key_column.name_const(), relation.local_table, relation.local_key_column_name );
191
192 self.joins.push(relation.local_key_column_name.to_string());
193 ModelQuery {
195 model: PhantomData,
196 table_name: self.table_name,
197 query,
198 joins: self.joins,
199 params: self.params,
200 }
201 },
202 None => panic!("Cannot join a non-relation column"),
203 }
204 }
205
206 pub fn columns(self, columns: &[Column<'static>]) -> Self {
218 let columns = columns.iter().map(|c| c.name()).collect::<Vec<_>>().join(", ");
219 let query = self.query.replacen('*', &columns, 1);
221 ModelQuery {
222 model: PhantomData,
223 table_name: self.table_name,
224 query,
225 joins: self.joins,
226 params: self.params,
227 }
228 }
229}
230
231impl<M: Model> Queryable<Vec<M>> for ModelQuery<M> {
232 fn get_query(&mut self) -> crate::connection::RawQuery {
233 crate::connection::RawQuery::new(self.query.clone(), self.params.drain(..).collect())
234 }
235
236 fn parse_result(&mut self, rows: rusqlite::Rows) -> Vec<M> {
237 M::parse_rows(rows, 0, &self.joins)
238 }
239}
240
241impl<M: Model> Executable<Vec<M>> for ModelQuery<M> {
242 fn exec(self, conn: &crate::prelude::Connection) -> Result<Vec<M>, rusqlite::Error> {
243 conn.query(self)
244 }
245}
246
247impl Queryable<usize> for ModelQuery<CountQuery> {
248 fn get_query(&mut self) -> crate::connection::RawQuery {
249 crate::connection::RawQuery::new(self.query.clone(), self.params.drain(..).collect())
250 }
251
252 fn parse_result(&mut self, mut rows: rusqlite::Rows) -> usize {
253 rows.next().unwrap().unwrap().get(0).unwrap()
254 }
255}
256
257impl Executable<usize> for ModelQuery<CountQuery> {
258 fn exec(self, conn: &crate::prelude::Connection) -> Result<usize, rusqlite::Error> {
259 conn.query(self)
260 }
261}
262
263pub trait ModelQueryFilter {
264 fn get_query(&mut self) -> crate::connection::RawQuery;
265}
266
267pub struct InQueryFilter {
268 sql: RawQuery,
269}
270
271impl ModelQueryFilter for InQueryFilter {
272 fn get_query(&mut self) -> RawQuery {
273 self.sql.move_clone()
274 }
275}
276
277pub struct ColumnQueryFilter {
278 column: String,
279 value: Option<Box<dyn ToSql>>,
280 op: &'static str,
281}
282
283impl ModelQueryFilter for ColumnQueryFilter {
284 fn get_query(&mut self) -> RawQuery {
285 let sql = format!("{} {} ?", self.column, self.op);
286 let params = vec![self.value.take().unwrap()];
287 RawQuery::new(sql, params)
288 }
289}
290
291pub struct ColumnQueryFilterUnary {
292 column: String,
293 op: &'static str,
294}
295
296impl ModelQueryFilter for ColumnQueryFilterUnary {
297 fn get_query(&mut self) -> RawQuery {
298 let sql = format!("{} {}", self.column, self.op);
299 RawQuery::new(sql, Vec::new())
300 }
301}
302
303macro_rules! trait_column_filter {
304 ($fn:ident) => {
305 fn $fn<V: ToSql + 'static>(self, value: V) -> ColumnQueryFilter;
306 };
307}
308
309macro_rules! impl_column_filter {
310 ($fn:ident, $op:literal, $doc:expr) => {
311 #[doc = $doc]
312 fn $fn<V: ToSql + 'static>(self, value: V) -> ColumnQueryFilter {
313 ColumnQueryFilter {
314 column: format!("{}.{}", self.table_name, self.name()),
315 op: $op,
316 value: Some(Box::new(value)),
317 }
318 }
319 };
320
321 ($fn:ident, $op:literal) => {
322 impl_column_filter!($fn, $op, "There is no documentation for this filter");
323 };
324}
325
326pub struct ColumnQueryOrder {
327 column: String,
328 order: ColumnQueryOrdering,
329}
330
331impl IntoSqlite for ColumnQueryOrder {
332 fn into_sqlite(&self) -> String {
333 format!("{} {}", self.column, self.order.into_sqlite())
334 }
335}
336
337pub enum ColumnQueryOrdering {
338 Ascending,
339 Descending,
340}
341
342impl IntoSqlite for ColumnQueryOrdering {
343 fn into_sqlite(&self) -> String {
344 match self {
345 ColumnQueryOrdering::Ascending => "ASC".to_string(),
346 ColumnQueryOrdering::Descending => "DESC".to_string(),
347 }
348 }
349}
350
351pub trait ColumnQueryFilterImpl {
352 trait_column_filter!(eq);
353 trait_column_filter!(ne);
354 trait_column_filter!(gt);
355 trait_column_filter!(lt);
356 trait_column_filter!(ge);
357 trait_column_filter!(le);
358
359 trait_column_filter!(like);
360 trait_column_filter!(not_like);
361
362 fn is_null(self) -> ColumnQueryFilterUnary;
363 fn is_not_null(self) -> ColumnQueryFilterUnary;
364
365 fn in_(self, values: impl ColumnInQuery) -> InQueryFilter;
366 fn not_in(self, values: impl ColumnInQuery) -> InQueryFilter;
367
368 fn asc(self) -> ColumnQueryOrder;
369 fn desc(self) -> ColumnQueryOrder;
370}
371
372impl ColumnQueryFilterImpl for Column<'_> {
373 impl_column_filter!(eq, "=", "
374 Checks if the column is equal to the given value.
375 ## Example
376 ```rust
377 User::select().filter(User::name.eq(\"John\")).exec(conn);
378 ```
379 This will generate the following SQL query:
380 ```sql
381 -- ? is a parameter
382 SELECT * FROM users WHERE users.name = ?;
383 ```
384 ");
385 impl_column_filter!(ne, "!=", "
386 Checks if the column is not equal to the given value.
387 ## Example
388 ```rust
389 User::select().filter(User::name.ne(\"John\")).exec(conn);
390 ```
391 This will generate the following SQL query:
392 ```sql
393 -- ? is a parameter
394 SELECT * FROM users WHERE users.name != ?;
395 ```
396 ");
397 impl_column_filter!(gt, ">", "
398 Checks if the column is greater than the given value.
399 ## Example
400 ```rust
401 User::select().filter(User::age.gt(18)).exec(conn);
402 ```
403 This will generate the following SQL query:
404 ```sql
405 -- ? is a parameter
406 SELECT * FROM users WHERE users.age > ?;
407 ```
408 ");
409 impl_column_filter!(lt, "<", "
410 Checks if the column is less than the given value.
411 ## Example
412 ```rust
413 User::select().filter(User::age.lt(18)).exec(conn);
414 ```
415 This will generate the following SQL query:
416 ```sql
417 -- ? is a parameter
418 SELECT * FROM users WHERE users.age < ?;
419 ```
420 ");
421 impl_column_filter!(ge, ">=", "
422 Checks if the column is greater than or equal to the given value.
423 ## Example
424 ```rust
425 User::select().filter(User::age.ge(18)).exec(conn);
426 ```
427 This will generate the following SQL query:
428 ```sql
429 -- ? is a parameter
430 SELECT * FROM users WHERE users.age >= ?;
431 ```
432 ");
433 impl_column_filter!(le, "<=", "
434 Checks if the column is less than or equal to the given value.
435 ## Example
436 ```rust
437 User::select().filter(User::age.le(18)).exec(conn);
438 ```
439 This will generate the following SQL query:
440 ```sql
441 -- ? is a parameter
442 SELECT * FROM users WHERE users.age <= ?;
443 ```
444 ");
445
446 impl_column_filter!(like, "LIKE", "
447 Checks if the column is like the given value.
448 ## Example
449 ```rust
450 User::select().filter(User::name.like(\"%John%\")).exec(conn);
451 ```
452 This will generate the following SQL query:
453 ```sql
454 -- ? is a parameter
455 SELECT * FROM users WHERE users.name LIKE ?;
456 ```
457 ");
458 impl_column_filter!(not_like, "NOT LIKE", "
459 Checks if the column is not like the given value.
460 ## Example
461 ```rust
462 User::select().filter(User::name.not_like(\"%John%\")).exec(conn);
463 ```
464 This will generate the following SQL query:
465 ```sql
466 SELECT * FROM users WHERE users.name NOT LIKE ?;
467 ```
468 ");
469
470 fn is_null(self) -> ColumnQueryFilterUnary {
480 ColumnQueryFilterUnary {
481 column: format!("{}.{}", self.table_name, self.name()),
482 op: "IS NULL",
483 }
484 }
485
486 fn is_not_null(self) -> ColumnQueryFilterUnary {
496 ColumnQueryFilterUnary {
497 column: format!("{}.{}", self.table_name, self.name()),
498 op: "IS NOT NULL",
499 }
500 }
501
502 fn in_(self, values: impl ColumnInQuery) -> InQueryFilter {
513 let q = values.to_query();
514 let sql = format!("{}.{} IN {}", self.table_name, self.name(), q.sql);
515
516 InQueryFilter { sql: RawQuery::new(sql, q.params) }
517 }
518
519 fn not_in(self, values: impl ColumnInQuery) -> InQueryFilter {
530 let q = values.to_query();
531 let sql = format!("{}.{} NOT IN {}", self.table_name, self.name(), q.sql);
532
533 InQueryFilter { sql: RawQuery::new(sql, q.params) }
534 }
535
536 fn asc(self) -> ColumnQueryOrder {
546 ColumnQueryOrder {
547 column: self.name(),
548 order: ColumnQueryOrdering::Ascending,
549 }
550 }
551
552 fn desc(self) -> ColumnQueryOrder {
562 ColumnQueryOrder {
563 column: self.name(),
564 order: ColumnQueryOrdering::Descending,
565 }
566 }
567}
568
569pub trait ColumnInQuery {
570 fn to_query(self) -> RawQuery;
571}
572
573impl<M: Model> ColumnInQuery for ModelQuery<M> {
574 fn to_query(mut self) -> RawQuery {
575 let mut query = self.get_query();
576 let sql = format!("({})", query.sql);
577 query.sql = sql;
578 query
579 }
580}
581
582impl<T: ToSql + 'static> ColumnInQuery for Vec<T> {
583 fn to_query(self) -> RawQuery {
584 let mut params = Vec::new();
585 let mut sql = String::from("(");
586
587 for (i, v) in self.into_iter().enumerate() {
588 if i > 0 {
589 sql.push_str(", ");
590 }
591
592 sql.push('?');
593 params.push(Box::new(v) as Box<dyn ToSql + 'static>);
594 }
595
596 sql.push(')');
597
598 RawQuery::new(sql, params)
599 }
600}
601
602impl<T: ToSql + 'static> ColumnInQuery for &'static [T] {
603 fn to_query(self) -> RawQuery {
604 let mut params = Vec::new();
605 let mut sql = String::from("(");
606
607 for (i, v) in self.iter().enumerate() {
608 if i > 0 {
609 sql.push_str(", ");
610 }
611
612 sql.push('?');
613 params.push(Box::new(v) as Box<dyn ToSql + 'static>);
614 }
615
616 sql.push(')');
617
618 RawQuery::new(sql, params)
619 }
620}
621impl<T: ToSql + 'static, const N: usize> ColumnInQuery for &'static [T; N] {
622 fn to_query(self) -> RawQuery {
623 let mut params = Vec::new();
624 let mut sql = String::from("(");
625
626 for (i, v) in self.iter().enumerate() {
627 if i > 0 {
628 sql.push_str(", ");
629 }
630
631 sql.push('?');
632 params.push(Box::new(v) as Box<dyn ToSql + 'static>);
633 }
634
635 sql.push(')');
636
637 RawQuery::new(sql, params)
638 }
639}
640
641pub trait ModelQueryFilterExt: ModelQueryFilter {
642 fn and<F: ModelQueryFilter>(self, filter: F) -> ModelQueryFilterAnd<Self, F>
643 where
644 Self: Sized;
645
646 fn or<F: ModelQueryFilter>(self, filter: F) -> ModelQueryFilterOr<Self, F>
647 where
648 Self: Sized;
649}
650
651impl<F: ModelQueryFilter> ModelQueryFilterExt for F {
652 fn and<F1: ModelQueryFilter>(self, filter: F1) -> ModelQueryFilterAnd<Self, F1>
668 where
669 Self: Sized,
670 {
671 ModelQueryFilterAnd {
672 filter0: self,
673 filter1: filter,
674 }
675 }
676
677 fn or<F1: ModelQueryFilter>(self, filter: F1) -> ModelQueryFilterOr<Self, F1>
693 where
694 Self: Sized,
695 {
696 ModelQueryFilterOr {
697 filter0: self,
698 filter1: filter,
699 }
700 }
701}
702
703pub struct ModelQueryFilterAnd<F0: ModelQueryFilter, F1: ModelQueryFilter> {
704 filter0: F0,
705 filter1: F1,
706}
707
708pub struct ModelQueryFilterOr<F0: ModelQueryFilter, F1: ModelQueryFilter> {
709 filter0: F0,
710 filter1: F1,
711}
712
713impl<F0: ModelQueryFilter, F1: ModelQueryFilter> ModelQueryFilter for ModelQueryFilterAnd<F0, F1> {
714 fn get_query(&mut self) -> crate::connection::RawQuery {
715 let mut query = self.filter0.get_query();
716 let mut query1 = self.filter1.get_query();
717 query.sql = format!("{} AND {}", query.sql, query1.sql);
718 query.params.append(&mut query1.params);
719 query
720 }
721}
722
723impl<F0: ModelQueryFilter, F1: ModelQueryFilter> ModelQueryFilter for ModelQueryFilterOr<F0, F1> {
724 fn get_query(&mut self) -> crate::connection::RawQuery {
725 let mut query = self.filter0.get_query();
726 let mut query1 = self.filter1.get_query();
727 query.sql = format!("{} OR {}", query.sql, query1.sql);
728 query.params.append(&mut query1.params);
729 query
730 }
731}
732
733macro_rules! impl_op {
734 ($op:ident ($fn:ident), $target:ident => $result:ident, $doc:expr) => {
735 impl<T: ModelQueryFilter> $op<T> for $target {
736 type Output = $result<Self, T>;
737
738 #[doc = $doc]
739 fn $fn(self, rhs: T) -> Self::Output {
740 $result {
741 filter0: self,
742 filter1: rhs,
743 }
744 }
745 }
746 };
747}
748
749impl_op!(BitAnd (bitand), ColumnQueryFilter => ModelQueryFilterAnd, "Alternative to [ModelQueryFilterExt::and]");
750impl_op!(BitOr (bitor), ColumnQueryFilter => ModelQueryFilterOr, "Alternative to [ModelQueryFilterExt::or]");
751
752impl_op!(BitAnd (bitand), InQueryFilter => ModelQueryFilterAnd, "Alternative to [ModelQueryFilterExt::and]");
753impl_op!(BitOr (bitor), InQueryFilter => ModelQueryFilterOr, "Alternative to [ModelQueryFilterExt::or]");
754
755impl_op!(BitAnd (bitand), ColumnQueryFilterUnary => ModelQueryFilterAnd, "Alternative to [ModelQueryFilterExt::and]");
756impl_op!(BitOr (bitor), ColumnQueryFilterUnary => ModelQueryFilterOr, "Alternative to [ModelQueryFilterExt::or]");
757
758
759pub struct ModelInsertQuery<M: Model> {
760 model: PhantomData<M>,
761 columns: Vec<String>,
762 values: Vec<Vec<Box<dyn ToSql>>>,
763}
764
765impl<M: Model> Insertable for ModelInsertQuery<M> {
766 fn get_query(&mut self) -> RawQuery {
767 let mut sql = format!("INSERT INTO {} (", M::table_name());
768 for column in &self.columns {
769 sql.push_str(column);
770 sql.push_str(", ");
771 }
772 sql.pop();
773 sql.pop();
774 sql.push_str(") VALUES ");
775
776 let mut params = Vec::new();
777 for values in &mut self.values {
778 sql.push('(');
779 for value in values.drain(..) {
780 sql.push_str("?, ");
781 params.push(value);
782 }
783 sql.pop();
784 sql.pop();
785 sql.push(')');
786 sql.push(',');
787 }
788 sql.pop();
789
790 RawQuery {
791 sql,
792 params,
793 }
794 }
795}
796
797impl<M: Model> IntoInsertable for M {
798 type Insertable = ModelInsertQuery<M>;
799
800 fn into_insertable(&self) -> ModelInsertQuery<M> {
801 let mut columns = Vec::new();
802 let mut values = Vec::new();
803 for column in M::columns() {
804 let cv = self.column_value(column);
805
806 if !column.can_insert_null() && cv.is_none() {
807 panic!("Column '{}' is not nullable", column.name());
808 }
809
810 if let Some(value) = cv {
811 columns.push(column.name().to_string());
812 values.push(value);
813 }
814 }
815
816 ModelInsertQuery {
817 model: PhantomData,
818 columns,
819 values: vec![values], }
821 }
822}
823
824impl<M: Model, const N: usize, I: IntoInsertable<Insertable = ModelInsertQuery<M>>> IntoInsertable for &[I; N] {
825 type Insertable = ModelInsertQuery<M>;
826
827 fn into_insertable(&self) -> Self::Insertable {
828 let mut columns = Vec::new();
829 let mut values = Vec::new();
830
831 for v in self.iter() {
832 let mut insertable = v.into_insertable();
833
834 if columns.is_empty() {
835 columns.append(&mut insertable.columns);
836 } else {
837 assert_eq!(columns, insertable.columns);
838 }
839
840 let v = insertable.values.pop().unwrap();
841 values.push(v);
842 }
843
844 ModelInsertQuery {
845 model: PhantomData,
846 columns,
847 values,
848 }
849 }
850}
851
852impl<M: Model, I: IntoInsertable<Insertable = ModelInsertQuery<M>>> IntoInsertable for &[I] {
853 type Insertable = ModelInsertQuery<M>;
854
855 fn into_insertable(&self) -> Self::Insertable {
856 let mut columns = Vec::new();
857 let mut values = Vec::new();
858
859 for v in self.iter() {
860 let mut insertable = v.into_insertable();
861
862 if columns.is_empty() {
863 columns.append(&mut insertable.columns);
864 } else {
865 assert_eq!(columns, insertable.columns);
866 }
867
868 let v = insertable.values.pop().unwrap();
869 values.push(v);
870 }
871
872 ModelInsertQuery {
873 model: PhantomData,
874 columns,
875 values,
876 }
877 }
878}