Skip to content

Commit 654fb97

Browse files
committed
Merge remote-tracking branch 'upstream/master' into faillible_queryable_stillgeneric
2 parents 3dfa41b + e8c8d16 commit 654fb97

4 files changed

Lines changed: 138 additions & 69 deletions

File tree

diesel/src/expression/operators.rs

Lines changed: 2 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,7 @@ macro_rules! diesel_prefix_operator {
421421
}
422422

423423
infix_operator!(And, " AND ");
424+
infix_operator!(Or, " OR ");
424425
infix_operator!(Escape, " ESCAPE ");
425426
infix_operator!(Eq, " = ");
426427
infix_operator!(Gt, " > ");
@@ -457,10 +458,7 @@ use crate::expression::{TypedExpressionType, ValidGrouping};
457458
use crate::insertable::{ColumnInsertValue, Insertable};
458459
use crate::query_builder::{QueryFragment, QueryId, ValuesClause};
459460
use crate::query_source::Column;
460-
use crate::sql_types::{
461-
is_nullable, AllAreNullable, Bool, DieselNumericOps, MaybeNullableType, SqlType,
462-
};
463-
use crate::Expression;
461+
use crate::sql_types::{DieselNumericOps, SqlType};
464462

465463
impl<T, U> Insertable<T::Table> for Eq<T, U>
466464
where
@@ -529,58 +527,3 @@ where
529527
Ok(())
530528
}
531529
}
532-
533-
// or is different
534-
// it only evaluates to null if both sides are null
535-
#[derive(
536-
Debug,
537-
Clone,
538-
Copy,
539-
crate::query_builder::QueryId,
540-
crate::sql_types::DieselNumericOps,
541-
crate::expression::ValidGrouping,
542-
)]
543-
#[doc(hidden)]
544-
pub struct Or<T, U> {
545-
pub(crate) left: T,
546-
pub(crate) right: U,
547-
}
548-
549-
impl<T, U> Or<T, U> {
550-
pub fn new(left: T, right: U) -> Self {
551-
Or { left, right }
552-
}
553-
}
554-
555-
impl_selectable_expression!(Or<T, U>);
556-
557-
impl<T, U> Expression for Or<T, U>
558-
where
559-
T: Expression,
560-
U: Expression,
561-
T::SqlType: SqlType,
562-
U::SqlType: SqlType,
563-
is_nullable::IsSqlTypeNullable<T::SqlType>:
564-
AllAreNullable<is_nullable::IsSqlTypeNullable<U::SqlType>>,
565-
is_nullable::AreAllNullable<T::SqlType, U::SqlType>: MaybeNullableType<Bool>,
566-
{
567-
type SqlType =
568-
is_nullable::MaybeNullable<is_nullable::AreAllNullable<T::SqlType, U::SqlType>, Bool>;
569-
}
570-
571-
impl<T, U, DB> crate::query_builder::QueryFragment<DB> for Or<T, U>
572-
where
573-
DB: crate::backend::Backend,
574-
T: crate::query_builder::QueryFragment<DB>,
575-
U: crate::query_builder::QueryFragment<DB>,
576-
{
577-
fn walk_ast(
578-
&self,
579-
mut out: crate::query_builder::AstPass<DB>,
580-
) -> crate::result::QueryResult<()> {
581-
self.left.walk_ast(out.reborrow())?;
582-
out.push_sql(" OR ");
583-
self.right.walk_ast(out.reborrow())?;
584-
Ok(())
585-
}
586-
}

diesel/src/expression/sql_literal.rs

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ where
7373
///
7474
/// ```rust
7575
/// # include!("../doctest_setup.rs");
76-
///
76+
/// #
7777
/// # table! {
7878
/// # users {
7979
/// # id -> Integer,
@@ -125,7 +125,7 @@ where
125125
///
126126
/// ```rust
127127
/// # include!("../doctest_setup.rs");
128-
///
128+
/// #
129129
/// # table! {
130130
/// # users {
131131
/// # id -> Integer,
@@ -199,7 +199,7 @@ impl<ST, T, GB> ValidGrouping<GB> for SqlLiteral<ST, T> {
199199
type IsAggregate = is_aggregate::Never;
200200
}
201201

