Skip to main content

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