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