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::*;
9
10use super::column::Column;
11use super::exists_column::ExistsColumn;
12use super::nested::NestedPath;
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 path_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
41 self.as_json_path_name = Some(name.into());
42 self
43 }
44
45 pub fn passing(mut self, value: impl Into<Value>, alias: impl Into<Cow<'static, str>>) -> Self {
47 self.passing.push((value.into(), alias.into()));
48 self
49 }
50
51 pub fn passing_many(
53 mut self,
54 passing: impl IntoIterator<Item = (impl Into<Value>, impl Into<Cow<'static, str>>)>,
55 ) -> Self {
56 for (value, alias) in passing {
57 self.passing.push((value.into(), alias.into()));
58 }
59 self
60 }
61
62 pub fn for_ordinality(mut self, name: impl Into<Cow<'static, str>>) -> Self {
64 self.columns
65 .push(JsonTableColumn::Ordinality { name: name.into() });
66 self
67 }
68
69 pub fn column(mut self, column: Column) -> Self {
70 self.columns.push(column.into_column());
71 self
72 }
73
74 pub fn exists(mut self, column: ExistsColumn) -> Self {
75 self.columns.push(column.into_column());
76 self
77 }
78
79 pub fn nested(mut self, nested: NestedPath) -> Self {
80 self.columns.push(nested.into_column());
81 self
82 }
83
84 pub fn error_on_error(mut self) -> Self {
86 self.on_error = Some(OnErrorClause::Error);
87 self
88 }
89
90 pub fn empty_on_error(mut self) -> Self {
92 self.on_error = Some(OnErrorClause::Empty);
93 self
94 }
95
96 pub fn empty_array_on_error(mut self) -> Self {
98 self.on_error = Some(OnErrorClause::EmptyArray);
99 self
100 }
101
102 pub fn build(self) -> FunctionCall {
103 self.build_internal().unwrap()
104 }
105
106 fn build_internal(self) -> Result<FunctionCall, core::fmt::Error> {
107 let mut buf = String::with_capacity(200);
108
109 PostgresQueryBuilder.prepare_expr(&self.context_item, &mut buf);
110 buf.write_str(", ")?;
111 write_json_path_expr(&mut buf, &self.path_expression)?;
112
113 if let Some(name) = &self.as_json_path_name {
114 write_as_json_path_name(&mut buf, name)?;
115 }
116
117 write_passing(&mut buf, self.passing)?;
118
119 Self::write_columns(&self.columns, &mut buf)?;
120
121 if let Some(on_error) = &self.on_error {
122 buf.write_str(" ")?;
123 on_error.write_to(&mut buf)?;
124 }
125
126 Ok(FunctionCall::new(Func::Custom("JSON_TABLE".into())).arg(Expr::Custom(buf.into())))
127 }
128
129 fn write_columns(columns: &[JsonTableColumn], buf: &mut String) -> fmt::Result {
130 buf.write_str(" COLUMNS (")?;
131 let mut citer = columns.iter();
132 join_io!(
133 citer,
134 col,
135 join {
136 buf.write_str(", ")?;
137 },
138 do {
139 Self::write_column_static(col, buf)?;
140 }
141 );
142 buf.write_str(")")?;
143
144 Ok(())
145 }
146
147 fn write_column_static(
148 column: &JsonTableColumn,
149 buf: &mut String,
150 ) -> Result<(), core::fmt::Error> {
151 match column {
152 JsonTableColumn::Ordinality { name } => {
153 buf.write_str(name)?;
154 buf.write_str(" FOR ORDINALITY")?;
155 }
156 JsonTableColumn::Regular {
157 name,
158 column_type,
159 format_json,
160 encoding_utf8,
161 path,
162 wrapper,
163 quotes,
164 on_empty,
165 on_error,
166 } => {
167 buf.write_str(name)?;
168 buf.write_str(" ")?;
169 PostgresQueryBuilder.prepare_type_ref(column_type, buf);
170
171 if *format_json {
172 buf.write_str(" FORMAT JSON")?;
173 if *encoding_utf8 {
174 buf.write_str(" ENCODING UTF8")?;
175 }
176 }
177
178 if let Some(path) = path {
179 buf.write_str(" PATH '")?;
180 buf.write_str(path)?;
181 buf.write_str("'")?;
182 }
183
184 if let Some(wrapper) = wrapper {
185 wrapper.write_to(buf)?;
186 }
187
188 if let Some(quotes) = quotes {
189 quotes.write_to(buf)?;
190 }
191
192 if let Some(on_empty) = on_empty {
193 buf.write_str(" ")?;
194 on_empty.write_to(buf)?;
195 buf.write_str(" ON EMPTY")?;
196 }
197
198 if let Some(on_error) = on_error {
199 buf.write_str(" ")?;
200 on_error.write_to(buf)?;
201 buf.write_str(" ON ERROR")?;
202 }
203 }
204 JsonTableColumn::Exists {
205 name,
206 column_type,
207 path,
208 on_error,
209 } => {
210 buf.write_str(name)?;
211 buf.write_str(" ")?;
212 PostgresQueryBuilder.prepare_type_ref(column_type, buf);
213 buf.write_str(" EXISTS")?;
214
215 if let Some(path) = path {
216 buf.write_str(" PATH '")?;
217 buf.write_str(path)?;
218 buf.write_str("'")?;
219 }
220
221 if let Some(on_error) = on_error {
222 buf.write_str(" ")?;
223 on_error.write_to(buf)?;
224 }
225 }
226 JsonTableColumn::Nested {
227 path,
228 as_json_path_name: json_path_name,
229 columns,
230 } => {
232 buf.write_str("NESTED PATH")?;
233 buf.write_str(" ")?;
234 write_json_path_expr(buf, path)?;
235
236 if let Some(name) = json_path_name {
237 write_as_json_path_name(buf, name)?;
238 }
239
240 Self::write_columns(columns, buf)?;
241 }
242 }
243 Ok(())
244 }
245}