1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
use std::marker::PhantomData;

use backend::Backend;
use expression::*;
use query_builder::*;
use result::QueryResult;
use super::unchecked_bind::UncheckedBind;
use types::HasSqlType;

#[derive(Debug, Clone)]
/// Available for when you truly cannot represent something using the expression
/// DSL. You will need to provide the type of the expression, in addition to the
/// SQL. The compiler will be unable to verify the correctness of this type.
///
/// To get a SQL literal, use the [`sql()`] function.
///
/// [`sql()`]: fn.sql.html
pub struct SqlLiteral<ST> {
    sql: String,
    _marker: PhantomData<ST>,
}

impl<ST> SqlLiteral<ST> {
    #[doc(hidden)]
    pub fn new(sql: String) -> Self {
        SqlLiteral {
            sql: sql,
            _marker: PhantomData,
        }
    }

    /// Bind a value for use with this SQL query.
    ///
    /// # Safety
    ///
    /// This function should be used with care, as Diesel cannot validate that
    /// the value is of the right type nor can it validate that you have passed
    /// the correct number of parameters.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("src/doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use self::users::dsl::*;
    /// #     use diesel::expression::dsl::sql;
    /// #     use diesel::types::{Integer, Text};
    /// #     let connection = establish_connection();
    /// #[cfg(feature="postgres")]
    /// let query = sql::<Integer>("SELECT id FROM users WHERE name = $1");
    /// #[cfg(not(feature="postgres"))]
    /// let query = sql::<Integer>("SELECT id FROM users WHERE name = ?");
    /// let seans_id = query.clone().bind::<Text, _>("Sean")
    ///     .get_result(&connection);
    /// assert_eq!(Ok(1), seans_id);
    /// let tess_id = query.bind::<Text, _>("Tess")
    ///     .get_result(&connection);
    /// assert_eq!(Ok(2), tess_id);
    /// # }
    /// ```
    ///
    /// ### Multiple Bind Params
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("src/doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use self::users::dsl::*;
    /// #     use diesel::expression::dsl::sql;
    /// #     use diesel::types::{Integer, Text};
    /// #     let connection = establish_connection();
    /// #     diesel::insert(&NewUser::new("Jim")).into(users)
    /// #         .execute(&connection).unwrap();
    /// #[cfg(not(feature="postgres"))]
    /// let query = sql::<Text>("SELECT name FROM users WHERE id > ? AND name <> ?");
    /// #[cfg(feature="postgres")]
    /// let query = sql("SELECT name FROM users WHERE id > $1 AND name <> $2");
    /// let query = query
    ///     .bind::<Integer, _>(1)
    ///     .bind::<Text, _>("Jim");
    /// let expected = vec!["Tess".to_string()];
    /// assert_eq!(Ok(expected), query.load(&connection));
    /// # }
    /// ```
    pub fn bind<BindST, T>(self, bind_value: T) -> UncheckedBind<Self, T, BindST> {
        UncheckedBind::new(self, bind_value)
    }
}

impl<ST> Expression for SqlLiteral<ST> {
    type SqlType = ST;
}

impl<ST, DB> QueryFragment<DB> for SqlLiteral<ST> where
    DB: Backend + HasSqlType<ST>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        out.push_sql(&self.sql);
        Ok(())
    }
}

impl_query_id!(noop: SqlLiteral<ST>);

impl<ST> Query for SqlLiteral<ST> {
    type SqlType = ST;
}

impl<QS, ST> SelectableExpression<QS> for SqlLiteral<ST> {
}

impl<QS, ST> AppearsOnTable<QS> for SqlLiteral<ST> {
}

impl<ST> NonAggregate for SqlLiteral<ST> {
}

/// Use literal SQL in the query builder
///
/// Available for when you truly cannot represent something using the expression
/// DSL. You will need to provide the SQL type of the expression, in addition to
/// the SQL.
///
/// # Safety
///
/// The compiler will be unable to verify the correctness of the annotated type.
/// If you give the wrong type, it'll either crash at runtime when deserializing
/// the query result or produce invalid values.
///
/// # Examples
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # #[macro_use] extern crate diesel_codegen;
/// use diesel::expression::sql;
/// use diesel::types::{Bool, Integer, Text};
/// # include!("src/doctest_setup.rs");
/// # table! {
/// #   users {
/// #       id -> Integer,
/// #       name -> VarChar,
/// #   }
/// # }
///
/// #[derive(PartialEq, Debug, Queryable)]
/// struct User {
///     id: i32,
///     name: String,
/// }
///
/// # fn main() {
/// # let connection = establish_connection();
/// #
/// let setup = sql::<Bool>("INSERT INTO users(name) VALUES('Ruby')");
/// setup.execute(&connection).expect("Can't insert in users");
///
/// let query = sql::<(Integer, Text)>("SELECT id, name FROM users WHERE name='Ruby';");
/// let users = query.load::<User>(&connection).expect("Can't query users");
/// assert_eq!(users, vec![User{id: 3, name: "Ruby".to_owned()}]);
///
/// let query = users::table.filter(sql::<Bool>("name='Ruby'")); // Same query as above
/// let users = query.load::<User>(&connection).expect("Can't query users");
/// assert_eq!(users, vec![User{id: 3, name: "Ruby".to_owned()}]);
/// # }
/// ```
pub fn sql<ST>(sql: &str) -> SqlLiteral<ST> {
    SqlLiteral::new(sql.into())
}