sea_query/extension/postgres/func/
json_value.rs

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