Skip to main content

tank_core/writer/
context.rs

1use crate::TableRef;
2use std::borrow::Cow;
3
4/// Represents the context or part of the SQL statement currently being generated.
5#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
6pub enum Fragment {
7    #[default]
8    None,
9    Aliasing,
10    Casting,
11    Json,
12    JsonKey,
13    ParameterBinding,
14    SqlCommentOnColumn,
15    SqlCreateSchema,
16    SqlCreateTable,
17    SqlCreateTablePrimaryKey,
18    SqlCreateTableUnique,
19    SqlDeleteFrom,
20    SqlDeleteFromWhere,
21    SqlDropSchema,
22    SqlDropTable,
23    SqlInsertInto,
24    SqlInsertIntoOnConflict,
25    SqlInsertIntoValues,
26    SqlJoin,
27    SqlSelect,
28    SqlSelectFrom,
29    SqlSelectGroupBy,
30    SqlSelectHaving,
31    SqlSelectOrderBy,
32    Timestamp,
33    SqlSelectWhere,
34}
35
36/// Holds state during SQL generation, including current fragment, table context, and formatting options.
37#[derive(Clone, PartialEq, Eq, Debug)]
38pub struct Context {
39    pub counter: u32,
40    pub fragment: Fragment,
41    pub table_ref: TableRef,
42    pub qualify_columns: bool,
43    pub quote_identifiers: bool,
44}
45
46impl Context {
47    /// Creates a new generation context for a specific fragment.
48    pub const fn new(fragment: Fragment, qualify_columns: bool) -> Self {
49        Self {
50            counter: 0,
51            fragment,
52            table_ref: TableRef::new(Cow::Borrowed("")),
53            qualify_columns,
54            quote_identifiers: true,
55        }
56    }
57    /// Creates an empty context with no special configuration.
58    pub const fn empty() -> Self {
59        Self {
60            counter: 0,
61            fragment: Fragment::None,
62            table_ref: TableRef::new(Cow::Borrowed("")),
63            qualify_columns: false,
64            quote_identifiers: false,
65        }
66    }
67    /// Creates a context for a specific SQL fragment.
68    pub const fn fragment(fragment: Fragment) -> Self {
69        Self {
70            counter: 0,
71            fragment,
72            table_ref: TableRef::new(Cow::Borrowed("")),
73            qualify_columns: false,
74            quote_identifiers: true,
75        }
76    }
77    /// Creates a context that enforces identifying columns with their table name.
78    pub const fn qualify(qualify_columns: bool) -> Self {
79        Self {
80            counter: 0,
81            fragment: Fragment::None,
82            table_ref: TableRef::new(Cow::Borrowed("")),
83            qualify_columns,
84            quote_identifiers: true,
85        }
86    }
87    /// Creates a context qualified with a specific table name.
88    pub const fn qualify_with(table: Cow<'static, str>) -> Self {
89        Self {
90            counter: 0,
91            fragment: Fragment::None,
92            table_ref: TableRef::new(table),
93            qualify_columns: true,
94            quote_identifiers: true,
95        }
96    }
97    pub const fn update_from(&mut self, context: &Context) {
98        self.counter = context.counter;
99    }
100    pub fn switch_fragment<'s>(&'s mut self, fragment: Fragment) -> ContextUpdater<'s> {
101        ContextUpdater {
102            current: Context {
103                fragment,
104                table_ref: self.table_ref.clone(),
105                ..*self
106            },
107            previous: self,
108        }
109    }
110    pub fn switch_table<'s>(&'s mut self, table_ref: TableRef) -> ContextUpdater<'s> {
111        let is_empty = table_ref.is_empty();
112        ContextUpdater {
113            current: Context {
114                table_ref,
115                qualify_columns: !is_empty,
116                ..*self
117            },
118            previous: self,
119        }
120    }
121}
122
123impl Default for Context {
124    fn default() -> Self {
125        Context::new(Fragment::None, true)
126    }
127}
128
129pub struct ContextUpdater<'a> {
130    pub current: Context,
131    pub previous: &'a mut Context,
132}
133
134impl<'a> Drop for ContextUpdater<'a> {
135    fn drop(&mut self) {
136        self.previous.counter = self.current.counter;
137    }
138}