Skip to content

Commit

Permalink
Merge pull request #4385 from calebbourg/add_create_if_missing_to_jso…
Browse files Browse the repository at this point in the history
…nb_set

Add create_if_missing variant for jsonb_set
  • Loading branch information
weiznich authored Dec 12, 2024
2 parents bfb16f1 + 8248f8f commit 907efb9
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 3 deletions.
103 changes: 100 additions & 3 deletions diesel/src/pg/expression/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2402,15 +2402,14 @@ define_sql_function! {
#[cfg(feature = "postgres_backend")]
define_sql_function! {
/// Returns target with the item designated by path replaced by new_value,
/// or with new_value added if create_if_missing is true (which is the default)
/// and the item designated by path does not exist.
/// or with new_value added and the item designated by path does not exist.
///
/// It can't set path in scalar
///
/// All earlier steps in the path must exist, or the target is returned unchanged.
/// As with the path oriented operators, negative integers that appear in the path count from the end of JSON arrays.
/// If the last path step is an array index that is out of range,
/// and create_if_missing is true, the new value is added at the beginning of the array if the index is negative,
/// the new value is added at the beginning of the array if the index is negative,
/// or at the end of the array if it is positive.
///
/// # Example
Expand Down Expand Up @@ -2481,3 +2480,101 @@ define_sql_function! {
Arr: TextArrayOrNullableTextArray + CombinedNullableValue<E,Jsonb>
>(base: E, path: Arr, new_value: E) -> Arr::Out;
}

#[cfg(feature = "postgres_backend")]
define_sql_function! {
/// Returns target with the item designated by path replaced by new_value,
/// or with new_value added if create_if_missing is true (which is the default)
/// and the item designated by path does not exist.
///
/// It can't set path in scalar
///
/// All earlier steps in the path must exist, or the target is returned unchanged.
/// As with the path oriented operators, negative integers that appear in the path count from the end of JSON arrays.
/// If the last path step is an array index that is out of range,
/// and create_if_missing is true, the new value is added at the beginning of the array if the index is negative,
/// or at the end of the array if it is positive.
///
/// # Example
///
/// ```rust
/// # include!("../../doctest_setup.rs");
/// #
/// # fn main() {
/// # #[cfg(feature = "serde_json")]
/// # run_test().unwrap();
/// # }
/// #
/// # #[cfg(feature = "serde_json")]
/// # fn run_test() -> QueryResult<()> {
/// # use diesel::dsl::jsonb_set_create_if_missing;
/// # use diesel::sql_types::{Jsonb, Array, Json, Nullable, Text};
/// # use serde_json::{json, Value};
/// # let connection = &mut establish_connection();
///
/// let result = diesel::select(jsonb_set_create_if_missing::<Jsonb, Array<Text>, _, _, _, _>(
/// json!([{"f1":1,"f2":null},2,null,3]),
/// vec!["0","f1"],
/// json!([2,3,4]),
/// true
/// )).get_result::<Value>(connection)?;
/// let expected: Value = json!([{"f1": [2, 3, 4], "f2": null}, 2, null, 3]);
/// assert_eq!(result, expected);
///
/// let result = diesel::select(jsonb_set_create_if_missing::<Jsonb, Array<Text>, _, _, _, _>(
/// json!([{"f1":1,"f2":null},2,null,3]),
/// vec!["0","f3"],
/// json!([2,3,4]),
/// false
/// )).get_result::<Value>(connection)?;
/// let expected: Value = json!([{"f1":1, "f2": null},2, null, 3]);
/// assert_eq!(result, expected);
///
/// let result = diesel::select(jsonb_set_create_if_missing::<Jsonb, Array<Text>, _, _, _, _>(
/// json!([{"odd":[2,4,6,8]}]),
/// // not vec!["odd"], cannot set path in scalar
/// vec!["0","odd"],
/// json!([1,3,5,7]),
/// true
/// )).get_result::<Value>(connection)?;
/// let expected: Value = json!([{"odd":[1,3,5,7]}]);
/// assert_eq!(result, expected);
///
/// let empty:Vec<String> = Vec::new();
/// let result = diesel::select(jsonb_set_create_if_missing::<Nullable<Jsonb>, Array<Nullable<Text>>, _, _, _, _>(
/// None::<Value>,
/// empty,
/// None::<Value>,
/// true
/// )).get_result::<Option<Value>>(connection)?;
/// assert!(result.is_none());
///
/// let empty:Vec<String> = Vec::new();
/// let result = diesel::select(jsonb_set_create_if_missing::<Jsonb, Array<Nullable<Text>>, _, _, _, _>(
/// // cannot be json!(null)
/// json!([]),
/// empty,
/// json!(null),
/// true
/// )).get_result::<Value>(connection)?;
/// let expected = json!([]);
/// assert_eq!(result, expected);
///
/// let result = diesel::select(jsonb_set_create_if_missing::<Jsonb, Nullable<Array<Nullable<Text>>>, _, _, _, _>(
/// json!(null),
/// None::<Vec<String>>,
/// json!({"foo": 42}),
/// true
/// )).get_result::<Option<Value>>(connection)?;
/// assert!(result.is_none());
///
///
/// # Ok(())
/// # }
/// ```
#[sql_name = "jsonb_set"]
fn jsonb_set_create_if_missing<
E: JsonbOrNullableJsonb + SingleValue,
Arr: TextArrayOrNullableTextArray + CombinedNullableValue<E,Jsonb>
>(base: E, path: Arr, new_value: E, create_if_missing: Bool) -> Arr::Out;
}
6 changes: 6 additions & 0 deletions diesel/src/pg/expression/helper_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -597,3 +597,9 @@ pub type jsonb_populate_record<B, J> =
#[allow(non_camel_case_types)]
#[cfg(feature = "postgres_backend")]
pub type jsonb_set<B, J, R> = super::functions::jsonb_set<SqlTypeOf<B>, SqlTypeOf<J>, B, J, R>;

/// Return type of [`jsonb_set_create_if_missing(base, path, new_value, create_if_missing)`](super::functions::jsonb_set_create_if_missing())
#[allow(non_camel_case_types)]
#[cfg(feature = "postgres_backend")]
pub type jsonb_set_create_if_missing<B, J, R, C> =
super::functions::jsonb_set_create_if_missing<SqlTypeOf<B>, SqlTypeOf<J>, B, J, R, C>;
7 changes: 7 additions & 0 deletions diesel_derives/tests/auto_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ table! {
name -> Text,
text_array -> Array<Text>,
record -> Record<(Integer, Text, Date)>,
boolean -> Bool,
}
}

Expand Down Expand Up @@ -462,6 +463,12 @@ fn postgres_functions() -> _ {
json_populate_record(pg_extras::record, pg_extras::json),
jsonb_populate_record(pg_extras::record, pg_extras::jsonb),
jsonb_set(pg_extras::jsonb, pg_extras::text_array, pg_extras::jsonb),
jsonb_set_create_if_missing(
pg_extras::jsonb,
pg_extras::text_array,
pg_extras::jsonb,
pg_extras::boolean,
),
)
}

Expand Down

0 comments on commit 907efb9

Please sign in to comment.