1#[macro_use]
2mod fmt;
3use fmt::ToSql;
4
5mod column;
6use column::ColumnAlias;
7
8mod cte;
9
10mod delim;
11use delim::{Comma, Delimited, Period};
12
13mod flavor;
14use flavor::Flavor;
15
16mod ident;
17use ident::Ident;
18
19mod params;
20pub use params::{Params, Placeholder, TypedValue};
21
22mod column_def;
24mod expr;
25mod name;
26mod statement;
27mod ty;
28mod value;
29
30use crate::stmt::Statement;
31
32use toasty_core::{
33 driver::operation::{IsolationLevel, Transaction},
34 schema::db::{self, Index, Table},
35};
36
37#[derive(Debug, Clone)]
39pub struct InsertContext {
40 pub table_id: db::TableId,
41 pub columns: Vec<db::ColumnId>,
42}
43
44#[derive(Debug)]
46pub struct Serializer<'a> {
47 schema: &'a db::Schema,
49
50 flavor: Flavor,
53}
54
55struct Formatter<'a, T> {
56 serializer: &'a Serializer<'a>,
58
59 dst: &'a mut String,
61
62 params: &'a mut T,
64
65 depth: usize,
68
69 alias: bool,
71
72 insert_context: Option<InsertContext>,
74}
75
76pub type ExprContext<'a> = toasty_core::stmt::ExprContext<'a, db::Schema>;
77
78impl<'a> Serializer<'a> {
79 pub fn serialize(&self, stmt: &Statement, params: &mut impl Params) -> String {
80 let mut ret = String::new();
81
82 let mut fmt = Formatter {
83 serializer: self,
84 dst: &mut ret,
85 params,
86 depth: 0,
87 alias: false,
88 insert_context: None,
89 };
90
91 let cx = ExprContext::new(self.schema);
92
93 stmt.to_sql(&cx, &mut fmt);
94
95 ret.push(';');
96 ret
97 }
98
99 pub fn serialize_transaction(&self, op: &Transaction) -> String {
104 let mut ret = String::new();
105
106 let mut f = Formatter {
107 serializer: self,
108 dst: &mut ret,
109 params: &mut Vec::<TypedValue>::new(),
110 depth: 0,
111 alias: false,
112 insert_context: None,
113 };
114
115 let cx = ExprContext::new(self.schema);
116
117 match op {
118 Transaction::Start {
119 isolation,
120 read_only,
121 } => fmt!(
122 &cx,
123 &mut f,
124 self.serialize_transaction_start(*isolation, *read_only)
125 ),
126 Transaction::Commit => fmt!(&cx, &mut f, "COMMIT"),
127 Transaction::Rollback => fmt!(&cx, &mut f, "ROLLBACK"),
128 Transaction::Savepoint(name) => {
129 fmt!(&cx, &mut f, "SAVEPOINT " Ident(name))
130 }
131 Transaction::ReleaseSavepoint(name) => {
132 fmt!(&cx, &mut f, "RELEASE SAVEPOINT " Ident(name))
133 }
134 Transaction::RollbackToSavepoint(name) => {
135 fmt!(&cx, &mut f, "ROLLBACK TO SAVEPOINT " Ident(name))
136 }
137 };
138
139 ret.push(';');
140 ret
141 }
142
143 fn serialize_transaction_start(
144 &self,
145 isolation: Option<IsolationLevel>,
146 read_only: bool,
147 ) -> String {
148 fn isolation_level_str(level: IsolationLevel) -> &'static str {
149 match level {
150 IsolationLevel::ReadUncommitted => "READ UNCOMMITTED",
151 IsolationLevel::ReadCommitted => "READ COMMITTED",
152 IsolationLevel::RepeatableRead => "REPEATABLE READ",
153 IsolationLevel::Serializable => "SERIALIZABLE",
154 }
155 }
156
157 match self.flavor {
158 Flavor::Mysql => {
159 let mut sql = String::new();
160 if let Some(level) = isolation {
161 sql.push_str("SET TRANSACTION ISOLATION LEVEL ");
162 sql.push_str(isolation_level_str(level));
163 sql.push_str("; ");
164 }
165 sql.push_str("START TRANSACTION");
166 if read_only {
167 sql.push_str(" READ ONLY");
168 }
169 sql
170 }
171 Flavor::Postgresql => {
172 let mut sql = String::from("BEGIN");
173 if let Some(level) = isolation {
174 sql.push_str(" ISOLATION LEVEL ");
175 sql.push_str(isolation_level_str(level));
176 }
177 if read_only {
178 sql.push_str(" READ ONLY");
179 }
180 sql
181 }
182 Flavor::Sqlite => {
183 "BEGIN".to_string()
185 }
186 }
187 }
188
189 fn table(&self, id: impl Into<db::TableId>) -> &'a Table {
190 self.schema.table(id.into())
191 }
192
193 fn index(&self, id: impl Into<db::IndexId>) -> &'a Index {
194 self.schema.index(id.into())
195 }
196
197 fn table_name(&self, id: impl Into<db::TableId>) -> Ident<&str> {
198 let table = self.schema.table(id.into());
199 Ident(&table.name)
200 }
201
202 fn column_name(&self, id: impl Into<db::ColumnId>) -> Ident<&str> {
203 let column = self.schema.column(id.into());
204 Ident(&column.name)
205 }
206}