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 }
226
227#[deprecated = "in favor of AcceptToSqlPart"]
228pub struct HandleAccept<T, S, Q>(pub T, pub PhantomData<(S, Q)>);
229
230#[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}