Skip to main content

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 fmt_query<DB>(
42    query: &dyn QueryFragment<DB>,
43    f: &mut fmt::Formatter<'_>,
44    formatter: fn(String, &DebugBinds<'_>, f: &mut fmt::Formatter<'_>) -> fmt::Result,
45) -> fmt::Result
46where
47    DB: Backend + Default,
48    DB::QueryBuilder: Default,
49{
50    let backend = DB::default();
51    let mut buffer = Vec::new();
52    let ast_pass = AstPass::debug_binds(&mut buffer, &backend);
53    query.walk_ast(ast_pass).map_err(|_| fmt::Error)?;
54    let debug_binds = DebugBinds::new(&buffer);
55    let query = serialize_query(query)?;
56    formatter(query, &debug_binds, f)
57}
58
59pub(crate) fn display(
60    query: String,
61    debug_binds: &DebugBinds<'_>,
62    f: &mut fmt::Formatter<'_>,
63) -> fmt::Result {
64    f.write_fmt(format_args!("{0} -- binds: {1:?}", query, debug_binds))write!(f, "{query} -- binds: {debug_binds:?}")
65}
66
67pub(crate) fn debug(
68    query: String,
69    debug_binds: &DebugBinds<'_>,
70    f: &mut fmt::Formatter<'_>,
71) -> fmt::Result {
72    f.debug_struct("Query")
73        .field("sql", &query)
74        .field("binds", &debug_binds)
75        .finish()
76}
77
78impl<T, DB> Display for DebugQuery<'_, T, DB>
79where
80    DB: Backend + Default,
81    DB::QueryBuilder: Default,
82    T: QueryFragment<DB>,
83{
84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85        fmt_query(self.query, f, display)
86    }
87}
88
89impl<T, DB> Debug for DebugQuery<'_, T, DB>
90where
91    DB: Backend + Default,
92    DB::QueryBuilder: Default,
93    T: QueryFragment<DB>,
94{
95    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96        fmt_query(self.query, f, debug)
97    }
98}
99
100/// A struct that implements `fmt::Debug` by walking the given AST and writing
101/// the `fmt::Debug` implementation of each bind parameter.
102pub(crate) struct DebugBinds<'a> {
103    binds: &'a [Box<dyn Debug + 'a>],
104}
105
106impl<'a> DebugBinds<'a> {
107    pub(crate) fn new(binds: &'a [Box<dyn Debug + 'a>]) -> Self {
108        DebugBinds { binds }
109    }
110}
111
112impl Debug for DebugBinds<'_> {
113    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114        format_list(f, self.binds)
115    }
116}
117
118fn format_list<'b>(f: &mut fmt::Formatter<'_>, entries: &[Box<dyn Debug + 'b>]) -> fmt::Result {
119    let mut list = f.debug_list();
120    for entry in entries {
121        list.entry(entry);
122    }
123    list.finish()
124}