diesel/expression/
sql_literal.rs

1use std::marker::PhantomData;
2
3use crate::expression::*;
4use crate::query_builder::*;
5use crate::query_dsl::RunQueryDsl;
6use crate::result::QueryResult;
7use crate::sql_types::DieselNumericOps;
8
9#[derive(Debug, Clone, DieselNumericOps)]
10#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
11/// Returned by the [`sql()`] function.
12///
13/// [`sql()`]: crate::dsl::sql()
14pub struct SqlLiteral<ST, T = self::private::Empty> {
15    sql: String,
16    inner: T,
17    _marker: PhantomData<ST>,
18}
19
20impl<ST, T> SqlLiteral<ST, T>
21where
22    ST: TypedExpressionType,
23{
24    pub(crate) fn new(sql: String, inner: T) -> Self {
25        SqlLiteral {
26            sql,
27            inner,
28            _marker: PhantomData,
29        }
30    }
31
32    /// Bind a value for use with this SQL query.
33    ///
34    /// # Safety
35    ///
36    /// This function should be used with care, as Diesel cannot validate that
37    /// the value is of the right type nor can it validate that you have passed
38    /// the correct number of parameters.
39    ///
40    /// # Examples
41    ///
42    /// ```rust
43    /// # include!("../doctest_setup.rs");
44    /// #
45    /// # table! {
46    /// #    users {
47    /// #        id -> Integer,
48    /// #        name -> VarChar,
49    /// #    }
50    /// # }
51    /// #
52    /// # fn main() {
53    /// #     use self::users::dsl::*;
54    /// #     use diesel::dsl::sql;
55    /// #     use diesel::sql_types::{Integer, Text, Bool};
56    /// #     let connection = &mut establish_connection();
57    /// let seans_id = users
58    ///     .select(id)
59    ///     .filter(sql::<Bool>("name = ").bind::<Text, _>("Sean"))
60    ///     .get_result(connection);
61    /// assert_eq!(Ok(1), seans_id);
62    ///
63    /// let tess_id = sql::<Integer>("SELECT id FROM users WHERE name = ")
64    ///     .bind::<Text, _>("Tess")
65    ///     .get_result(connection);
66    /// assert_eq!(Ok(2), tess_id);
67    /// # }
68    /// ```
69    ///
70    /// ### Multiple Bind Params
71    ///
72    /// ```rust
73    /// # include!("../doctest_setup.rs");
74    /// #
75    /// # table! {
76    /// #    users {
77    /// #        id -> Integer,
78    /// #        name -> VarChar,
79    /// #    }
80    /// # }
81    /// #
82    /// # fn main() {
83    /// #     use self::users::dsl::*;
84    /// #     use diesel::dsl::sql;
85    /// #     use diesel::sql_types::{Integer, Text, Bool};
86    /// #     let connection = &mut establish_connection();
87    /// #     diesel::insert_into(users).values(name.eq("Ryan"))
88    /// #           .execute(connection).unwrap();
89    /// let query = users
90    ///     .select(name)
91    ///     .filter(
92    ///         sql::<Bool>("id > ")
93    ///             .bind::<Integer, _>(1)
94    ///             .sql(" AND name <> ")
95    ///             .bind::<Text, _>("Ryan"),
96    ///     )
97    ///     .get_results(connection);
98    /// let expected = vec!["Tess".to_string()];
99    /// assert_eq!(Ok(expected), query);
100    /// # }
101    /// ```
102    pub fn bind<BindST, U>(self, bind_value: U) -> UncheckedBind<Self, U::Expression>
103    where
104        BindST: SqlType + TypedExpressionType,
105        U: AsExpression<BindST>,
106    {
107        UncheckedBind::new(self, bind_value.as_expression())
108    }
109
110    /// Use literal SQL in the query builder
111    ///
112    /// This function is intended for use when you need a small bit of raw SQL in
113    /// your query. If you want to write the entire query using raw SQL, use
114    /// [`sql_query`](crate::sql_query()) instead.
115    ///
116    /// # Safety
117    ///
118    /// This function should be used with care, as Diesel cannot validate that
119    /// the value is of the right type nor can it validate that you have passed
120    /// the correct number of parameters.
121    ///
122    /// # Examples
123    ///
124    /// ```rust
125    /// # include!("../doctest_setup.rs");
126    /// #
127    /// # table! {
128    /// #    users {
129    /// #        id -> Integer,
130    /// #        name -> VarChar,
131    /// #    }
132    /// # }
133    /// #
134    /// # fn main() {
135    /// #     use self::users::dsl::*;
136    /// #     use diesel::dsl::sql;
137    /// #     use diesel::sql_types::Bool;
138    /// #     let connection = &mut establish_connection();
139    /// #     diesel::insert_into(users).values(name.eq("Ryan"))
140    /// #           .execute(connection).unwrap();
141    /// let query = users
142    ///     .select(name)
143    ///     .filter(sql::<Bool>("id > 1").sql(" AND name <> 'Ryan'"))
144    ///     .get_results(connection);
145    /// let expected = vec!["Tess".to_string()];
146    /// assert_eq!(Ok(expected), query);
147    /// # }
148    /// ```
149    pub fn sql(self, sql: &str) -> SqlLiteral<ST, Self> {
150        SqlLiteral::new(sql.into(), self)
151    }
152}
153
154impl<ST, T> Expression for SqlLiteral<ST, T>
155where
156    ST: TypedExpressionType,
157{
158    type SqlType = ST;
159}
160
161impl<ST, T, DB> QueryFragment<DB> for SqlLiteral<ST, T>
162where
163    DB: Backend,
164    T: QueryFragment<DB>,
165{
166    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
167        out.unsafe_to_cache_prepared();
168        self.inner.walk_ast(out.reborrow())?;
169        out.push_sql(&self.sql);
170        Ok(())
171    }
172}
173
174impl<ST, T> QueryId for SqlLiteral<ST, T> {
175    type QueryId = ();
176
177    const HAS_STATIC_QUERY_ID: bool = false;
178}
179
180impl<ST, T> Query for SqlLiteral<ST, T>
181where
182    Self: Expression,
183{
184    type SqlType = ST;
185}
186
187impl<ST, T, Conn> RunQueryDsl<Conn> for SqlLiteral<ST, T> {}
188
189impl<QS, ST, T> SelectableExpression<QS> for SqlLiteral<ST, T> where Self: Expression {}
190
191impl<QS, ST, T> AppearsOnTable<QS> for SqlLiteral<ST, T> where Self: Expression {}
192
193impl<ST, T, GB> ValidGrouping<GB> for SqlLiteral<ST, T> {
194    type IsAggregate = is_aggregate::Never;
195}
196
197/// Use literal SQL in the query builder.
198///
199/// Available for when you truly cannot represent something using the expression
200/// DSL. You will need to provide the SQL type of the expression, in addition to
201/// the SQL.
202///
203/// This function is intended for use when you need a small bit of raw SQL in
204/// your query. If you want to write the entire query using raw SQL, use
205/// [`sql_query`](crate::sql_query()) instead.
206///
207/// Query parameters can be bound into the literal SQL using [`SqlLiteral::bind()`].
208///
209/// # Safety
210///
211/// The compiler will be unable to verify the correctness of the annotated type.
212/// If you give the wrong type, it'll either return an error when deserializing
213/// the query result or produce unexpected values.
214///
215/// # Examples
216///
217/// ```rust
218/// # include!("../doctest_setup.rs");
219/// # fn main() {
220/// #     run_test_1().unwrap();
221/// #     run_test_2().unwrap();
222/// # }
223/// #
224/// # fn run_test_1() -> QueryResult<()> {
225/// #     use schema::users::dsl::*;
226/// #     use diesel::sql_types::Bool;
227/// use diesel::dsl::sql;
228/// #     let connection = &mut establish_connection();
229/// let user = users
230///     .filter(sql::<Bool>("name = 'Sean'"))
231///     .first(connection)?;
232/// let expected = (1, String::from("Sean"));
233/// assert_eq!(expected, user);
234/// #     Ok(())
235/// # }
236/// #
237/// # fn run_test_2() -> QueryResult<()> {
238/// #     use crate::schema::users::dsl::*;
239/// #     use diesel::dsl::sql;
240/// #     use diesel::sql_types::{Bool, Integer, Text};
241/// #     let connection = &mut establish_connection();
242/// #     diesel::insert_into(users)
243/// #         .values(name.eq("Ryan"))
244/// #         .execute(connection).unwrap();
245/// let query = users
246///     .select(name)
247///     .filter(
248///         sql::<Bool>("id > ")
249///             .bind::<Integer, _>(1)
250///             .sql(" AND name <> ")
251///             .bind::<Text, _>("Ryan"),
252///     )
253///     .get_results(connection);
254/// let expected = vec!["Tess".to_string()];
255/// assert_eq!(Ok(expected), query);
256/// #     Ok(())
257/// # }
258/// ```
259/// [`SqlLiteral::bind()`]: crate::expression::SqlLiteral::bind()
260pub fn sql<ST>(sql: &str) -> SqlLiteral<ST>
261where
262    ST: TypedExpressionType,
263{
264    SqlLiteral::new(sql.into(), self::private::Empty)
265}
266
267#[derive(QueryId, Debug, Clone, Copy)]
268#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
269/// Returned by the [`SqlLiteral::bind()`] method when binding a value to a fragment of SQL.
270pub struct UncheckedBind<Query, Value> {
271    query: Query,
272    value: Value,
273}
274
275impl<Query, Value> UncheckedBind<Query, Value>
276where
277    Query: Expression,
278{
279    pub(crate) fn new(query: Query, value: Value) -> Self {
280        UncheckedBind { query, value }
281    }
282
283    /// Use literal SQL in the query builder.
284    ///
285    /// This function is intended for use when you need a small bit of raw SQL in
286    /// your query. If you want to write the entire query using raw SQL, use
287    /// [`sql_query`](crate::sql_query()) instead.
288    ///
289    /// # Safety
290    ///
291    /// This function should be used with care, as Diesel cannot validate that
292    /// the value is of the right type nor can it validate that you have passed
293    /// the correct number of parameters.
294    ///
295    /// # Examples
296    ///
297    /// ```rust
298    /// # include!("../doctest_setup.rs");
299    /// #
300    /// # table! {
301    /// #    users {
302    /// #        id -> Integer,
303    /// #        name -> VarChar,
304    /// #    }
305    /// # }
306    /// #
307    /// # fn main() {
308    /// #     use self::users::dsl::*;
309    /// #     use diesel::dsl::sql;
310    /// #     use diesel::sql_types::{Integer, Bool};
311    /// #     let connection = &mut establish_connection();
312    /// #     diesel::insert_into(users).values(name.eq("Ryan"))
313    /// #           .execute(connection).unwrap();
314    /// let query = users
315    ///     .select(name)
316    ///     .filter(
317    ///         sql::<Bool>("id > ")
318    ///             .bind::<Integer, _>(1)
319    ///             .sql(" AND name <> 'Ryan'"),
320    ///     )
321    ///     .get_results(connection);
322    /// let expected = vec!["Tess".to_string()];
323    /// assert_eq!(Ok(expected), query);
324    /// # }
325    /// ```
326    pub fn sql(self, sql: &str) -> SqlLiteral<Query::SqlType, Self> {
327        SqlLiteral::new(sql.into(), self)
328    }
329}
330
331impl<Query, Value> Expression for UncheckedBind<Query, Value>
332where
333    Query: Expression,
334{
335    type SqlType = Query::SqlType;
336}
337
338impl<Query, Value, DB> QueryFragment<DB> for UncheckedBind<Query, Value>
339where
340    DB: Backend,
341    Query: QueryFragment<DB>,
342    Value: QueryFragment<DB>,
343{
344    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
345        self.query.walk_ast(out.reborrow())?;
346        self.value.walk_ast(out.reborrow())?;
347        Ok(())
348    }
349}
350
351impl<Q, Value> Query for UncheckedBind<Q, Value>
352where
353    Q: Query,
354{
355    type SqlType = Q::SqlType;
356}
357
358impl<Query, Value, GB> ValidGrouping<GB> for UncheckedBind<Query, Value> {
359    type IsAggregate = is_aggregate::Never;
360}
361
362impl<QS, Query, Value> SelectableExpression<QS> for UncheckedBind<Query, Value> where
363    Self: AppearsOnTable<QS>
364{
365}
366
367impl<QS, Query, Value> AppearsOnTable<QS> for UncheckedBind<Query, Value> where Self: Expression {}
368
369impl<Query, Value, Conn> RunQueryDsl<Conn> for UncheckedBind<Query, Value> {}
370
371mod private {
372    use crate::backend::{Backend, DieselReserveSpecialization};
373    use crate::query_builder::{QueryFragment, QueryId};
374
375    #[derive(Debug, Clone, Copy, QueryId)]
376    pub struct Empty;
377
378    impl<DB> QueryFragment<DB> for Empty
379    where
380        DB: Backend + DieselReserveSpecialization,
381    {
382        fn walk_ast<'b>(
383            &'b self,
384            _pass: crate::query_builder::AstPass<'_, 'b, DB>,
385        ) -> crate::QueryResult<()> {
386            Ok(())
387        }
388    }
389}