queries_for_sqlx/
select_st.rs

1use std::marker::PhantomData;
2
3use joins::{Join, JoinType};
4
5use crate::execute_no_cache::ExecuteNoCacheUsingSelectTrait;
6use crate::sql_part::{
7    AcceptToSqlPart, ToSqlPart, WhereItemToSqlPart,
8};
9use crate::{
10    Accept, InitStatement, Query, Statement, TakeParts,
11};
12use crate::{SelectItem, WhereItem};
13
14pub struct SelectSt<S, Q: Query<S>> {
15    pub(crate) select_list: Vec<String>,
16    pub(crate) where_clause: Vec<Q::SqlPart>,
17    pub(crate) joins: Vec<Join<&'static str>>,
18    pub(crate) order_by: Vec<(&'static str, bool)>,
19    pub(crate) limit: Option<Q::SqlPart>,
20    pub(crate) shift: Option<Q::SqlPart>,
21    pub(crate) ctx: Q::Context1,
22    pub(crate) from: &'static str,
23    pub(crate) _sqlx: PhantomData<S>,
24}
25
26impl<S, Q> ExecuteNoCacheUsingSelectTrait for SelectSt<S, Q> where
27    Q: Query<S>
28{
29}
30
31impl<S, Q> InitStatement<Q> for SelectSt<S, Q>
32where
33    Q: Query<S>,
34{
35    type Init = &'static str;
36    fn init(from: &'static str) -> SelectSt<S, Q> {
37        SelectSt {
38            select_list: Default::default(),
39            where_clause: Default::default(),
40            joins: Default::default(),
41            order_by: Default::default(),
42            limit: Default::default(),
43            shift: Default::default(),
44            ctx: Default::default(),
45            from,
46            _sqlx: PhantomData,
47        }
48    }
49}
50
51impl<S, Q> Statement<S, Q> for SelectSt<S, Q>
52where
53    Q: Query<S>,
54{
55    fn deref_ctx(&self) -> &Q::Context1 {
56        &self.ctx
57    }
58    fn deref_mut_ctx(&mut self) -> &mut Q::Context1 {
59        &mut self.ctx
60    }
61
62    fn _build(self) -> (String, <Q as Query<S>>::Output) {
63        self.build()
64    }
65}
66
67impl<S, Q> SelectSt<S, Q>
68where
69    Q: Query<S>,
70{
71    pub fn build(self) -> (String, Q::Output) {
72        Q::build_query(self.ctx, |ctx| {
73            let mut str = String::from("SELECT ");
74
75            if self.select_list.len() == 0 {
76                panic!("select list is empty");
77            }
78
79            for (index, item) in
80                self.select_list.into_iter().enumerate()
81            {
82                if index != 0 {
83                    str.push_str(", ");
84                }
85                str.push_str(&item);
86            }
87
88            str.push_str(" FROM ");
89            str.push_str(&self.from);
90
91            for join in self.joins.into_iter() {
92                let join = format!(
93                    " {} {} ON {}.{} = {}.{}",
94                    join.ty.to_string(),
95                    join.on_table,
96                    join.on_table,
97                    join.on_column,
98                    self.from,
99                    join.local_column,
100                );
101                str.push_str(&join);
102            }
103
104            for (index, item) in
105                self.where_clause.into_iter().enumerate()
106            {
107                if index == 0 {
108                    str.push_str(" WHERE ");
109                } else {
110                    str.push_str(" AND ");
111                }
112                let item = Q::build_sql_part_back(ctx, item);
113                str.push_str(&item);
114            }
115
116            if self.order_by.len() != 0 {
117                str.push_str(" ORDER BY ");
118                for (index, (by, asc)) in
119                    self.order_by.into_iter().enumerate()
120                {
121                    if index != 0 {
122                        str.push_str(", ");
123                    }
124                    str.push_str(by);
125                    if !asc {
126                        str.push_str(" DESC");
127                    }
128                }
129            }
130
131            if let Some(limit) = self.limit {
132                let limit = Q::build_sql_part_back(ctx, limit);
133                str.push_str(" LIMIT ");
134                str.push_str(&limit);
135            }
136
137            if let Some(shift) = self.shift {
138                let shift = Q::build_sql_part_back(ctx, shift);
139                str.push_str(" OFFSET ");
140                str.push_str(&shift);
141            }
142
143            str.push_str(";");
144            str
145        })
146    }
147
148    pub fn select(
149        &mut self,
150        item: impl SelectItem<S> + 'static,
151    ) {
152        self.select_list.push(item.select_item());
153    }
154
155    pub fn join(&mut self, join: impl JoinType<S> + 'static) {
156        let join = join.join_ty();
157        if self
158            .joins
159            .iter()
160            .find(|e| e.on_table == join.on_table)
161            .is_some()
162        {
163            panic!(
164                "table {} has been joined already",
165                join.on_table
166            );
167        }
168
169        self.joins.push(join);
170    }
171
172    pub fn offset<T>(&mut self, shift: T)
173    where
174        Q: Accept<T, S>,
175        AcceptToSqlPart<T>: ToSqlPart<Q, S>,
176    {
177        if self.shift.is_some() {
178            panic!("limit has been set already");
179        }
180
181        let limit =
182            AcceptToSqlPart(shift).to_sql_part(&mut self.ctx);
183
184        self.shift = Some(limit);
185    }
186
187    pub fn limit<T>(&mut self, limit: T)
188    where
189        Q: Accept<T, S>,
190        AcceptToSqlPart<T>: ToSqlPart<Q, S>,
191    {
192        if self.limit.is_some() {
193            panic!("limit has been set already");
194        }
195
196        let limit =
197            AcceptToSqlPart(limit).to_sql_part(&mut self.ctx);
198
199        self.limit = Some(limit);
200    }
201
202    pub fn order_by(&mut self, by: &'static str, asc: bool) {
203        self.order_by.push((by, asc));
204    }
205
206    pub fn where_<T>(&mut self, item: T)
207    where
208        T: WhereItem<S, Q> + 'static,
209        WhereItemToSqlPart<T>: ToSqlPart<Q, S>,
210    {
211        let item =
212            WhereItemToSqlPart(item).to_sql_part(&mut self.ctx);
213
214        self.where_clause.push(item);
215    }
216    // pub fn where_(
217    //     &mut self,
218    //     item: impl WhereItem<S, Q> + 'static,
219    // )
220    // {
221    //     let item = Q::handle_where_item(item, &mut self.ctx);
222    //
223    //     self.where_clause.push(item);
224    // }
225}
226
227#[deprecated = "in favor of AcceptToSqlPart"]
228pub struct HandleAccept<T, S, Q>(pub T, pub PhantomData<(S, Q)>);
229
230/// this trait will be removed once I figure out universal
231/// way to accept all Q: Accept<S, T>
232#[deprecated = "in favor of AcceptToSqlPart"]
233pub trait HandleAcceptIsWorking {
234    type SqlPart;
235    type Ctx;
236    fn to_sql_part(self, ctx: &mut Self::Ctx) -> Self::SqlPart;
237}
238
239pub mod joins {
240    pub mod join_type {
241        use super::{Join, JoinType};
242
243        pub struct Left;
244
245        impl<S> JoinType<S> for Join<Left> {
246            fn join_ty(self) -> Join<&'static str> {
247                Join {
248                    ty: "LEFT JOIN",
249                    on_table: self.on_table,
250                    on_column: self.on_column,
251                    local_column: self.local_column,
252                }
253            }
254        }
255    }
256
257    pub trait JoinType<S> {
258        fn join_ty(self) -> Join<&'static str>;
259    }
260
261    pub struct Join<J> {
262        pub ty: J,
263        pub on_table: &'static str,
264        pub on_column: &'static str,
265        pub local_column: &'static str,
266    }
267}
268
269pub mod order_by {
270    pub const ASC: bool = true;
271    pub const DESC: bool = false;
272}
273
274pub mod exports {
275    pub use super::joins::{Join, JoinType};
276}