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 187 188 189 190 191 192
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. /// /// # Bound parameters /// /// If you need to pass arguments to your query, you should use [`.bind()`]. /// /// [`.bind()`]: ../sql_literal/struct.SqlLiteral.html#method.bind /// /// # 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()) }