sequelite/model/
query.rs

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
9/// Just a marker type for count queries
10pub struct CountQuery;
11
12/// A trait for filtering queries
13/// 
14/// This allows you to filter, limit, offset, and order elements that you are querying.
15/// 
16/// # Example
17/// ```rs
18/// User::select()
19///     .filter(User::id.eq(1) & User::name.like("%test%"))
20///     .limit(1)
21///     .order(User::id.desc())
22///     .exec(&conn).unwrap();
23/// ```
24pub 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
52// Only tables can be queried
53impl<M: Model> ModelQuery<M> {
54    // ====< Constructors >====
55    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
76// Every ModelQuery is a Queryable
77impl<M> ModelQuery<M> {
78
79    // ====< Utils >====
80    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    // ====< Additional Methods >====
93    /// Filter the query with the given filter
94    /// 
95    /// ## Arguments
96    /// * `filter` - The filter to apply to the query
97    /// 
98    /// ## Example
99    /// ```rs
100    /// let user = User::select()
101    ///     .filter(User::id.eq(1) & User::name.like("%test%"))
102    ///     .exec(&conn).unwrap();
103    /// ```
104    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    /// Select element by id
110    /// 
111    /// ## Arguments
112    /// * `id` - The id of the element to select
113    /// 
114    /// ## Example
115    /// ```rs
116    /// let user = User::select()
117    ///     .with_id(1)
118    ///     .exec(&conn).unwrap();
119    /// ```
120    /// 
121    /// ## Note
122    /// This is equivalent to `.filter(User::id.eq(id)).limit(1)` and should not be combined with other filters or limits.
123    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    /// Limit the number of elements returned
129    /// 
130    /// ## Arguments
131    /// * `limit` - The maximum number of elements to return
132    /// 
133    /// ## Example
134    /// ```rs
135    /// let users = User::select()
136    ///     .limit(10)
137    ///     .exec(&conn).unwrap();
138    /// ```
139    pub fn limit(self, limit: u32) -> Self {
140        ModelQuery::combine(self, "LIMIT ?".to_string(), vec![Box::new(limit)])
141    }
142
143    /// Offset selection by the given number of elements
144    /// 
145    /// ## Arguments
146    /// * `offset` - The number of elements to skip
147    /// 
148    /// ## Example
149    /// ```rs
150    /// let users = User::select()
151    ///     .offset(10)
152    ///     .exec(&conn).unwrap();
153    /// ```
154    pub fn offset(self, offset: u32) -> Self {
155        ModelQuery::combine(self, "OFFSET ?".to_string(), vec![Box::new(offset)])
156    }
157
158    /// Order the elements by the given order
159    /// 
160    /// ## Arguments
161    /// * `order` - The order to apply to the elements
162    /// 
163    /// ## Example
164    /// ```rs
165    /// let users = User::select()
166    ///     .order(User::id.desc())
167    ///     .exec(&conn).unwrap();
168    /// ```
169    pub fn order_by(self, order: ColumnQueryOrder) -> Self {
170        ModelQuery::combine(self, format!("ORDER BY {}", order.into_sqlite()), Vec::new())
171    }
172
173    /// **WARNING:** This is highly experimental and may not work as expected
174    /// Use Relation::get() or Relation::take() instead
175    /// 
176    /// ## Arguments
177    /// * `relation` - The relation to join
178    /// 
179    /// ## Example
180    /// ```rs
181    /// let users = Post::select()
182    ///     .join_relation(Post::author)
183    ///     .exec(&conn).unwrap();
184    /// ```
185    pub fn join_relation(mut self, relation: Column<'static>) -> Self {
186        // Ensure that the relation is a relation
187        match relation.get_relation() {
188            Some(relation) => {
189                // Left join the relation table
190                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                // Add the relation to the joins
194                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    /// Select only the given columns (do not use this if you want to map to a model column which is not an `Option<T>`)
207    /// 
208    /// ## Arguments
209    /// * `columns` - The columns to select
210    /// 
211    /// ## Example
212    /// ```rs
213    /// let users = User::select()
214    ///     .columns(&[User::id, User::name])
215    ///     .exec(&conn).unwrap();
216    /// ```
217    pub fn columns(self, columns: &[Column<'static>]) -> Self {
218        let columns = columns.iter().map(|c| c.name()).collect::<Vec<_>>().join(", ");
219        // Replace first SELECT * with the given columns
220        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    /// Check if the column is null (only for nullable columns)
471    /// ## Example
472    /// ```rust
473    /// User::select().filter(User::name.is_null()).exec(conn);
474    /// ```
475    /// This will generate the following SQL query:
476    /// ```sql
477    /// SELECT * FROM users WHERE users.name IS NULL;
478    /// ```
479    fn is_null(self) -> ColumnQueryFilterUnary {
480        ColumnQueryFilterUnary {
481            column: format!("{}.{}", self.table_name, self.name()),
482            op: "IS NULL",
483        }
484    }
485
486    /// Check if the column is not null (only for nullable columns)
487    /// ## Example
488    /// ```rust
489    /// User::select().filter(User::name.is_not_null()).exec(conn);
490    /// ```
491    /// This will generate the following SQL query:
492    /// ```sql
493    /// SELECT * FROM users WHERE users.name IS NOT NULL;
494    /// ```
495    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    /// Check if the column is in the list of values
503    /// ## Example
504    /// ```rust
505    /// User::select().filter(User::name.in_(vec!["John", "Jane"])).exec(conn);
506    /// ```
507    /// This will generate the following SQL query:
508    /// ```sql
509    /// -- ? is a parameter
510    /// SELECT * FROM users WHERE users.name IN (?, ?);
511    /// ```
512    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    /// Check if the column is not in the list of values
520    /// ## Example
521    /// ```rust
522    /// User::select().filter(User::name.not_in(vec!["John", "Jane"])).exec(conn);
523    /// ```
524    /// This will generate the following SQL query:
525    /// ```sql
526    /// -- ? is a parameter
527    /// SELECT * FROM users WHERE users.name NOT IN (?, ?);
528    /// ```
529    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    /// Order the query by the column in ascending order
537    /// ## Example
538    /// ```rust
539    /// User::select().order_by(User::name.asc()).exec(conn);
540    /// ```
541    /// This will generate the following SQL query:
542    /// ```sql
543    /// SELECT * FROM users ORDER BY users.name ASC;
544    /// ```
545    fn asc(self) -> ColumnQueryOrder {
546        ColumnQueryOrder {
547            column: self.name(),
548            order: ColumnQueryOrdering::Ascending,
549        }
550    }
551
552    /// Order the query by the column in descending order
553    /// ## Example
554    /// ```rust
555    /// User::select().order_by(User::name.desc()).exec(conn);
556    /// ```
557    /// This will generate the following SQL query:
558    /// ```sql
559    /// SELECT * FROM users ORDER BY users.name DESC;
560    /// ```
561    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    /// Combine two filters with an AND operator
653    /// ## Example
654    /// ```rust
655    /// User::select().filter(User::name.eq("John").and(User::age.gt(18))).exec(conn);
656    /// ```
657    /// This will generate the following SQL query:
658    /// ```sql
659    /// SELECT * FROM users WHERE users.name = ? AND users.age > ?;
660    /// ```
661    /// 
662    /// ## Note
663    /// This is not a beautiful way to write this query, so you should use '&' instead:
664    /// ```rust
665    /// User::select().filter(User::name.eq("John") & User::age.gt(18)).exec(conn);
666    /// ```
667    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    /// Combine two filters with an OR operator
678    /// ## Example
679    /// ```rust
680    /// User::select().filter(User::name.eq("John").or(User::age.gt(18))).exec(conn);
681    /// ```
682    /// This will generate the following SQL query:
683    /// ```sql
684    /// SELECT * FROM users WHERE users.name = ? OR users.age > ?;
685    /// ```
686    /// 
687    /// ## Note
688    /// This is not a beautiful way to write this query, so you should use '|' instead:
689    /// ```rust
690    /// User::select().filter(User::name.eq("John") | User::age.gt(18)).exec(conn);
691    /// ```
692    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], // Only one row
820        }
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}