1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
use crate::Result;
use crate::ident::{write_quoted_ident, write_quoted_qualified};
use crate::{
Assignment, AssignmentValue, BoolExpr, BuiltQuery, ConflictAction, ConflictClause,
ConflictTarget, Cte, Delete, FrameBound, GroupByItem, Insert, InsertBody, Merge, MergeAction,
MergeWhen, Param, Params, RawStmt, RowLimit, Select, SelectItem, SetQuery, Source, Stmt,
ValueExpr, WindowFrame, WindowSpec,
};
mod bool;
mod raw;
mod source;
mod stmt;
mod value;
mod write;
struct Renderer {
sql: String,
params: Vec<Param>,
cacheable: bool,
}
impl Renderer {
fn new() -> Self {
Self {
sql: String::with_capacity(256),
params: Vec::new(),
cacheable: true,
}
}
fn finish(self) -> BuiltQuery {
BuiltQuery {
sql: self.sql,
params: Params::from_vec(self.params),
cacheable: self.cacheable,
}
}
fn build_with(render: impl FnOnce(&mut Self)) -> BuiltQuery {
let mut renderer = Self::new();
render(&mut renderer);
renderer.finish()
}
}
impl Stmt {
/// Validates and renders this statement into parameterized SQL.
///
/// Use this when you need a reusable [`BuiltQuery`] or want to inspect SQL
/// before execution. The convenience `fetch_*` and `execute` methods build
/// on each call.
pub fn build(&self) -> Result<BuiltQuery> {
self.validate()?;
Ok(Renderer::build_with(|renderer| renderer.render_stmt(self)))
}
}
impl Select {
/// Validates and renders this select into parameterized SQL.
///
/// Default projection is expanded during render when no explicit projection
/// items were added.
pub fn build(&self) -> Result<BuiltQuery> {
self.validate()?;
Ok(Renderer::build_with(|renderer| {
renderer.render_select(self)
}))
}
}
impl SetQuery {
/// Validates and renders this set query into parameterized SQL.
///
/// Validation checks both sides before rendering the set operator, ordering,
/// and row-limit clauses.
pub fn build(&self) -> Result<BuiltQuery> {
self.validate()?;
Ok(Renderer::build_with(|renderer| renderer.render_set(self)))
}
}
impl Insert {
/// Validates and renders this insert into parameterized SQL.
///
/// Validation rejects empty insert shapes and write targets that are not
/// table/view sources before SQL is produced.
pub fn build(&self) -> Result<BuiltQuery> {
self.validate()?;
Ok(Renderer::build_with(|renderer| {
renderer.render_insert(self)
}))
}
}
impl crate::Update {
/// Validates and renders this update into parameterized SQL.
///
/// Validation rejects empty `SET` assignments and non-table/view targets
/// before SQL is produced.
pub fn build(&self) -> Result<BuiltQuery> {
self.validate()?;
Ok(Renderer::build_with(|renderer| {
renderer.render_update(self)
}))
}
}
impl Delete {
/// Validates and renders this delete into parameterized SQL.
///
/// Deletes require a `WHERE` predicate; validation returns
/// [`Error::DeleteWithoutFilter`](crate::Error::DeleteWithoutFilter) before
/// any SQL is rendered.
pub fn build(&self) -> Result<BuiltQuery> {
self.validate()?;
Ok(Renderer::build_with(|renderer| {
renderer.render_delete(self)
}))
}
}
impl Merge {
/// Validates and renders this merge into parameterized SQL.
///
/// Branch builders restrict actions for each `WHEN` category. Validation
/// checks branch ordering, assignments, and expressions before rendering.
pub fn build(&self) -> Result<BuiltQuery> {
self.validate()?;
Ok(Renderer::build_with(|renderer| renderer.render_merge(self)))
}
}
impl RawStmt {
/// Validates and renders this raw statement into parameterized SQL.
///
/// `?` placeholders are converted into Postgres `$N` binds. `??` renders a
/// literal question mark, and placeholder-like text inside SQL strings,
/// quoted identifiers, dollar quotes, and comments is ignored.
pub fn build(&self) -> Result<BuiltQuery> {
self.validate()?;
Ok(Renderer::build_with(|renderer| {
renderer.render_raw_stmt(self)
}))
}
}
#[cfg(test)]
mod tests;