202-
/// Use literal SQL in the query builder
202+
/// Use literal SQL in the query builder.
203203
///
204204
/// Available for when you truly cannot represent something using the expression
205205
/// DSL. You will need to provide the SQL type of the expression, in addition to
@@ -209,6 +209,8 @@ impl<ST, T, GB> ValidGrouping<GB> for SqlLiteral<ST, T> {
209209
/// your query. If you want to write the entire query using raw SQL, use
210210
/// [`sql_query`](../fn.sql_query.html) instead.
211211
///
212+
/// Query parameters can be bound into the literal SQL using [`SqlLiteral::bind()`].
213+
///
212214
/// # Safety
213215
///
214216
/// The compiler will be unable to verify the correctness of the annotated type.
@@ -220,10 +222,11 @@ impl<ST, T, GB> ValidGrouping<GB> for SqlLiteral<ST, T> {
220222
/// ```rust
221223
/// # include!("../doctest_setup.rs");
222224
/// # fn main() {
223-
/// # run_test().unwrap();
225+
/// # run_test_1().unwrap();
226+
/// # run_test_2().unwrap();
224227
/// # }
225228
/// #
226-
/// # fn run_test() -> QueryResult<()> {
229+
/// # fn run_test_1() -> QueryResult<()> {
227230
/// # use schema::users::dsl::*;
228231
/// # use diesel::sql_types::Bool;
229232
/// use diesel::dsl::sql;
@@ -233,7 +236,30 @@ impl<ST, T, GB> ValidGrouping<GB> for SqlLiteral<ST, T> {
233236
/// assert_eq!(expected, user);
234237
/// # Ok(())
235238
/// # }
239+
/// #
240+
/// # fn run_test_2() -> QueryResult<()> {
241+
/// # use crate::schema::users::dsl::*;
242+
/// # use diesel::dsl::sql;
243+
/// # use diesel::sql_types::{Bool, Integer, Text};
244+
/// # let connection = establish_connection();
245+
/// # diesel::insert_into(users)
246+
/// # .values(name.eq("Ryan"))
247+
/// # .execute(&connection).unwrap();
248+
/// let query = users
249+
/// .select(name)
250+
/// .filter(
251+
/// sql::<Bool>("id > ")
252+
/// .bind::<Integer,_>(1)
253+
/// .sql(" AND name <> ")
254+
/// .bind::<Text, _>("Ryan")
255+
/// )
256+
/// .get_results(&connection);
257+
/// let expected = vec!["Tess".to_string()];
258+
/// assert_eq!(Ok(expected), query);
259+
/// # Ok(())
260+
/// # }
236261
/// ```
262+
/// [`SqlLiteral::bind()`]: ../expression/struct.SqlLiteral.html#method.bind
237263
pub fn sql<ST>(sql: &str) -> SqlLiteral<ST>
238264
where
239265
ST: TypedExpressionType,
@@ -245,7 +271,7 @@ where
245271
#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
246272
/// Returned by the [`SqlLiteral::bind()`] method when binding a value to a fragment of SQL.
247273
///
248-
/// [`bind()`]: ./struct.SqlLiteral.html#method.bind
274+
/// [`SqlLiteral::bind()`]: ./struct.SqlLiteral.html#method.bind
249275
pub struct UncheckedBind<Query, Value> {
250276
query: Query,
251277
value: Value,
@@ -259,7 +285,7 @@ where
259285
UncheckedBind { query, value }
260286
}
261287

262-
/// Use literal SQL in the query builder
288+
/// Use literal SQL in the query builder.
263289
///
264290
/// This function is intended for use when you need a small bit of raw SQL in
265291
/// your query. If you want to write the entire query using raw SQL, use
@@ -275,7 +301,7 @@ where
275301
///
276302
/// ```rust
277303
/// # include!("../doctest_setup.rs");
278-
///
304+
/// #
279305
/// # table! {
280306
/// # users {
281307
/// # id -> Integer,

diesel/src/query_builder/functions.rs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,13 @@ pub fn replace_into<T>(target: T) -> IncompleteInsertStatement<T, Replace> {
512512
/// supported by the query builder. Unlike most queries in Diesel, `sql_query`
513513
/// will deserialize its data by name, not by index. That means that you cannot
514514
/// deserialize into a tuple, and structs which you deserialize from this
515-
/// function will need to have `#[derive(QueryableByName)]`
515+
/// function will need to have `#[derive(QueryableByName)]`.
516+
///
517+
/// This function is intended for use when you want to write the entire query
518+
/// using raw SQL. If you only need a small bit of raw SQL in your query, use
519+
/// [`sql`](./dsl/fn.sql.html) instead.
520+
///
521+
/// Query parameters can be bound into the raw query using [`SqlQuery::bind()`].
516522
///
517523
/// # Safety
518524
///
@@ -521,7 +527,7 @@ pub fn replace_into<T>(target: T) -> IncompleteInsertStatement<T, Replace> {
521527
/// that the given type is correct. If your query returns a column of an
522528
/// unexpected type, the result may have the wrong value, or return an error.
523529
///
524-
/// # Example
530+
/// # Examples
525531
///
526532
/// ```rust
527533
/// # include!("../doctest_setup.rs");
@@ -536,7 +542,13 @@ pub fn replace_into<T>(target: T) -> IncompleteInsertStatement<T, Replace> {
536542
/// # }
537543
/// #
538544
/// # fn main() {
545+
/// # run_test_1().unwrap();
546+
/// # run_test_2().unwrap();
547+
/// # }
548+
/// #
549+
/// # fn run_test_1() -> QueryResult<()> {
539550
/// # use diesel::sql_query;
551+
/// # use diesel::sql_types::{Integer, Text};
540552
/// #
541553
/// # let connection = establish_connection();
542554
/// let users = sql_query("SELECT * FROM users ORDER BY id")
@@ -546,8 +558,34 @@ pub fn replace_into<T>(target: T) -> IncompleteInsertStatement<T, Replace> {
546558
/// User { id: 2, name: "Tess".into() },
547559
/// ];
548560
/// assert_eq!(Ok(expected_users), users);
561+
/// # Ok(())
562+
/// # }
563+
///
564+
/// # fn run_test_2() -> QueryResult<()> {
565+
/// # use diesel::sql_query;
566+
/// # use diesel::sql_types::{Integer, Text};
567+
/// #
568+
/// # let connection = establish_connection();
569+
/// # diesel::insert_into(users::table)
570+
/// # .values(users::name.eq("Jim"))
571+
/// # .execute(&connection).unwrap();
572+
/// # #[cfg(feature = "postgres")]
573+
/// # let users = sql_query("SELECT * FROM users WHERE id > $1 AND name != $2");
574+
/// # #[cfg(not(feature = "postgres"))]
575+
/// let users = sql_query("SELECT * FROM users WHERE id > ? AND name <> ?")
576+
/// # ;
577+
/// let users = users
578+
/// .bind::<Integer, _>(1)
579+
/// .bind::<Text, _>("Tess")
580+
/// .get_results(&connection);
581+
/// let expected_users = vec![
582+
/// User { id: 3, name: "Jim".into() },
583+
/// ];
584+
/// assert_eq!(Ok(expected_users), users);
585+
/// # Ok(())
549586
/// # }
550587
/// ```
588+
/// [`SqlQuery::bind()`]: query_builder/struct.SqlQuery.html#method.bind
551589
pub fn sql_query<T: Into<String>>(query: T) -> SqlQuery<()> {
552590
SqlQuery::new((), query.into())
553591
}

diesel/src/query_builder/sql_query.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ impl<Inner, Conn> RunQueryDsl<Conn> for SqlQuery<Inner> {}
124124

125125
#[derive(Debug, Clone, Copy)]
126126
#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
127+
/// Returned by the [`SqlQuery::bind()`] method when binding a value to a fragment of SQL.
128+
///
129+
/// [`SqlQuery::bind()`]: ./struct.SqlQuery.html#method.bind
127130
pub struct UncheckedBind<Query, Value, ST> {
128131
query: Query,
129132
value: Value,
@@ -147,6 +150,65 @@ impl<Query, Value, ST> UncheckedBind<Query, Value, ST> {
147150
BoxedSqlQuery::new(self)
148151
}
149152

153+
/// Construct a full SQL query using raw SQL.
154+
///
155+
/// This function exists for cases where a query needs to be written that is not
156+
/// supported by the query builder. Unlike most queries in Diesel, `sql_query`
157+
/// will deserialize its data by name, not by index. That means that you cannot
158+
/// deserialize into a tuple, and structs which you deserialize from this
159+
/// function will need to have `#[derive(QueryableByName)]`.
160+
///
161+
/// This function is intended for use when you want to write the entire query
162+
/// using raw SQL. If you only need a small bit of raw SQL in your query, use
163+
/// [`sql`](./dsl/fn.sql.html) instead.
164+
///
165+
/// Query parameters can be bound into the raw query using [`SqlQuery::bind()`].
166+
///
167+
/// # Safety
168+
///
169+
/// The implementation of `QueryableByName` will assume that columns with a
170+
/// given name will have a certain type. The compiler will be unable to verify
171+
/// that the given type is correct. If your query returns a column of an
172+
/// unexpected type, the result may have the wrong value, or return an error.
173+
///
174+
/// # Examples
175+
///
176+
/// ```rust
177+
/// # include!("../doctest_setup.rs");
178+
/// #
179+
/// # use schema::users;
180+
/// #
181+
/// # #[derive(QueryableByName, Debug, PartialEq)]
182+
/// # #[table_name="users"]
183+
/// # struct User {
184+
/// # id: i32,
185+
/// # name: String,
186+
/// # }
187+
/// #
188+
/// # fn main() {
189+
/// # use diesel::sql_query;
190+
/// # use diesel::sql_types::{Integer, Text};
191+
/// #
192+
/// # let connection = establish_connection();
193+
/// # diesel::insert_into(users::table)
194+
/// # .values(users::name.eq("Jim"))
195+
/// # .execute(&connection).unwrap();
196+
/// # #[cfg(feature = "postgres")]
197+
/// # let users = sql_query("SELECT * FROM users WHERE id > $1 AND name != $2");
198+
/// # #[cfg(not(feature = "postgres"))]
199+
/// let users = sql_query("SELECT * FROM users WHERE id > ? AND name <> ?")
200+
/// # ;
201+
/// # let users = users
202+
/// .bind::<Integer, _>(1)
203+
/// .bind::<Text, _>("Tess")
204+
/// .get_results(&connection);
205+
/// let expected_users = vec![
206+
/// User { id: 3, name: "Jim".into() },
207+
/// ];
208+
/// assert_eq!(Ok(expected_users), users);
209+
/// # }
210+
/// ```
211+
/// [`SqlQuery::bind()`]: query_builder/struct.SqlQuery.html#method.bind
150212
pub fn sql<T: Into<String>>(self, sql: T) -> SqlQuery<Self> {
151213
SqlQuery::new(self, sql.into())
152214
}

0 commit comments

Comments
 (0)