sea_query/extension/postgres/func/json_table/
builder.rs1use core::fmt;
2use std::borrow::Cow;
3use std::fmt::Write;
4
5use crate::extension::postgres::json_fn::{
6 write_as_json_path_name, write_json_path_expr, write_passing,
7};
8use crate::extension::postgres::json_table::ExistsColumnBuilder;
9use crate::*;
10
11use super::column::ColumnBuilder;
12use super::nested::NestedPathBuilder;
13use super::types::*;
14
15#[derive(Debug, Clone)]
17pub struct Builder {
18 pub(super) context_item: Expr,
19 pub(super) path_expression: Cow<'static, str>,
20 pub(super) as_json_path_name: Option<Cow<'static, str>>,
21 pub(super) passing: Vec<(Value, Cow<'static, str>)>,
22 pub(super) columns: Vec<JsonTableColumn>,
23 pub(super) on_error: Option<OnErrorClause>,
24}
25
26impl From<Builder> for FunctionCall {
27 fn from(builder: Builder) -> Self {
28 builder.build()
29 }
30}
31
32impl From<Builder> for Expr {
33 fn from(value: Builder) -> Self {
34 Expr::FunctionCall(FunctionCall::from(value))
35 }
36}
37
38impl Builder {
39 pub fn json_path_name<T>(mut self, name: T) -> Self
41 where
42 T: Into<Cow<'static, str>>,
43 {
44 self.as_json_path_name = Some(name.into());
45 self
46 }
47
48 pub fn passing<V, A>(mut self, value: V, alias: A) -> Self
50 where
51 V: Into<Value>,
52 A: Into<Cow<'static, str>>,
53 {
54 self.passing.push((value.into(), alias.into()));
55 self
56 }
57
58 pub fn passing_many<V, A, I>(mut self, passing: I) -> Self
60 where
61 V: Into<Value>,
62 A: Into<Cow<'static, str>>,
63 I: IntoIterator<Item = (V, A)>,
64 {
65 for (value, alias) in passing {
66 self.passing.push((value.into(), alias.into()));
67 }
68 self
69 }
70
71 pub fn ordinality_column<N>(mut self, name: N) -> Self
73 where
74 N: Into<Cow<'static, str>>,
75 {
76 self.columns
77 .push(JsonTableColumn::Ordinality { name: name.into() });
78 self
79 }
80
81 pub fn column<N, T>(self, name: N, column_type: T) -> ColumnBuilder<Self>
83 where
84 N: Into<Cow<'static, str>>,
85 T: Into<TypeRef>,
86 {
87 ColumnBuilder {
88 builder: self,
89 name: name.into(),
90 column_type: column_type.into(),
91 format_json: false,
92 encoding_utf8: false,
93 path: None,
94 wrapper: None,
95 quotes: None,
96 on_empty: None,
97 on_error: None,
98 }
99 }
100
101 pub fn exists_column<N, T>(self, name: N, column_type: T) -> ExistsColumnBuilder<Self>
103 where
104 N: Into<Cow<'static, str>>,
105 T: Into<TypeRef>,
106 {
107 ExistsColumnBuilder {
108 builder: self,
109 name: name.into(),
110 column_type: column_type.into(),
111 path: None,
112 on_error: None,
113 }
114 }
115
116 pub fn nested<P>(self, path: P) -> NestedPathBuilder
118 where
119 P: Into<Cow<'static, str>>,
120 {
121 NestedPathBuilder {
122 builder: self,
123 path: path.into(),
124 explicit: false,
125 json_path_name: None,
126 columns: Vec::new(),
127 }
128 }
129
130 pub fn error_on_error(mut self) -> Self {
132 self.on_error = Some(OnErrorClause::Error);
133 self
134 }
135
136 pub fn empty_on_error(mut self) -> Self {
138 self.on_error = Some(OnErrorClause::Empty);
139 self
140 }
141
142 pub fn empty_array_on_error(mut self) -> Self {
144 self.on_error = Some(OnErrorClause::EmptyArray);
145 self
146 }
147
148 pub fn build(self) -> FunctionCall {
149 self.build_internal().unwrap()
150 }
151
152 fn build_internal(self) -> Result<FunctionCall, core::fmt::Error> {
153 let mut buf = String::with_capacity(200);
154
155 PostgresQueryBuilder.prepare_expr(&self.context_item, &mut buf);
156 buf.write_str(", ")?;
157 write_json_path_expr(&mut buf, &self.path_expression)?;
158
159 self.as_json_path_name
160 .map(|x| write_as_json_path_name(&mut buf, &x));
161
162 write_passing(&mut buf, self.passing)?;
163
164 Self::write_columns(&self.columns, &mut buf)?;
165
166 if let Some(on_error) = &self.on_error {
167 buf.write_str(" ")?;
168 on_error.write_to(&mut buf)?;
169 }
170
171 Ok(FunctionCall::new(Func::Custom("JSON_TABLE".into())).arg(Expr::Custom(buf.into())))
172 }
173
174 fn write_columns(columns: &[JsonTableColumn], buf: &mut String) -> fmt::Result {
175 buf.write_str(" COLUMNS (")?;
176 let mut citer = columns.iter();
177 join_io!(
178 citer,
179 col,
180 join {
181 buf.write_str(", ")?;
182 },
183 do {
184 Self::write_column_static(col, buf)?;
185 }
186 );
187 buf.write_str(")")?;
188
189 Ok(())
190 }
191
192 fn write_column_static(
193 column: &JsonTableColumn,
194 buf: &mut String,
195 ) -> Result<(), core::fmt::Error> {
196 match column {
197 JsonTableColumn::Ordinality { name } => {
198 buf.write_str(name)?;
199 buf.write_str(" FOR ORDINALITY")?;
200 }
201 JsonTableColumn::Regular {
202 name,
203 column_type,
204 format_json,
205 encoding_utf8,
206 path,
207 wrapper,
208 quotes,
209 on_empty,
210 on_error,
211 } => {
212 buf.write_str(name)?;
213 buf.write_str(" ")?;
214 PostgresQueryBuilder.prepare_type_ref(column_type, buf);
215
216 if *format_json {
217 buf.write_str(" FORMAT JSON")?;
218 if *encoding_utf8 {
219 buf.write_str(" ENCODING UTF8")?;
220 }
221 }
222
223 if let Some(path) = path {
224 buf.write_str(" PATH '")?;
225 buf.write_str(path)?;
226 buf.write_str("'")?;
227 }
228
229 if let Some(wrapper) = wrapper {
230 wrapper.write_to(buf)?;
231 }
232
233 if let Some(quotes) = quotes {
234 quotes.write_to(buf)?;
235 }
236
237 if let Some(on_empty) = on_empty {
238 buf.write_str(" ")?;
239 on_empty.write_to(buf)?;
240 buf.write_str(" ON EMPTY")?;
241 }
242
243 if let Some(on_error) = on_error {
244 buf.write_str(" ")?;
245 on_error.write_to(buf)?;
246 buf.write_str(" ON ERROR")?;
247 }
248 }
249 JsonTableColumn::Exists {
250 name,
251 column_type,
252 path,
253 on_error,
254 } => {
255 buf.write_str(name)?;
256 buf.write_str(" ")?;
257 PostgresQueryBuilder.prepare_type_ref(column_type, buf);
258 buf.write_str(" EXISTS")?;
259
260 if let Some(path) = path {
261 buf.write_str(" PATH '")?;
262 buf.write_str(path)?;
263 buf.write_str("'")?;
264 }
265
266 if let Some(on_error) = on_error {
267 buf.write_str(" ")?;
268 on_error.write_to(buf)?;
269 }
270 }
271 JsonTableColumn::Nested {
272 path,
273 as_json_path_name: json_path_name,
274 columns,
275 explicit_path,
276 } => {
277 buf.write_str("NESTED")?;
278 if *explicit_path {
279 buf.write_str(" PATH")?;
280 }
281 buf.write_str(" ")?;
282 write_json_path_expr(buf, path)?;
283
284 if let Some(name) = json_path_name {
285 write_as_json_path_name(buf, name)?;
286 }
287
288 Self::write_columns(columns, buf)?;
289 }
290 }
291 Ok(())
292 }
293}