diesel/query_builder/
sql_query.rs

1use std::marker::PhantomData;
2
3use backend::Backend;
4use connection::Connection;
5use deserialize::QueryableByName;
6use query_builder::{AstPass, QueryFragment, QueryId};
7use query_dsl::{LoadQuery, RunQueryDsl};
8use result::QueryResult;
9use serialize::ToSql;
10use sql_types::HasSqlType;
11
12#[derive(Debug, Clone)]
13#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
14/// The return value of `sql_query`.
15///
16/// Unlike most queries in Diesel, `SqlQuery` loads its data by column name,
17/// rather than by index. This means that you cannot deserialize this query into
18/// a tuple, and any structs used must implement `QueryableByName`.
19///
20/// See [`sql_query`](../fn.sql_query.html) for examples.
21pub struct SqlQuery {
22    query: String,
23}
24
25impl SqlQuery {
26    pub(crate) fn new(query: String) -> Self {
27        SqlQuery { query }
28    }
29
30    /// Bind a value for use with this SQL query.
31    ///
32    /// # Safety
33    ///
34    /// This function should be used with care, as Diesel cannot validate that
35    /// the value is of the right type nor can it validate that you have passed
36    /// the correct number of parameters.
37    ///
38    /// # Example
39    ///
40    /// ```
41    /// # #[macro_use] extern crate diesel;
42    /// # include!("../doctest_setup.rs");
43    /// #
44    /// # use schema::users;
45    /// #
46    /// # #[derive(QueryableByName, Debug, PartialEq)]
47    /// # #[table_name="users"]
48    /// # struct User {
49    /// #     id: i32,
50    /// #     name: String,
51    /// # }
52    /// #
53    /// # fn main() {
54    /// #     use diesel::sql_query;
55    /// #     use diesel::sql_types::{Integer, Text};
56    /// #
57    /// #     let connection = establish_connection();
58    /// #     diesel::insert_into(users::table)
59    /// #         .values(users::name.eq("Jim"))
60    /// #         .execute(&connection).unwrap();
61    /// # #[cfg(feature = "postgres")]
62    /// # let users = sql_query("SELECT * FROM users WHERE id > $1 AND name != $2");
63    /// # #[cfg(not(feature = "postgres"))]
64    /// let users = sql_query("SELECT * FROM users WHERE id > ? AND name <> ?")
65    /// # ;
66    /// # let users = users
67    ///     .bind::<Integer, _>(1)
68    ///     .bind::<Text, _>("Tess")
69    ///     .get_results(&connection);
70    /// let expected_users = vec![
71    ///     User { id: 3, name: "Jim".into() },
72    /// ];
73    /// assert_eq!(Ok(expected_users), users);
74    /// # }
75    /// ```
76    pub fn bind<ST, Value>(self, value: Value) -> UncheckedBind<Self, Value, ST> {
77        UncheckedBind::new(self, value)
78    }
79}
80
81impl<DB> QueryFragment<DB> for SqlQuery
82where
83    DB: Backend,
84{
85    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
86        out.unsafe_to_cache_prepared();
87        out.push_sql(&self.query);
88        Ok(())
89    }
90}
91
92impl QueryId for SqlQuery {
93    type QueryId = ();
94
95    const HAS_STATIC_QUERY_ID: bool = false;
96}
97
98impl<Conn, T> LoadQuery<Conn, T> for SqlQuery
99where
100    Conn: Connection,
101    T: QueryableByName<Conn::Backend>,
102{
103    fn internal_load(self, conn: &Conn) -> QueryResult<Vec<T>> {
104        conn.query_by_name(&self)
105    }
106}
107
108impl<Conn> RunQueryDsl<Conn> for SqlQuery {}
109
110#[derive(Debug, Clone, Copy)]
111#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
112pub struct UncheckedBind<Query, Value, ST> {
113    query: Query,
114    value: Value,
115    _marker: PhantomData<ST>,
116}
117
118impl<Query, Value, ST> UncheckedBind<Query, Value, ST> {
119    pub fn new(query: Query, value: Value) -> Self {
120        UncheckedBind {
121            query,
122            value,
123            _marker: PhantomData,
124        }
125    }
126
127    pub fn bind<ST2, Value2>(self, value: Value2) -> UncheckedBind<Self, Value2, ST2> {
128        UncheckedBind::new(self, value)
129    }
130}
131
132impl<Query, Value, ST> QueryId for UncheckedBind<Query, Value, ST>
133where
134    Query: QueryId,
135    ST: QueryId,
136{
137    type QueryId = UncheckedBind<Query::QueryId, (), ST::QueryId>;
138
139    const HAS_STATIC_QUERY_ID: bool = Query::HAS_STATIC_QUERY_ID && ST::HAS_STATIC_QUERY_ID;
140}
141
142impl<Query, Value, ST, DB> QueryFragment<DB> for UncheckedBind<Query, Value, ST>
143where
144    DB: Backend + HasSqlType<ST>,
145    Query: QueryFragment<DB>,
146    Value: ToSql<ST, DB>,
147{
148    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
149        self.query.walk_ast(out.reborrow())?;
150        out.push_bind_param_value_only(&self.value)?;
151        Ok(())
152    }
153}
154
155impl<Conn, Query, Value, ST, T> LoadQuery<Conn, T> for UncheckedBind<Query, Value, ST>
156where
157    Conn: Connection,
158    T: QueryableByName<Conn::Backend>,
159    Self: QueryFragment<Conn::Backend> + QueryId,
160{
161    fn internal_load(self, conn: &Conn) -> QueryResult<Vec<T>> {
162        conn.query_by_name(&self)
163    }
164}
165
166impl<Conn, Query, Value, ST> RunQueryDsl<Conn> for UncheckedBind<Query, Value, ST> {}