1 use std::marker::PhantomData;
2 
3 use backend::Backend;
4 use connection::Connection;
5 use deserialize::QueryableByName;
6 use query_builder::{AstPass, QueryFragment, QueryId};
7 use query_dsl::{LoadQuery, RunQueryDsl};
8 use result::QueryResult;
9 use serialize::ToSql;
10 use 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.
21 pub struct SqlQuery {
22     query: String,
23 }
24 
25 impl SqlQuery {
new(query: String) -> Self26     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     /// ```
bind<ST, Value>(self, value: Value) -> UncheckedBind<Self, Value, ST>76     pub fn bind<ST, Value>(self, value: Value) -> UncheckedBind<Self, Value, ST> {
77         UncheckedBind::new(self, value)
78     }
79 }
80 
81 impl<DB> QueryFragment<DB> for SqlQuery
82 where
83     DB: Backend,
84 {
walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()>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 
92 impl QueryId for SqlQuery {
93     type QueryId = ();
94 
95     const HAS_STATIC_QUERY_ID: bool = false;
96 }
97 
98 impl<Conn, T> LoadQuery<Conn, T> for SqlQuery
99 where
100     Conn: Connection,
101     T: QueryableByName<Conn::Backend>,
102 {
internal_load(self, conn: &Conn) -> QueryResult<Vec<T>>103     fn internal_load(self, conn: &Conn) -> QueryResult<Vec<T>> {
104         conn.query_by_name(&self)
105     }
106 }
107 
108 impl<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."]
112 pub struct UncheckedBind<Query, Value, ST> {
113     query: Query,
114     value: Value,
115     _marker: PhantomData<ST>,
116 }
117 
118 impl<Query, Value, ST> UncheckedBind<Query, Value, ST> {
new(query: Query, value: Value) -> Self119     pub fn new(query: Query, value: Value) -> Self {
120         UncheckedBind {
121             query,
122             value,
123             _marker: PhantomData,
124         }
125     }
126 
bind<ST2, Value2>(self, value: Value2) -> UncheckedBind<Self, Value2, ST2>127     pub fn bind<ST2, Value2>(self, value: Value2) -> UncheckedBind<Self, Value2, ST2> {
128         UncheckedBind::new(self, value)
129     }
130 }
131 
132 impl<Query, Value, ST> QueryId for UncheckedBind<Query, Value, ST>
133 where
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 
142 impl<Query, Value, ST, DB> QueryFragment<DB> for UncheckedBind<Query, Value, ST>
143 where
144     DB: Backend + HasSqlType<ST>,
145     Query: QueryFragment<DB>,
146     Value: ToSql<ST, DB>,
147 {
walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()>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 
155 impl<Conn, Query, Value, ST, T> LoadQuery<Conn, T> for UncheckedBind<Query, Value, ST>
156 where
157     Conn: Connection,
158     T: QueryableByName<Conn::Backend>,
159     Self: QueryFragment<Conn::Backend> + QueryId,
160 {
internal_load(self, conn: &Conn) -> QueryResult<Vec<T>>161     fn internal_load(self, conn: &Conn) -> QueryResult<Vec<T>> {
162         conn.query_by_name(&self)
163     }
164 }
165 
166 impl<Conn, Query, Value, ST> RunQueryDsl<Conn> for UncheckedBind<Query, Value, ST> {}
167