Skip to main content

diesel/query_builder/
debug_query.rs

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