diesel/query_builder/
debug_query.rs

1use super::{AstPass, QueryBuilder, QueryFragment};
2use crate::backend::Backend;
3use std::fmt::{self, Debug, Display};
4use std::marker::PhantomData;
5
6/// A struct that implements `fmt::Display` and `fmt::Debug` to show the SQL
7/// representation of a query.
8///
9/// The `Display` implementation will be the exact query sent to the server,
10/// plus a comment with the values of the bind parameters. The `Debug`
11/// implementation is more structured, and able to be pretty printed.
12///
13/// See [`debug_query`] for usage examples.
14///
15/// [`debug_query`]: crate::query_builder::debug_query()
16pub struct DebugQuery<'a, T: 'a, DB> {
17    pub(crate) query: &'a T,
18    _marker: PhantomData<DB>,
19}
20
21impl<'a, T, DB> DebugQuery<'a, T, DB> {
22    pub(crate) fn new(query: &'a T) -> Self {
23        DebugQuery {
24            query,
25            _marker: PhantomData,
26        }
27    }
28}
29
30fn serialize_query<DB>(query: &dyn QueryFragment<DB>) -> Result<String, fmt::Error>
31where
32    DB: Backend + Default,
33    DB::QueryBuilder: Default,
34{
35    let mut query_builder = DB::QueryBuilder::default();
36    let backend = DB::default();
37    QueryFragment::<DB>::to_sql(query, &mut query_builder, &backend).map_err(|_| fmt::Error)?;
38    Ok(query_builder.finish())
39}
40
41fn display<DB>(query: &dyn QueryFragment<DB>, f: &mut fmt::Formatter<'_>) -> fmt::Result
42where
43    DB: Backend + Default,
44    DB::QueryBuilder: Default,
45{
46    let debug_binds = DebugBinds::<DB>::new(query);
47    let query = serialize_query(query)?;
48    write!(f, "{} -- binds: {:?}", query, debug_binds)
49}
50
51fn debug<DB>(query: &dyn QueryFragment<DB>, f: &mut fmt::Formatter<'_>) -> fmt::Result
52where
53    DB: Backend + Default,
54    DB::QueryBuilder: Default,
55{
56    let debug_binds = DebugBinds::<DB>::new(query);
57    let query = serialize_query(query)?;
58    f.debug_struct("Query")
59        .field("sql", &query)
60        .field("binds", &debug_binds)
61        .finish()
62}
63
64impl<T, DB> Display for DebugQuery<'_, T, DB>
65where
66    DB: Backend + Default,
67    DB::QueryBuilder: Default,
68    T: QueryFragment<DB>,
69{
70    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71        display(self.query, f)
72    }
73}
74
75impl<T, DB> Debug for DebugQuery<'_, T, DB>
76where
77    DB: Backend + Default,
78    DB::QueryBuilder: Default,
79    T: QueryFragment<DB>,
80{
81    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82        debug(self.query, f)
83    }
84}
85
86/// A struct that implements `fmt::Debug` by walking the given AST and writing
87/// the `fmt::Debug` implementation of each bind parameter.
88pub(crate) struct DebugBinds<'a, DB> {
89    query: &'a dyn QueryFragment<DB>,
90}
91
92impl<'a, DB> DebugBinds<'a, DB>
93where
94    DB: Backend,
95{
96    fn new(query: &'a dyn QueryFragment<DB>) -> Self {
97        DebugBinds { query }
98    }
99}
100
101impl<DB> Debug for DebugBinds<'_, DB>
102where
103    DB: Backend + Default,
104{
105    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106        let backend = DB::default();
107        let mut buffer = Vec::new();
108        let ast_pass = AstPass::debug_binds(&mut buffer, &backend);
109        self.query.walk_ast(ast_pass).map_err(|_| fmt::Error)?;
110        format_list(f, &buffer)
111    }
112}
113
114fn format_list<'b>(f: &mut fmt::Formatter<'_>, entries: &[Box<dyn Debug + 'b>]) -> fmt::Result {
115    let mut list = f.debug_list();
116    for entry in entries {
117        list.entry(entry);
118    }
119    list.finish()
120}