Skip to content

Commit 66cb13d

Browse files
authored
Merge pull request diesel-rs#3036 from czotomo/pg-jsonb-exists-operator
implement jsonb key existence check expression
2 parents f25881d + bc513ee commit 66cb13d

6 files changed

Lines changed: 75 additions & 10 deletions

File tree

diesel/src/pg/expression/expression_methods.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,6 +1241,66 @@ pub trait PgJsonbExpressionMethods: Expression + Sized {
12411241
{
12421242
Grouped(ConcatJsonb::new(self, other.as_expression()))
12431243
}
1244+
/// Creates a PostgreSQL `?` expression.
1245+
///
1246+
/// This operator checks if the right hand side string exists as a top-level key within the JSON
1247+
///
1248+
/// # Example
1249+
///
1250+
/// ```rust
1251+
/// # include!("../../doctest_setup.rs");
1252+
/// #
1253+
/// # table! {
1254+
/// # contacts {
1255+
/// # id -> Integer,
1256+
/// # name -> VarChar,
1257+
/// # address -> Jsonb,
1258+
/// # }
1259+
/// # }
1260+
/// #
1261+
/// # fn main() {
1262+
/// # run_test().unwrap();
1263+
/// # }
1264+
///
1265+
/// # #[cfg(feature = "serde_json")]
1266+
/// # fn run_test() -> QueryResult<()> {
1267+
/// # use self::contacts::dsl::*;
1268+
/// # let conn = &mut establish_connection();
1269+
/// # conn.execute("DROP TABLE IF EXISTS contacts").unwrap();
1270+
/// # conn.execute("CREATE TABLE contacts (
1271+
/// # id SERIAL PRIMARY KEY,
1272+
/// # name VARCHAR NOT NULL,
1273+
/// # address JSONB NOT NULL
1274+
/// # )").unwrap();
1275+
/// #
1276+
/// let santas_address: serde_json::Value = serde_json::json!({
1277+
/// "street": "Article Circle Expressway 1",
1278+
/// "city": "North Pole",
1279+
/// "postcode": "99705",
1280+
/// "state": "Alaska"
1281+
/// });
1282+
/// diesel::insert_into(contacts)
1283+
/// .values((name.eq("Claus"), address.eq(&santas_address)))
1284+
/// .execute(conn)?;
1285+
///
1286+
/// let key_exists = contacts.select(address.has_key("street")).get_result::<bool>(conn)?;
1287+
/// assert!(key_exists);
1288+
///
1289+
/// let santas_with_address_postcode = contacts.select(id).filter(address.has_key("postcode")).get_result::<i32>(conn)?;
1290+
/// assert_eq!(1, santas_with_address_postcode);
1291+
/// # Ok(())
1292+
/// # }
1293+
/// # #[cfg(not(feature = "serde_json"))]
1294+
/// # fn run_test() -> QueryResult<()> {
1295+
/// # Ok(())
1296+
/// # }
1297+
/// ```
1298+
fn has_key<T>(self, other: T) -> dsl::HasKeyJsonb<Self, T>
1299+
where
1300+
T: AsExpression<VarChar>,
1301+
{
1302+
Grouped(HasKeyJsonb::new(self, other.as_expression()))
1303+
}
12441304
}
12451305

12461306
impl<T> PgJsonbExpressionMethods for T

diesel/src/pg/expression/helper_types.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,7 @@ pub type DifferenceNet<Lhs, Rhs> =
8181

8282
/// The return type of `lsh.concat(rhs)`
8383
pub type ConcatJsonb<Lhs, Rhs> = Grouped<super::operators::ConcatJsonb<Lhs, AsExprOf<Rhs, Jsonb>>>;
84+
85+
/// The return type of `lsh.has_key(rhs)`
86+
pub type HasKeyJsonb<Lhs, Rhs> =
87+
Grouped<super::operators::HasKeyJsonb<Lhs, AsExprOf<Rhs, VarChar>>>;

diesel/src/pg/expression/operators.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ infix_operator!(AndNet, " & ", Inet, backend: Pg);
2121
infix_operator!(OrNet, " | ", Inet, backend: Pg);
2222
infix_operator!(DifferenceNet, " - ", Bigint, backend: Pg);
2323
infix_operator!(ConcatJsonb, " || ", Jsonb, backend: Pg);
24+
infix_operator!(HasKeyJsonb, " ? ", backend: Pg);

