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