ormlite_core/query_builder/
select.rs

1use crate::error::{Error, Result};
2use crate::model::Model;
3use crate::query_builder::args::QueryBuilderArgs;
4use crate::query_builder::{util, Placeholder};
5use sqlmo::{Expr, OrderBy, ToSql};
6
7use crate::join::{criteria, select_columns, JoinDescription};
8use sqlmo::{query::Where, Select};
9use sqlx::{Executor, IntoArguments};
10use std::marker::PhantomData;
11
12pub use sqlmo::query::Direction;
13
14// Add additional information to the sqlx::Database
15pub trait DatabaseMetadata {
16    fn dialect() -> sqlmo::Dialect;
17    fn placeholder() -> Placeholder;
18}
19
20#[cfg(feature = "postgres")]
21impl DatabaseMetadata for sqlx::postgres::Postgres {
22    fn dialect() -> sqlmo::Dialect {
23        sqlmo::Dialect::Postgres
24    }
25
26    fn placeholder() -> Placeholder {
27        Placeholder::dollar_sign()
28    }
29}
30
31#[cfg(feature = "sqlite")]
32impl DatabaseMetadata for sqlx::sqlite::Sqlite {
33    fn dialect() -> sqlmo::Dialect {
34        sqlmo::Dialect::Sqlite
35    }
36
37    fn placeholder() -> Placeholder {
38        Placeholder::question_mark()
39    }
40}
41
42pub struct SelectQueryBuilder<'args, DB, Model>
43where
44    DB: sqlx::Database,
45{
46    pub query: Select,
47    arguments: QueryBuilderArgs<'args, DB>,
48    model: PhantomData<Model>,
49    gen: Placeholder,
50}
51
52impl<'args, DB, M> SelectQueryBuilder<'args, DB, M>
53where
54    M: Sized + Send + Sync + Unpin + for<'r> sqlx::FromRow<'r, DB::Row> + 'static + Model<DB>,
55    DB: sqlx::Database + DatabaseMetadata,
56    DB::Arguments<'args>: IntoArguments<'args, DB>,
57{
58    pub async fn fetch_all<'executor, E>(self, db: E) -> Result<Vec<M>>
59    where
60        E: Executor<'executor, Database = DB>,
61    {
62        let (text, args) = self.into_query_and_args()?;
63        let z: &str = &text;
64        util::query_as_with_recast_lifetime::<DB, M>(z, args)
65            .fetch_all(db)
66            .await
67            .map_err(Error::from)
68    }
69
70    pub async fn fetch_one<'executor, E>(mut self, db: E) -> Result<M>
71    where
72        E: Executor<'executor, Database = DB>,
73    {
74        if self.query.limit.is_none() {
75            self.query.limit = Some(1);
76        }
77        let (text, args) = self.into_query_and_args()?;
78        let z: &str = &text;
79        util::query_as_with_recast_lifetime::<DB, M>(z, args)
80            .fetch_one(db)
81            .await
82            .map_err(Error::from)
83    }
84
85    pub async fn fetch_optional<'executor, E>(mut self, db: E) -> Result<Option<M>>
86    where
87        E: Executor<'executor, Database = DB>,
88    {
89        if self.query.limit.is_none() {
90            self.query.limit = Some(1);
91        }
92        let (text, args) = self.into_query_and_args()?;
93        let z: &str = &text;
94        util::query_as_with_recast_lifetime::<DB, M>(z, args)
95            .fetch_optional(db)
96            .await
97            .map_err(Error::from)
98    }
99
100    pub fn with(mut self, name: &str, query: &str) -> Self {
101        self.query = self.query.with_raw(name, query);
102        self
103    }
104
105    /// Add a column to the query. Note you typically don't need this, as creating a query from
106    /// `Model::select` will automatically add that model's columns.
107    ///
108    /// # Arguments
109    /// * `column` - The column to add. Examples: "id", "name", "person.*"
110    pub fn select(mut self, column: impl Into<String>) -> Self {
111        self.query = self.query.select_raw(column.into());
112        self
113    }
114
115    /// Add a WHERE clause to the query.
116    /// Do not use format! to add parameters. Instead, use `?` as the placeholder, and add
117    /// parameters with [`bind`](Self::bind).
118    ///
119    /// Postgres users: You can (and should) use `?` as the placeholder. You might not have a defined
120    /// numerical order for your parameters, preventing $<N> syntax. Upon execution, the query
121    /// builder replaces `?` with `$<N>`. If you need the same parameter multiple times, you should
122    /// bind it multiple times. Arguments aren't moved, so this doesn't incur a memory cost. If you
123    /// still want to re-use parameters, you can use $<N> placeholders. However, don't mix `?` and
124    /// `$<N>` placeholders, as they will conflict.
125    ///
126    /// # Arguments
127    /// * `clause` - The clause to add. Examples: "id = ?", "name = ?", "person.id = ?"
128    pub fn where_(mut self, clause: &'static str) -> Self {
129        self.query = self.query.where_raw(clause);
130        self
131    }
132
133    /// Convenience method to add a `WHERE` and bind a value in one call.
134    pub fn where_bind<T>(mut self, clause: &'static str, value: T) -> Self
135    where
136        T: 'args + Send + sqlx::Type<DB> + sqlx::Encode<'args, DB>,
137    {
138        self.query = self.query.where_raw(clause);
139        self.arguments.add(value);
140        self
141    }
142    /// Dangerous because it takes a string that could be user crafted. You should prefer `.where_` which
143    /// takes a &'static str, and pass arguments with `.bind()`.
144    pub fn dangerous_where(mut self, clause: &str) -> Self {
145        self.query = self.query.where_raw(clause);
146        self
147    }
148
149    pub fn join(mut self, join_description: JoinDescription) -> Self {
150        match &join_description {
151            JoinDescription::ManyToOne {
152                columns,
153                foreign_table,
154                field,
155                foreign_key,
156                local_column,
157            } => {
158                let join = sqlmo::query::Join {
159                    typ: sqlmo::query::JoinType::Left,
160                    table: sqlmo::query::JoinTable::Table {
161                        schema: None,
162                        table: foreign_table.to_string(),
163                    },
164                    alias: Some(field.to_string()),
165                    criteria: criteria(M::table_name(), local_column, field, foreign_key),
166                };
167                self.query.join.push(join);
168                self.query.columns.extend(select_columns(columns, field))
169            }
170        }
171        self
172    }
173
174    #[doc(hidden)]
175    #[deprecated(note = "Please use `where_` instead")]
176    pub fn filter(self, clause: &'static str) -> Self {
177        self.where_(clause)
178    }
179
180    /// Add a HAVING clause to the query.
181    pub fn having(mut self, clause: &str) -> Self {
182        self.query = self.query.having(Where::Expr(Expr::Raw(clause.to_string())));
183        self
184    }
185
186    /// Add a GROUP BY clause to the query.
187    ///
188    /// # Arguments:
189    /// * `clause`: The GROUP BY clause to add. Examples: "id", "id, date", "1, 2, ROLLUP(3)"
190    pub fn group_by(mut self, clause: &str) -> Self {
191        self.query = self.query.group_by(clause);
192        self
193    }
194
195    /// Add an ORDER BY clause to the query.
196    ///
197    /// # Arguments:
198    /// * `clause`: The ORDER BY clause to add. "created_at DESC", "id ASC NULLS FIRST"
199    /// * `direction`: Direction::Asc or Direction::Desc
200    pub fn order_by(mut self, order: OrderBy) -> Self {
201        self.query = self.query.order_by(order);
202        self
203    }
204
205    pub fn order_asc(mut self, clause: &str) -> Self {
206        self.query = self.query.order_asc(clause);
207        self
208    }
209
210    pub fn order_desc(mut self, clause: &str) -> Self {
211        self.query = self.query.order_desc(clause);
212        self
213    }
214
215    /// Add a limit to the query.
216    pub fn limit(mut self, limit: usize) -> Self {
217        self.query = self.query.limit(limit);
218        self
219    }
220
221    /// Add an offset to the query.
222    pub fn offset(mut self, offset: usize) -> Self {
223        self.query = self.query.offset(offset);
224        self
225    }
226
227    /// Bind an argument to the query.
228    pub fn bind<T>(mut self, value: T) -> Self
229    where
230        T: 'args + Send + sqlx::Type<DB> + sqlx::Encode<'args, DB>,
231    {
232        self.arguments.add(value);
233        self
234    }
235
236    pub fn into_query_and_args(mut self) -> Result<(String, QueryBuilderArgs<'args, DB>)> {
237        let q = self.query.to_sql(DB::dialect());
238        let args = self.arguments;
239        let (q, placeholder_count) = util::replace_placeholders(&q, &mut self.gen)?;
240        if placeholder_count != args.len() {
241            return Err(Error::OrmliteError(format!(
242                "Failing to build query. {} placeholders were found in the query, but \
243                {} arguments were provided.",
244                placeholder_count,
245                args.len(),
246            )));
247        }
248        Ok((q, args))
249    }
250}
251
252impl<'args, DB: sqlx::Database + DatabaseMetadata, M: Model<DB>> Default for SelectQueryBuilder<'args, DB, M> {
253    fn default() -> Self {
254        Self {
255            query: Select::default().from(M::table_name()),
256            arguments: QueryBuilderArgs::default(),
257            model: PhantomData,
258            gen: DB::placeholder(),
259        }
260    }
261}