diesel_compile_tests/tests/fail/array_expressions_must_be_same_type.stderr

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ error[E0277]: the trait bound `{integer}: SelectableExpression<NoFromClause>` is
110110
<(T0, T1) as SelectableExpression<QS>>
111111
<(T0, T1, T2) as SelectableExpression<QS>>
112112
<(T0, T1, T2, T3) as SelectableExpression<QS>>
113-
and 138 others
113+
and 139 others
114114
= note: required because of the requirements on the impl of `SelectableExpression<NoFromClause>` for `({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>)`
115115
= note: 1 redundant requirements hidden
116116
= note: required because of the requirements on the impl of `SelectableExpression<NoFromClause>` for `diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>`
@@ -134,7 +134,7 @@ error[E0277]: the trait bound `{integer}: ValidGrouping<()>` is not satisfied
134134
<(T0, T1) as ValidGrouping<__GroupByClause>>
135135
<(T0, T1, T2) as ValidGrouping<__GroupByClause>>
136136
<(T0, T1, T2, T3) as ValidGrouping<__GroupByClause>>
137-
and 126 others
137+
and 127 others
138138
= note: required because of the requirements on the impl of `ValidGrouping<()>` for `({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>)`
139139
= note: 1 redundant requirements hidden
140140
= note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>`
@@ -152,7 +152,7 @@ error[E0277]: the trait bound `{integer}: SelectableExpression<NoFromClause>` is
152152
<(T0, T1) as SelectableExpression<QS>>
153153
<(T0, T1, T2) as SelectableExpression<QS>>
154154
<(T0, T1, T2, T3) as SelectableExpression<QS>>
155-
and 138 others
155+
and 139 others
156156
= note: required because of the requirements on the impl of `SelectableExpression<NoFromClause>` for `({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>)`
157157
= note: 1 redundant requirements hidden
158158
= note: required because of the requirements on the impl of `SelectableExpression<NoFromClause>` for `diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>`
@@ -171,7 +171,7 @@ error[E0277]: the trait bound `{integer}: ValidGrouping<()>` is not satisfied
171171
<(T0, T1) as ValidGrouping<__GroupByClause>>
172172
<(T0, T1, T2) as ValidGrouping<__GroupByClause>>
173173
<(T0, T1, T2, T3) as ValidGrouping<__GroupByClause>>
174-
and 126 others
174+
and 127 others
175175
= note: required because of the requirements on the impl of `ValidGrouping<()>` for `({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>)`
176176
= note: 1 redundant requirements hidden
177177
= note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>`
@@ -189,7 +189,7 @@ error[E0277]: the trait bound `{integer}: QueryFragment<Pg>` is not satisfied
189189
<() as QueryFragment<DB>>
190190
<(T0, T1) as QueryFragment<__DB>>
191191
<(T0, T1, T2) as QueryFragment<__DB>>
192-
and 248 others
192+
and 249 others
193193
= note: required because of the requirements on the impl of `QueryFragment<Pg>` for `({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>)`
194194
= note: 3 redundant requirements hidden
195195
= note: required because of the requirements on the impl of `QueryFragment<Pg>` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
@@ -206,7 +206,7 @@ error[E0277]: the trait bound `{integer}: QueryId` is not satisfied
206206
<() as QueryId>
207207
<(T0, T1) as QueryId>
208208
<(T0, T1, T2) as QueryId>
209-
and 213 others
209+
and 214 others
210210
= note: required because of the requirements on the impl of `QueryId` for `({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>)`
211211
= note: 3 redundant requirements hidden
212212
= note: required because of the requirements on the impl of `QueryId` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
@@ -228,6 +228,6 @@ error[E0277]: the trait bound `{integer}: diesel::Expression` is not satisfied
228228
<(T0, T1) as diesel::Expression>
229229
<(T0, T1, T2) as diesel::Expression>
230230
<(T0, T1, T2, T3) as diesel::Expression>
231-
and 107 others
231+
and 108 others
232232
= note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Double>` for `{integer}`
233233
= note: required because of the requirements on the impl of `AsExpressionList<diesel::sql_types::Double>` for `({integer}, f64)`

diesel_compile_tests/tests/fail/find_requires_correct_type.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ error[E0277]: the trait bound `{integer}: diesel::Expression` is not satisfied
3232
<(T0, T1) as diesel::Expression>
3333
<(T0, T1, T2) as diesel::Expression>
3434
<(T0, T1, T2, T3) as diesel::Expression>
35-
and 111 others
35+
and 112 others
3636
= note: required because of the requirements on the impl of `diesel::Expression` for `diesel::expression::operators::Eq<string_primary_key::columns::id, {integer}>`
3737
= note: required because of the requirements on the impl of `FilterDsl<Grouped<diesel::expression::operators::Eq<string_primary_key::columns::id, {integer}>>>` for `SelectStatement<FromClause<string_primary_key::table>>`
3838

@@ -47,7 +47,7 @@ error[E0277]: the trait bound `{integer}: ValidGrouping<()>` is not satisfied
4747
<(T0, T1) as ValidGrouping<__GroupByClause>>
4848
<(T0, T1, T2) as ValidGrouping<__GroupByClause>>
4949
<(T0, T1, T2, T3) as ValidGrouping<__GroupByClause>>
50-
and 132 others
50+
and 133 others
5151
= note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::expression::operators::Eq<string_primary_key::columns::id, {integer}>`
5252
= note: required because of the requirements on the impl of `NonAggregate` for `Grouped<diesel::expression::operators::Eq<string_primary_key::columns::id, {integer}>>`
5353
= note: required because of the requirements on the impl of `FilterDsl<Grouped<diesel::expression::operators::Eq<string_primary_key::columns::id, {integer}>>>` for `SelectStatement<FromClause<string_primary_key::table>>`

diesel_compile_tests/tests/fail/insert_requires_value_of_same_type_as_column.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ error[E0277]: the trait bound `{integer}: diesel::Expression` is not satisfied
99
<(T0, T1) as diesel::Expression>
1010
<(T0, T1, T2) as diesel::Expression>
1111
<(T0, T1, T2, T3) as diesel::Expression>
12-
and 111 others
12+
and 112 others
1313
= note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Text>` for `{integer}`

0 commit comments

Comments
 (0)