sea_query/extension/postgres/func/
json_query.rs

1use std::borrow::Cow;
2
3use crate::{
4    extension::postgres::{
5        json_fn::{QuotesClause, WrapperClause, write_json_path_expr, write_passing},
6        json_table::OnClause,
7    },
8    *,
9};
10
11/// Builder for JSON_QUERY function
12#[derive(Debug, Clone)]
13pub struct Builder {
14    context_item: Expr,
15    path_expression: Cow<'static, str>,
16    passing: Vec<(Value, Cow<'static, str>)>,
17    returning: Option<crate::TypeRef>,
18    wrapper: Option<WrapperClause>,
19    quotes: Option<QuotesClause>,
20    on_empty: Option<OnClause>,
21    on_error: Option<OnClause>,
22}
23
24impl From<Builder> for FunctionCall {
25    fn from(builder: Builder) -> Self {
26        builder.build()
27    }
28}
29
30impl From<Builder> for Expr {
31    fn from(builder: Builder) -> Self {
32        Expr::FunctionCall(builder.build())
33    }
34}
35
36impl Builder {
37    pub fn passing<V, A>(mut self, value: V, alias: A) -> Self
38    where
39        V: Into<Value>,
40        A: Into<Cow<'static, str>>,
41    {
42        self.passing.push((value.into(), alias.into()));
43        self
44    }
45
46    /// Add multiple PASSING parameters at once
47    pub fn passing_many<V, A, I>(mut self, passing: I) -> Self
48    where
49        V: Into<Value>,
50        A: Into<Cow<'static, str>>,
51        I: IntoIterator<Item = (V, A)>,
52    {
53        for (value, alias) in passing {
54            self.passing.push((value.into(), alias.into()));
55        }
56        self
57    }
58
59    /// Set RETURNING clause
60    pub fn returning<T>(mut self, returning: T) -> Self
61    where
62        T: Into<TypeRef>,
63    {
64        self.returning = Some(returning.into());
65        self
66    }
67
68    /// Set WRAPPER clause
69    pub fn wrapper<T>(mut self, wrapper: T) -> Self
70    where
71        T: Into<WrapperClause>,
72    {
73        self.wrapper = Some(wrapper.into());
74        self
75    }
76
77    /// Set QUOTES clause
78    pub fn quotes<T>(mut self, quotes: T) -> Self
79    where
80        T: Into<QuotesClause>,
81    {
82        self.quotes = Some(quotes.into());
83        self
84    }
85
86    pub fn error_on_empty(mut self) -> Self {
87        self.on_empty = Some(OnClause::Error);
88        self
89    }
90
91    pub fn null_on_empty(mut self) -> Self {
92        self.on_empty = Some(OnClause::Null);
93        self
94    }
95
96    pub fn empty_array_on_empty(mut self) -> Self {
97        self.on_empty = Some(OnClause::EmptyArray);
98        self
99    }
100
101    pub fn empty_object_on_empty(mut self) -> Self {
102        self.on_empty = Some(OnClause::EmptyObject);
103        self
104    }
105
106    pub fn default_on_empty<T>(mut self, expr: T) -> Self
107    where
108        T: Into<Expr>,
109    {
110        self.on_empty = Some(OnClause::Default(expr.into()));
111        self
112    }
113
114    pub fn error_on_error(mut self) -> Self {
115        self.on_error = Some(OnClause::Error);
116        self
117    }
118
119    pub fn null_on_error(mut self) -> Self {
120        self.on_error = Some(OnClause::Null);
121        self
122    }
123
124    pub fn empty_array_on_error(mut self) -> Self {
125        self.on_error = Some(OnClause::EmptyArray);
126        self
127    }
128
129    pub fn empty_object_on_error(mut self) -> Self {
130        self.on_error = Some(OnClause::EmptyObject);
131        self
132    }
133
134    pub fn default_on_error<T>(mut self, expr: T) -> Self
135    where
136        T: Into<Expr>,
137    {
138        self.on_error = Some(OnClause::Default(expr.into()));
139        self
140    }
141
142    pub fn build(self) -> FunctionCall {
143        self.build_internal().unwrap()
144    }
145
146    fn build_internal(self) -> Result<FunctionCall, core::fmt::Error> {
147        let mut buf = String::with_capacity(50);
148
149        PostgresQueryBuilder.prepare_expr(&self.context_item, &mut buf);
150        buf.write_str(" ")?;
151        write_json_path_expr(&mut buf, &self.path_expression)?;
152
153        write_passing(&mut buf, self.passing)?;
154
155        // RETURNING clause
156        if let Some(returning) = self.returning {
157            buf.write_str(" RETURNING ")?;
158            PostgresQueryBuilder.prepare_type_ref(&returning, &mut buf);
159        }
160
161        if let Some(wrapper) = self.wrapper {
162            wrapper.write_to(&mut buf)?;
163        }
164
165        if let Some(quotes) = self.quotes {
166            quotes.write_to(&mut buf)?;
167        }
168
169        if let Some(on_empty) = self.on_empty {
170            buf.write_str(" ")?;
171            on_empty.write_to(&mut buf)?;
172            buf.write_str(" ON EMPTY")?;
173        }
174
175        if let Some(on_error) = self.on_error {
176            buf.write_str(" ")?;
177            on_error.write_to(&mut buf)?;
178            buf.write_str(" ON ERROR")?;
179        }
180
181        Ok(FunctionCall::new(Func::Custom("JSON_QUERY".into())).arg(Expr::Custom(buf.into())))
182    }
183}
184
185impl PgFunc {
186    /// Create a `JSON_QUERY` function builder. Postgres only.
187    ///
188    /// # Examples
189    ///
190    /// Basic usage:
191    /// ```
192    /// use sea_query::extension::postgres::*;
193    /// use sea_query::{tests_cfg::*, *};
194    ///
195    /// let query = Query::select()
196    ///     .expr(
197    ///         PgFunc::json_query(Expr::cust(r#"jsonb '[1,[2,3],null]'"#), "lax $[*][$off]")
198    ///             .passing(1, "off")
199    ///             .wrapper(json_fn::WrapperKind::WithConditional),
200    ///     )
201    ///     .to_owned();
202    ///
203    /// assert_eq!(
204    ///     query.to_string(PostgresQueryBuilder),
205    ///     r#"SELECT JSON_QUERY(jsonb '[1,[2,3],null]' 'lax $[*][$off]' PASSING 1 AS off WITH CONDITIONAL WRAPPER)"#
206    /// );
207    /// ```
208    ///
209    /// With OMIT QUOTES:
210    /// ```
211    /// use sea_query::extension::postgres::*;
212    /// use sea_query::{tests_cfg::*, *};
213    ///
214    /// let query = Query::select()
215    ///     .expr(
216    ///         PgFunc::json_query(Expr::cust(r#"jsonb '{"a": "[1, 2]"}'"#), "lax $.a")
217    ///             .quotes(json_fn::QuotesKind::Omit),
218    ///     )
219    ///     .to_owned();
220    ///
221    /// assert_eq!(
222    ///     query.to_string(PostgresQueryBuilder),
223    ///     r#"SELECT JSON_QUERY(jsonb '{"a": "[1, 2]"}' 'lax $.a' OMIT QUOTES)"#
224    /// );
225    /// ```
226    pub fn json_query<T, P>(context_item: T, path_expression: P) -> Builder
227    where
228        T: Into<Expr>,
229        P: Into<Cow<'static, str>>,
230    {
231        Builder {
232            context_item: context_item.into(),
233            path_expression: path_expression.into(),
234            passing: Vec::new(),
235            returning: None,
236            wrapper: None,
237            quotes: None,
238            on_empty: None,
239            on_error: None,
240        }
241    }
242}