fire_postgres/query/
mod.rs1use crate::table::column::{ColumnData, ColumnKind, ColumnType};
2
3use std::borrow::Cow;
4use std::fmt;
5
6#[cfg(feature = "connect")]
7use tokio_postgres::types::ToSql;
8
9pub mod update;
10pub mod whr;
11pub use update::UpdateParams;
12
13pub type SqlStr = Cow<'static, str>;
14
15#[derive(Debug, Clone)]
22enum SqlBuilderType {
23 NoSpace(SqlStr),
24 SpaceAfter(SqlStr),
25 SpaceBefore(SqlStr),
26 Space(SqlStr),
27 Param,
28}
29
30#[derive(Debug, Clone)]
31pub struct SqlBuilder {
32 data: Vec<SqlBuilderType>,
33}
34
35impl SqlBuilder {
36 pub fn new() -> Self {
37 Self { data: vec![] }
38 }
39
40 pub fn from_sql_str(sql: impl Into<SqlStr>) -> Self {
41 Self {
42 data: vec![SqlBuilderType::SpaceAfter(sql.into())],
43 }
44 }
45
46 pub fn no_space(&mut self, s: impl Into<SqlStr>) {
47 self.data.push(SqlBuilderType::NoSpace(s.into()));
48 }
49
50 pub fn space_after(&mut self, s: impl Into<SqlStr>) {
51 self.data.push(SqlBuilderType::SpaceAfter(s.into()));
52 }
53
54 pub fn space_before(&mut self, s: impl Into<SqlStr>) {
55 self.data.push(SqlBuilderType::SpaceBefore(s.into()));
56 }
57
58 pub fn space(&mut self, s: impl Into<SqlStr>) {
59 self.data.push(SqlBuilderType::Space(s.into()));
60 }
61
62 pub fn param(&mut self) {
63 self.data.push(SqlBuilderType::Param);
64 }
65
66 pub fn prepend(&mut self, mut sql: SqlBuilder) {
67 sql.data.append(&mut self.data);
68 self.data = sql.data;
69 }
70
71 pub fn append(&mut self, mut sql: SqlBuilder) {
72 self.data.append(&mut sql.data);
73 }
74
75 pub fn is_empty(&self) -> bool {
76 self.data.is_empty()
77 }
78}
79
80impl fmt::Display for SqlBuilder {
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 let mut c = 0;
83 for d in &self.data {
84 match d {
85 SqlBuilderType::NoSpace(s) => {
86 f.write_str(s)?;
87 }
88 SqlBuilderType::SpaceAfter(s) => {
89 write!(f, "{} ", s)?;
90 }
91 SqlBuilderType::SpaceBefore(s) => {
92 write!(f, " {}", s)?;
93 }
94 SqlBuilderType::Space(s) => {
95 write!(f, " {} ", s)?;
96 }
97 SqlBuilderType::Param => {
98 c += 1;
99 write!(f, "${}", c)?;
100 }
101 }
102 }
103
104 Ok(())
105 }
106}
107
108#[derive(Debug, Clone)]
109pub struct Query<'a> {
110 pub sql: SqlBuilder,
111 pub params: Vec<Param<'a>>,
112}
113
114impl<'a> Query<'a> {
115 pub fn new(sql: SqlBuilder, params: Vec<Param<'a>>) -> Self {
116 Self { sql, params }
117 }
118
119 pub fn from_sql_str(sql: impl Into<SqlStr>) -> Self {
120 Self {
121 sql: SqlBuilder::from_sql_str(sql),
122 params: vec![],
123 }
124 }
125
126 pub fn prepend(&mut self, sql: SqlBuilder, mut params: Vec<Param<'a>>) {
127 self.sql.prepend(sql);
128 params.append(&mut self.params);
129 self.params = params;
130 }
131
132 pub fn append(&mut self, mut query: Query<'a>) {
133 self.sql.append(query.sql);
134 self.params.append(&mut query.params);
135 }
136
137 pub fn append_raw(&mut self, sql: SqlBuilder, mut params: Vec<Param<'a>>) {
138 self.sql.append(sql);
139 self.params.append(&mut params);
140 }
141
142 pub fn sql(&self) -> &SqlBuilder {
143 &self.sql
144 }
145
146 pub fn params(&self) -> &[Param] {
147 self.params.as_slice()
148 }
149
150 pub fn is_empty(&self) -> bool {
151 self.sql.is_empty() && self.params.is_empty()
152 }
153
154 pub fn params_data(&self) -> Vec<&ColumnData> {
155 let mut v = Vec::with_capacity(self.params.len());
156 for param in &self.params {
157 v.push(param.data());
158 }
159 v
160 }
161
162 #[cfg(feature = "connect")]
163 pub fn to_sql_params(&self) -> Vec<&(dyn ToSql + Sync)> {
164 let mut v = Vec::with_capacity(self.params.len());
165 for param in &self.params {
166 v.push(param.data() as &(dyn ToSql + Sync));
167 }
168 v
169 }
170}
171
172#[derive(Debug, Clone, PartialEq)]
173pub struct Param<'a> {
174 pub name: &'static str,
175 pub kind: ColumnKind,
176 pub data: ColumnData<'a>,
177}
178
179impl<'a> Param<'a> {
180 pub fn new<T>(name: &'static str, data: &'a T) -> Self
181 where
182 T: ColumnType,
183 {
184 let kind = T::column_kind();
185 Self {
186 name,
187 kind,
188 data: data.to_data(),
189 }
190 }
191
192 pub fn data(&self) -> &ColumnData {
193 &self.data
194 }
195
196 #[inline(always)]
197 pub fn maybe_null(&self) -> bool {
198 matches!(self.kind, ColumnKind::Option(_))
199 }
200}
201
202