mirror of
https://github.com/diesel-rs/diesel.git
synced 2024-10-04 01:28:13 +03:00
Include bind parameters in debug_sql!
I've implemented this as a separate AST pass, rather than the `CollectBinds` pass of the `Debug` backend. This is because we will ultimately want to use this same code for logging, which won't have the `QueryFragment<Debug>` constraint. Ultimately I think I want to get rid of the `Debug` backend entirely once logging is implemented. I had originally implemented this by adding two additional lifetime parameters onto `AstPass`. However, I really disliked how opaque and random these two extra parameters felt, and it made the type harder to document (and use). Shortening an invariant lifetime like this is actually one of the documented use cases that `mem::transmute` is useful for. I don't like introducing unsafe code in general, but I felt that the tradeoff was worth it in this case.
This commit is contained in:
parent
83efa6664f
commit
47f1710a5c
@ -10,9 +10,10 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/
|
||||
|
||||
* Added helper types for inner join and left outer join
|
||||
|
||||
* `diesel::debug_sql` has been added as a replacement for `debug_sql!`. This
|
||||
* `diesel::debug_query` has been added as a replacement for `debug_sql!`. This
|
||||
function differs from the macro by allowing you to specify the backend, and
|
||||
will generate the actual query which will be run.
|
||||
will generate the actual query which will be run. The returned value will
|
||||
implement `Display` and `Debug` to show the query in different ways
|
||||
|
||||
* `diesel::pg::PgConnection`, `diesel::mysql::MysqlConnection`, and
|
||||
`diesel::sqlite::SqliteConnection` are now exported from `diesel::prelude`.
|
||||
@ -47,7 +48,7 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/
|
||||
|
||||
### Removed
|
||||
|
||||
* `debug_sql!` has been deprecated in favor of `diesel::debug_sql`.
|
||||
* `debug_sql!` has been deprecated in favor of `diesel::debug_query`.
|
||||
|
||||
* `print_sql!` has been deprecated without replacement.
|
||||
|
||||
|
@ -144,7 +144,7 @@ pub mod prelude {
|
||||
|
||||
pub use prelude::*;
|
||||
#[doc(inline)]
|
||||
pub use query_builder::debug_sql;
|
||||
pub use query_builder::debug_query;
|
||||
#[doc(inline)]
|
||||
pub use query_builder::functions::{insert, update, delete, select, insert_default_values};
|
||||
#[cfg(feature = "sqlite")]
|
||||
|
@ -999,15 +999,23 @@ macro_rules! enable_multi_table_joins {
|
||||
/// # fn main() {
|
||||
/// let sql = debug_sql!(users.count());
|
||||
/// if cfg!(feature = "postgres") {
|
||||
/// assert_eq!(sql, r#"SELECT COUNT(*) FROM "users""#);
|
||||
/// assert_eq!(sql, r#"SELECT COUNT(*) FROM "users" -- binds: []"#);
|
||||
/// } else {
|
||||
/// assert_eq!(sql, "SELECT COUNT(*) FROM `users`");
|
||||
/// assert_eq!(sql, "SELECT COUNT(*) FROM `users` -- binds: []");
|
||||
/// }
|
||||
///
|
||||
/// let sql = debug_sql!(users.filter(n.eq(1)));
|
||||
/// if cfg!(feature = "postgres") {
|
||||
/// assert_eq!(sql, r#"SELECT "users"."id", "users"."n" FROM "users" WHERE "users"."n" = $1 -- binds: [1]"#);
|
||||
/// } else {
|
||||
/// assert_eq!(sql, "SELECT `users`.`id`, `users`.`n` FROM `users` WHERE \
|
||||
/// `users`.`n` = ? -- binds: [1]");
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(feature = "with-deprecated")]
|
||||
#[macro_export]
|
||||
#[deprecated(since = "0.16.0", note = "use `diesel::debug_sql` instead")]
|
||||
#[deprecated(since = "0.16.0", note = "use `diesel::debug_query(...).to_string()` instead")]
|
||||
macro_rules! debug_sql {
|
||||
($query:expr) => {
|
||||
$crate::query_builder::deprecated_debug_sql(&$query)
|
||||
@ -1039,7 +1047,7 @@ macro_rules! debug_sql {
|
||||
/// ```
|
||||
#[macro_export]
|
||||
#[cfg(feature = "with-deprecated")]
|
||||
#[deprecated(since = "0.16.0", note = "use `println!(\"{}\", diesel::debug_sql(...))` instead")]
|
||||
#[deprecated(since = "0.16.0", note = "use `println!(\"{}\", diesel::debug_query(...))` instead")]
|
||||
macro_rules! print_sql {
|
||||
($query:expr) => {
|
||||
println!("{}", debug_sql!($query));
|
||||
@ -1105,8 +1113,8 @@ mod tests {
|
||||
#[cfg(feature = "postgres")]
|
||||
fn table_with_custom_schema() {
|
||||
use pg::Pg;
|
||||
let expected_sql = r#"SELECT "foo"."bars"."baz" FROM "foo"."bars""#;
|
||||
assert_eq!(expected_sql, ::debug_sql::<Pg, _>(&bars::table.select(bars::baz)));
|
||||
let expected_sql = r#"SELECT "foo"."bars"."baz" FROM "foo"."bars" -- binds: []"#;
|
||||
assert_eq!(expected_sql, &::debug_query::<Pg, _>(&bars::table.select(bars::baz)).to_string());
|
||||
}
|
||||
|
||||
table! {
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::{fmt, mem};
|
||||
|
||||
use backend::Backend;
|
||||
use query_builder::{BindCollector, QueryBuilder};
|
||||
use result::QueryResult;
|
||||
@ -55,6 +57,15 @@ impl<'a, DB> AstPass<'a, DB> where
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn debug_binds(
|
||||
formatter: &'a mut fmt::DebugList<'a, 'a>,
|
||||
) -> Self {
|
||||
AstPass {
|
||||
internals: AstPassInternals::DebugBinds(formatter),
|
||||
}
|
||||
}
|
||||
|
||||
/// Call this method whenever you pass an instance of `AstPass` by value.
|
||||
///
|
||||
/// Effectively copies `self`, with a narrower lifetime. When passing a
|
||||
@ -75,6 +86,11 @@ impl<'a, DB> AstPass<'a, DB> where
|
||||
}
|
||||
}
|
||||
IsSafeToCachePrepared(ref mut result) => IsSafeToCachePrepared(&mut **result),
|
||||
DebugBinds(ref mut f) => {
|
||||
// Safe because the lifetime is always being shortened.
|
||||
let f_with_shorter_lifetime = unsafe { mem::transmute(&mut **f) };
|
||||
DebugBinds(f_with_shorter_lifetime)
|
||||
}
|
||||
};
|
||||
AstPass { internals }
|
||||
}
|
||||
@ -155,6 +171,9 @@ impl<'a, DB> AstPass<'a, DB> where
|
||||
ToSql(ref mut out) => out.push_bind_param(),
|
||||
CollectBinds { ref mut collector, metadata_lookup } =>
|
||||
collector.push_bound_value(bind, metadata_lookup)?,
|
||||
DebugBinds(ref mut f) => {
|
||||
f.entry(bind);
|
||||
}
|
||||
_ => {}, // noop
|
||||
}
|
||||
Ok(())
|
||||
@ -176,8 +195,10 @@ impl<'a, DB> AstPass<'a, DB> where
|
||||
DB: HasSqlType<T>,
|
||||
U: ToSql<T, DB>,
|
||||
{
|
||||
if let AstPassInternals::CollectBinds { .. } = self.internals {
|
||||
self.push_bind_param(bind)?;
|
||||
use self::AstPassInternals::*;
|
||||
match self.internals {
|
||||
CollectBinds { .. } | DebugBinds(..) => self.push_bind_param(bind)?,
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -200,4 +221,5 @@ enum AstPassInternals<'a, DB> where
|
||||
metadata_lookup: &'a DB::MetadataLookup,
|
||||
},
|
||||
IsSafeToCachePrepared(&'a mut bool),
|
||||
DebugBinds(&'a mut fmt::DebugList<'a, 'a>),
|
||||
}
|
||||
|
91
diesel/src/query_builder/debug_query.rs
Normal file
91
diesel/src/query_builder/debug_query.rs
Normal file
@ -0,0 +1,91 @@
|
||||
use std::fmt::{self, Display, Debug};
|
||||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
|
||||
use backend::Backend;
|
||||
use super::{QueryBuilder, QueryFragment, AstPass};
|
||||
|
||||
/// A struct that implements `fmt::Display` and `fmt::Debug` to show the SQL
|
||||
/// representation of a query.
|
||||
///
|
||||
/// The `Display` implementation will be the exact query sent to the server,
|
||||
/// plus a comment with the values of the bind parameters. The `Debug`
|
||||
/// implementation is more structured, and able to be pretty printed.
|
||||
pub struct DebugQuery<'a, T: 'a, DB> {
|
||||
query: &'a T,
|
||||
_marker: PhantomData<DB>,
|
||||
}
|
||||
|
||||
impl<'a, T, DB> DebugQuery<'a, T, DB> {
|
||||
pub(crate) fn new(query: &'a T) -> Self {
|
||||
DebugQuery {
|
||||
query,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, DB> Display for DebugQuery<'a, T, DB> where
|
||||
DB: Backend,
|
||||
DB::QueryBuilder: Default,
|
||||
T: QueryFragment<DB>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut query_builder = DB::QueryBuilder::default();
|
||||
QueryFragment::<DB>::to_sql(self.query, &mut query_builder)
|
||||
.map_err(|_| fmt::Error)?;
|
||||
let debug_binds = DebugBinds::<_, DB>::new(self.query);
|
||||
write!(f, "{} -- binds: {:?}", query_builder.finish(), debug_binds)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, DB> Debug for DebugQuery<'a, T, DB> where
|
||||
DB: Backend,
|
||||
DB::QueryBuilder: Default,
|
||||
T: QueryFragment<DB>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut query_builder = DB::QueryBuilder::default();
|
||||
QueryFragment::<DB>::to_sql(self.query, &mut query_builder)
|
||||
.map_err(|_| fmt::Error)?;
|
||||
let debug_binds = DebugBinds::<_, DB>::new(self.query);
|
||||
f.debug_struct("Query")
|
||||
.field("sql", &query_builder.finish())
|
||||
.field("binds", &debug_binds)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// A struct that implements `fmt::Debug` by walking the given AST and writing
|
||||
/// the `fmt::Debug` implementation of each bind parameter.
|
||||
pub struct DebugBinds<'a, T: 'a, DB> {
|
||||
query: &'a T,
|
||||
_marker: PhantomData<DB>,
|
||||
}
|
||||
|
||||
impl<'a, T, DB> DebugBinds<'a, T, DB> {
|
||||
fn new(query: &'a T) -> Self {
|
||||
DebugBinds {
|
||||
query,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, DB> Debug for DebugBinds<'a, T, DB> where
|
||||
DB: Backend,
|
||||
T: QueryFragment<DB>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut list = f.debug_list();
|
||||
{
|
||||
// Safe because the lifetime is shortened to one smaller
|
||||
// than the lifetime of the formatter.
|
||||
let list_with_shorter_lifetime = unsafe { mem::transmute(&mut list) };
|
||||
let ast_pass = AstPass::debug_binds(list_with_shorter_lifetime);
|
||||
self.query.walk_ast(ast_pass).map_err(|_| fmt::Error)?;
|
||||
}
|
||||
list.finish()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ mod clause_macro;
|
||||
|
||||
mod ast_pass;
|
||||
pub mod bind_collector;
|
||||
mod debug_query;
|
||||
mod delete_statement;
|
||||
#[doc(hidden)]
|
||||
pub mod functions;
|
||||
@ -30,6 +31,7 @@ pub mod update_statement;
|
||||
|
||||
pub use self::ast_pass::AstPass;
|
||||
pub use self::bind_collector::BindCollector;
|
||||
pub use self::debug_query::DebugQuery;
|
||||
pub use self::query_id::QueryId;
|
||||
#[doc(hidden)]
|
||||
pub use self::select_statement::{SelectStatement, BoxedSelectStatement};
|
||||
@ -148,8 +150,13 @@ impl<T: Query> AsQuery for T {
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes a query `QueryFragment` expression as an argument and returns a string
|
||||
/// of SQL with placeholders for the dynamic values.
|
||||
/// Takes a query `QueryFragment` expression as an argument and returns a type
|
||||
/// that implements `fmt::Display` and `fmt::Debug` to show the query.
|
||||
///
|
||||
/// The `Display` implementation will show the exact query being sent to the
|
||||
/// server, with a comment showing the values of the bind parameters. The
|
||||
/// `Debug` implementation will include the same information in a more
|
||||
/// structured form, and respects pretty printing.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
@ -164,23 +171,36 @@ impl<T: Query> AsQuery for T {
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// # use schema::users::dsl::*;
|
||||
/// let sql = debug_sql::<DB, _>(&users.count());
|
||||
/// if cfg!(feature = "postgres") {
|
||||
/// assert_eq!(sql, r#"SELECT COUNT(*) FROM "users""#);
|
||||
/// } else {
|
||||
/// assert_eq!(sql, "SELECT COUNT(*) FROM `users`");
|
||||
/// }
|
||||
/// let sql = debug_query::<DB, _>(&users.count()).to_string();
|
||||
/// # if cfg!(feature = "postgres") {
|
||||
/// # assert_eq!(sql, r#"SELECT COUNT(*) FROM "users" -- binds: []"#);
|
||||
/// # } else {
|
||||
/// assert_eq!(sql, "SELECT COUNT(*) FROM `users` -- binds: []");
|
||||
/// # }
|
||||
///
|
||||
/// let query = users.find(1);
|
||||
/// let debug = debug_query::<DB, _>(&query);
|
||||
/// # if cfg!(feature = "postgres") {
|
||||
/// # assert_eq!(debug.to_string(), "SELECT \"users\".\"id\", \"users\".\"name\" \
|
||||
/// # FROM \"users\" WHERE \"users\".\"id\" = $1 -- binds: [1]");
|
||||
/// # } else {
|
||||
/// assert_eq!(debug.to_string(), "SELECT `users`.`id`, `users`.`name` FROM `users` \
|
||||
/// WHERE `users`.`id` = ? -- binds: [1]");
|
||||
/// # }
|
||||
///
|
||||
/// let debug = format!("{:?}", debug);
|
||||
/// # if !cfg!(feature = "postgres") { // Escaping that string is a pain
|
||||
/// let expected = "Query { \
|
||||
/// sql: \"SELECT `users`.`id`, `users`.`name` FROM `users` WHERE \
|
||||
/// `users`.`id` = ?\", \
|
||||
/// binds: [1] \
|
||||
/// }";
|
||||
/// assert_eq!(debug, expected);
|
||||
/// # }
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn debug_sql<DB, T>(query: &T) -> String where
|
||||
DB: Backend,
|
||||
DB::QueryBuilder: Default,
|
||||
T: QueryFragment<DB>,
|
||||
{
|
||||
let mut query_builder = DB::QueryBuilder::default();
|
||||
QueryFragment::<DB>::to_sql(query, &mut query_builder)
|
||||
.expect("Failed to construct query");
|
||||
query_builder.finish()
|
||||
pub fn debug_query<DB, T>(query: &T) -> DebugQuery<T, DB> {
|
||||
DebugQuery::new(query)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
@ -188,7 +208,7 @@ pub fn debug_sql<DB, T>(query: &T) -> String where
|
||||
pub fn deprecated_debug_sql<T>(query: &T) -> String where
|
||||
T: QueryFragment<::pg::Pg>,
|
||||
{
|
||||
debug_sql(query)
|
||||
debug_query(query).to_string()
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
@ -196,7 +216,7 @@ pub fn deprecated_debug_sql<T>(query: &T) -> String where
|
||||
pub fn deprecated_debug_sql<T>(query: &T) -> String where
|
||||
T: QueryFragment<::mysql::Mysql>,
|
||||
{
|
||||
debug_sql(query)
|
||||
debug_query(query).to_string()
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
@ -204,7 +224,7 @@ pub fn deprecated_debug_sql<T>(query: &T) -> String where
|
||||
pub fn deprecated_debug_sql<T>(query: &T) -> String where
|
||||
T: QueryFragment<::sqlite::Sqlite>,
|
||||
{
|
||||
debug_sql(query)
|
||||
debug_query(query).to_string()
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
|
@ -59,8 +59,8 @@ fn simple_belongs_to() {
|
||||
let filter = posts::table.filter(posts::user_id.eq(42));
|
||||
|
||||
assert_eq!(
|
||||
debug_sql::<Backend, _>(&belong_to),
|
||||
debug_sql::<Backend, _>(&filter)
|
||||
debug_query::<Backend, _>(&belong_to).to_string(),
|
||||
debug_query::<Backend, _>(&filter).to_string()
|
||||
);
|
||||
}
|
||||
|
||||
@ -118,8 +118,8 @@ fn custom_foreign_key() {
|
||||
let filter = posts::table.filter(posts::belongs_to_user.eq(42));
|
||||
|
||||
assert_eq!(
|
||||
debug_sql::<Backend, _>(&belong_to),
|
||||
debug_sql::<Backend, _>(&filter)
|
||||
debug_query::<Backend, _>(&belong_to).to_string(),
|
||||
debug_query::<Backend, _>(&filter).to_string()
|
||||
);
|
||||
}
|
||||
|
||||
@ -146,7 +146,7 @@ fn self_referential() {
|
||||
let belong_to = Tree::belonging_to(&t);
|
||||
let filter = trees::table.filter(trees::parent_id.eq(42));
|
||||
assert_eq!(
|
||||
debug_sql::<Backend, _>(&belong_to),
|
||||
debug_sql::<Backend, _>(&filter)
|
||||
debug_query::<Backend, _>(&belong_to).to_string(),
|
||||
debug_query::<Backend, _>(&filter).to_string()
|
||||
);
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ use diesel::*;
|
||||
#[test]
|
||||
fn test_debug_count_output() {
|
||||
use schema::users::dsl::*;
|
||||
let sql = debug_sql::<TestBackend, _>(&users.count());
|
||||
let sql = debug_query::<TestBackend, _>(&users.count()).to_string();
|
||||
if cfg!(feature = "postgres") {
|
||||
assert_eq!(sql, r#"SELECT COUNT(*) FROM "users""#);
|
||||
assert_eq!(sql, r#"SELECT COUNT(*) FROM "users" -- binds: []"#);
|
||||
} else {
|
||||
assert_eq!(sql, "SELECT COUNT(*) FROM `users`");
|
||||
assert_eq!(sql, "SELECT COUNT(*) FROM `users` -- binds: []");
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,10 +16,10 @@ fn test_debug_count_output() {
|
||||
fn test_debug_output() {
|
||||
use schema::users::dsl::*;
|
||||
let command = update(users.filter(id.eq(1))).set(name.eq("new_name"));
|
||||
let sql = debug_sql::<TestBackend, _>(&command);
|
||||
let sql = debug_query::<TestBackend, _>(&command).to_string();
|
||||
if cfg!(feature = "postgres") {
|
||||
assert_eq!(sql, r#"UPDATE "users" SET "name" = $1 WHERE "users"."id" = $2"#)
|
||||
assert_eq!(sql, r#"UPDATE "users" SET "name" = $1 WHERE "users"."id" = $2 -- binds: ["new_name", 1]"#)
|
||||
} else {
|
||||
assert_eq!(sql, "UPDATE `users` SET `name` = ? WHERE `users`.`id` = ?")
|
||||
assert_eq!(sql, r#"UPDATE `users` SET `name` = ? WHERE `users`.`id` = ? -- binds: ["new_name", 1]"#)
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ fn test_count_star() {
|
||||
assert_eq!(Ok(1), source.first(&connection));
|
||||
|
||||
// Ensure we're doing COUNT(*) instead of COUNT(table.*) which is going to be more efficient
|
||||
assert!(debug_sql::<TestBackend, _>(&source).starts_with("SELECT COUNT(*) FROM"));
|
||||
assert!(debug_query::<TestBackend, _>(&source).to_string().starts_with("SELECT COUNT(*) FROM"));
|
||||
}
|
||||
|
||||
table! {
|
||||
|
@ -9,12 +9,13 @@ fn group_by_generates_group_by_sql() {
|
||||
let source = users::table.group_by(users::name).select(users::id).filter(users::hair_color.is_null());
|
||||
let mut expected_sql = "SELECT `users`.`id` FROM `users` \
|
||||
WHERE `users`.`hair_color` IS NULL \
|
||||
GROUP BY `users`.`name`".to_string();
|
||||
GROUP BY `users`.`name` \
|
||||
-- binds: []".to_string();
|
||||
if cfg!(feature = "postgres") {
|
||||
expected_sql = expected_sql.replace('`', "\"");
|
||||
}
|
||||
|
||||
assert_eq!(expected_sql, debug_sql::<TestBackend, _>(&source));
|
||||
assert_eq!(expected_sql, debug_query::<TestBackend, _>(&source).to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -28,10 +29,11 @@ fn boxed_queries_have_group_by_method() {
|
||||
.filter(users::hair_color.is_null());
|
||||
let mut expected_sql = "SELECT `users`.`id` FROM `users` \
|
||||
WHERE `users`.`hair_color` IS NULL \
|
||||
GROUP BY `users`.`name`".to_string();
|
||||
GROUP BY `users`.`name` \
|
||||
-- binds: []".to_string();
|
||||
if cfg!(feature = "postgres") {
|
||||
expected_sql = expected_sql.replace('`', "\"");
|
||||
}
|
||||
|
||||
assert_eq!(expected_sql, debug_sql(&source));
|
||||
assert_eq!(expected_sql, debug_query(&source).to_string());
|
||||
}
|
||||
|
@ -4,6 +4,10 @@
|
||||
use std::time::SystemTime;
|
||||
|
||||
use diesel::prelude::*;
|
||||
#[cfg(test)]
|
||||
use diesel::debug_query;
|
||||
#[cfg(test)]
|
||||
use diesel::pg::Pg;
|
||||
|
||||
table! {
|
||||
posts {
|
||||
@ -38,8 +42,8 @@ fn examine_sql_from_publish_all_posts() {
|
||||
use posts::dsl::*;
|
||||
|
||||
assert_eq!(
|
||||
"UPDATE \"posts\" SET \"draft\" = $1".to_string(),
|
||||
debug_sql!(diesel::update(posts).set(draft.eq(false)))
|
||||
"UPDATE \"posts\" SET \"draft\" = $1 -- binds: [false]",
|
||||
debug_query(&diesel::update(posts).set(draft.eq(false))).to_string()
|
||||
);
|
||||
}
|
||||
|
||||
@ -60,8 +64,9 @@ fn examine_sql_from_publish_pending_posts() {
|
||||
let target = posts.filter(publish_at.lt(now));
|
||||
assert_eq!(
|
||||
"UPDATE \"posts\" SET \"draft\" = $1 \
|
||||
WHERE \"posts\".\"publish_at\" < CURRENT_TIMESTAMP".to_string(),
|
||||
debug_sql!(diesel::update(target).set(draft.eq(false)))
|
||||
WHERE \"posts\".\"publish_at\" < CURRENT_TIMESTAMP \
|
||||
-- binds: [false]",
|
||||
debug_query(&diesel::update(target).set(draft.eq(false))).to_string()
|
||||
);
|
||||
}
|
||||
|
||||
@ -81,8 +86,9 @@ fn examine_sql_from_publish_post() {
|
||||
visit_count: 0,
|
||||
};
|
||||
assert_eq!(
|
||||
"UPDATE \"posts\" SET \"draft\" = $1 WHERE \"posts\".\"id\" = $2".to_string(),
|
||||
debug_sql!(diesel::update(&post).set(posts::draft.eq(false)))
|
||||
"UPDATE \"posts\" SET \"draft\" = $1 WHERE \"posts\".\"id\" = $2 \
|
||||
-- binds: [false, 1]",
|
||||
debug_query(&diesel::update(&post).set(posts::draft.eq(false))).to_string()
|
||||
);
|
||||
}
|
||||
|
||||
@ -98,8 +104,9 @@ fn examine_sql_from_increment_visit_counts() {
|
||||
use posts::dsl::*;
|
||||
|
||||
assert_eq!(
|
||||
"UPDATE \"posts\" SET \"visit_count\" = \"posts\".\"visit_count\" + $1".to_string(),
|
||||
debug_sql!(diesel::update(posts).set(visit_count.eq(visit_count + 1)))
|
||||
"UPDATE \"posts\" SET \"visit_count\" = \"posts\".\"visit_count\" + $1 \
|
||||
-- binds: [1]",
|
||||
debug_query::<Pg, _>(&diesel::update(posts).set(visit_count.eq(visit_count + 1))).to_string()
|
||||
);
|
||||
}
|
||||
|
||||
@ -123,8 +130,9 @@ fn examine_sql_from_hide_everything() {
|
||||
body.eq("This post has been classified"),
|
||||
));
|
||||
assert_eq!(
|
||||
"UPDATE \"posts\" SET \"title\" = $1, \"body\" = $2".to_string(),
|
||||
debug_sql!(query)
|
||||
"UPDATE \"posts\" SET \"title\" = $1, \"body\" = $2 \
|
||||
-- binds: [\"[REDACTED]\", \"This post has been classified\"]",
|
||||
debug_query::<Pg, _>(&query).to_string()
|
||||
);
|
||||
}
|
||||
|
||||
@ -135,22 +143,32 @@ pub fn update_from_post_fields(post: Post, conn: &PgConnection) -> QueryResult<u
|
||||
|
||||
#[test]
|
||||
fn examine_sql_from_update_post_fields() {
|
||||
let now = SystemTime::now();
|
||||
let post = Post {
|
||||
id: 1,
|
||||
title: "".into(),
|
||||
body: "".into(),
|
||||
draft: false,
|
||||
publish_at: SystemTime::now(),
|
||||
publish_at: now,
|
||||
visit_count: 0,
|
||||
};
|
||||
assert_eq!(
|
||||
let sql = format!(
|
||||
"UPDATE \"posts\" SET \
|
||||
\"title\" = $1, \
|
||||
\"body\" = $2, \
|
||||
\"draft\" = $3, \
|
||||
\"publish_at\" = $4, \
|
||||
\"visit_count\" = $5".to_string(),
|
||||
debug_sql!(diesel::update(posts::table).set(&post))
|
||||
\"visit_count\" = $5 \
|
||||
-- binds: [\
|
||||
\"\", \
|
||||
\"\", \
|
||||
false, \
|
||||
{:?}, \
|
||||
0\
|
||||
]", now);
|
||||
assert_eq!(
|
||||
sql,
|
||||
debug_query(&diesel::update(posts::table).set(&post)).to_string()
|
||||
);
|
||||
}
|
||||
|
||||
@ -186,7 +204,8 @@ fn examine_sql_from_update_with_option() {
|
||||
let query = diesel::update(posts::table)
|
||||
.set(&post_form);
|
||||
assert_eq!(
|
||||
"UPDATE \"posts\" SET \"body\" = $1".to_string(),
|
||||
debug_sql!(query)
|
||||
"UPDATE \"posts\" SET \"body\" = $1 \
|
||||
-- binds: [\"My new post\"]",
|
||||
debug_query::<Pg, _>(&query).to_string()
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user