Skip to content

Commit

Permalink
fix: definition of json_pretty.
Browse files Browse the repository at this point in the history
  • Loading branch information
xuehaonan27 committed Dec 19, 2024
1 parent 0e38689 commit 31d2f1c
Show file tree
Hide file tree
Showing 4 changed files with 241 additions and 24 deletions.
18 changes: 9 additions & 9 deletions diesel/src/sqlite/expression/expression_methods.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! Sqlite specific expression methods.
pub(in crate::sqlite) use self::private::{
BinaryOrNullableBinary, MaybeNullableValue, TextOrNullableText,
TextOrNullableTextOrBinaryOrNullableBinary,
BinaryOrNullableBinary, JsonOrNullableJsonOrJsonbOrNullableJsonb, MaybeNullableValue,
TextOrNullableText,
};
use super::operators::*;
use crate::dsl;
Expand Down Expand Up @@ -88,7 +88,7 @@ pub trait SqliteExpressionMethods: Expression + Sized {
impl<T: Expression> SqliteExpressionMethods for T {}

pub(in crate::sqlite) mod private {
use crate::sql_types::{Binary, MaybeNullableType, Nullable, SingleValue, Text};
use crate::sql_types::{Binary, Json, Jsonb, MaybeNullableType, Nullable, SingleValue, Text};

#[diagnostic::on_unimplemented(
message = "`{Self}` is neither `diesel::sql_types::Text` nor `diesel::sql_types::Nullable<Text>`",
Expand All @@ -109,14 +109,14 @@ pub(in crate::sqlite) mod private {
impl BinaryOrNullableBinary for Nullable<Binary> {}

#[diagnostic::on_unimplemented(
message = "`{Self}` is not `diesel::sql_types::Text`, `diesel::sql_types::Nullable<Text>`, `diesel::sql_types::Binary` or `diesel::sql_types::Nullable<Binary>`",
message = "`{Self}` is neither `diesel::sql_types::Json`, `diesel::sql_types::Jsonb`, `diesel::sql_types::Nullable<Json>` nor `diesel::sql_types::Nullable<Jsonb>`",
note = "try to provide an expression that produces one of the expected sql types"
)]
pub trait TextOrNullableTextOrBinaryOrNullableBinary {}
impl TextOrNullableTextOrBinaryOrNullableBinary for Text {}
impl TextOrNullableTextOrBinaryOrNullableBinary for Nullable<Text> {}
impl TextOrNullableTextOrBinaryOrNullableBinary for Binary {}
impl TextOrNullableTextOrBinaryOrNullableBinary for Nullable<Binary> {}
pub trait JsonOrNullableJsonOrJsonbOrNullableJsonb {}
impl JsonOrNullableJsonOrJsonbOrNullableJsonb for Json {}
impl JsonOrNullableJsonOrJsonbOrNullableJsonb for Nullable<Json> {}
impl JsonOrNullableJsonOrJsonbOrNullableJsonb for Jsonb {}
impl JsonOrNullableJsonOrJsonbOrNullableJsonb for Nullable<Jsonb> {}

pub trait MaybeNullableValue<T>: SingleValue {
type Out: SingleValue;
Expand Down
235 changes: 222 additions & 13 deletions diesel/src/sqlite/expression/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
use crate::expression::functions::define_sql_function;
use crate::sql_types::*;
use crate::sqlite::expression::expression_methods::BinaryOrNullableBinary;
use crate::sqlite::expression::expression_methods::JsonOrNullableJsonOrJsonbOrNullableJsonb;
use crate::sqlite::expression::expression_methods::MaybeNullableValue;
use crate::sqlite::expression::expression_methods::TextOrNullableText;
use crate::sqlite::expression::expression_methods::TextOrNullableTextOrBinaryOrNullableBinary;

#[cfg(feature = "sqlite")]
define_sql_function! {
Expand Down Expand Up @@ -111,7 +111,7 @@ define_sql_function! {
define_sql_function! {
/// Converts the given json value to pretty-printed, indented text
///
/// /// # Example
/// # Example
///
/// ```rust
/// # include!("../../doctest_setup.rs");
Expand All @@ -125,7 +125,7 @@ define_sql_function! {
/// # fn run_test() -> QueryResult<()> {
/// # use diesel::dsl::{sql, json_pretty};
/// # use serde_json::{json, Value};
/// # use diesel::sql_types::{Text, Binary, Nullable};
/// # use diesel::sql_types::{Text, Json, Jsonb, Nullable};
/// # let connection = &mut establish_connection();
///
/// let version = diesel::select(sql::<Text>("sqlite_version();"))
Expand All @@ -144,7 +144,7 @@ define_sql_function! {
/// return Ok(());
/// }
///
/// let result = diesel::select(json_pretty::<Text, _>(r#"[{"f1":1,"f2":null},2,null,3]"#))
/// let result = diesel::select(json_pretty::<Json, _>(json!([{"f1":1,"f2":null},2,null,3])))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"[
Expand All @@ -157,7 +157,45 @@ define_sql_function! {
/// 3
/// ]"#, result);
///
/// let result = diesel::select(json_pretty::<Binary, _>(br#"[{"f1":1,"f2":null},2,null,3]"#))
/// let result = diesel::select(json_pretty::<Json, _>(json!({"a": 1, "b": "cd"})))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"{
/// "a": 1,
/// "b": "cd"
/// }"#, result);
///
/// let result = diesel::select(json_pretty::<Json, _>(json!("abc")))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#""abc""#, result);
///
/// let result = diesel::select(json_pretty::<Json, _>(json!(22)))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"22"#, result);
///
/// let result = diesel::select(json_pretty::<Json, _>(json!(false)))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"false"#, result);
///
/// let result = diesel::select(json_pretty::<Json, _>(json!(null)))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"null"#, result);
///
/// let result = diesel::select(json_pretty::<Json, _>(json!({})))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"{}"#, result);
///
/// let result = diesel::select(json_pretty::<Nullable<Json>, _>(None::<Value>))
/// .get_result::<Option<String>>(connection)?;
///
/// assert!(result.is_none());
///
/// let result = diesel::select(json_pretty::<Jsonb, _>(json!([{"f1":1,"f2":null},2,null,3])))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"[
Expand All @@ -170,46 +208,217 @@ define_sql_function! {
/// 3
/// ]"#, result);
///
/// let result = diesel::select(json_pretty::<Text, _>(r#"{"a": 1, "b": "cd"}"#))
/// let result = diesel::select(json_pretty::<Jsonb, _>(json!({"a": 1, "b": "cd"})))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"{
/// "a": 1,
/// "b": "cd"
/// }"#, result);
///
/// let result = diesel::select(json_pretty::<Text, _>(r#""abc""#))
/// let result = diesel::select(json_pretty::<Jsonb, _>(json!("abc")))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#""abc""#, result);
///
/// let result = diesel::select(json_pretty::<Jsonb, _>(json!(22)))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"22"#, result);
///
/// let result = diesel::select(json_pretty::<Jsonb, _>(json!(false)))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"false"#, result);
///
/// let result = diesel::select(json_pretty::<Jsonb, _>(json!(null)))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"null"#, result);
///
/// let result = diesel::select(json_pretty::<Jsonb, _>(json!({})))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"{}"#, result);
///
/// let result = diesel::select(json_pretty::<Nullable<Jsonb>, _>(None::<Value>))
/// .get_result::<Option<String>>(connection)?;
///
/// assert!(result.is_none());
/// # Ok(())
/// # }
/// ```
fn json_pretty<J: JsonOrNullableJsonOrJsonbOrNullableJsonb + MaybeNullableValue<Text>>(j: J) -> J::Out;
}

#[cfg(feature = "sqlite")]
define_sql_function! {
/// Converts the given json value to pretty-printed, indented text
///
/// # 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::{sql, json_pretty_with_indentation};
/// # use serde_json::{json, Value};
/// # use diesel::sql_types::{Text, Json, Jsonb, Nullable};
/// # let connection = &mut establish_connection();
///
/// let version = diesel::select(sql::<Text>("sqlite_version();"))
/// .get_result::<String>(connection)?;
///
/// // Querying SQLite version should not fail.
/// let version_components: Vec<&str> = version.split('.').collect();
/// let major: u32 = version_components[0].parse().unwrap();
/// let minor: u32 = version_components[1].parse().unwrap();
/// let patch: u32 = version_components[2].parse().unwrap();
///
/// if major > 3 || (major == 3 && minor >= 46) {
/// /* Valid sqlite version, do nothing */
/// } else {
/// println!("SQLite version is too old, skipping the test.");
/// return Ok(());
/// }
///
/// let result = diesel::select(json_pretty_with_indentation::<Json, _, _>(json!([{"f1":1,"f2":null},2,null,3]), " "))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"[
/// {
/// "f1": 1,
/// "f2": null
/// },
/// 2,
/// null,
/// 3
/// ]"#, result);
///
/// let result = diesel::select(json_pretty_with_indentation::<Json, _, _>(json!([{"f1":1,"f2":null},2,null,3]), None::<&str>))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"[
/// {
/// "f1": 1,
/// "f2": null
/// },
/// 2,
/// null,
/// 3
/// ]"#, result);
///
/// let result = diesel::select(json_pretty_with_indentation::<Json, _, _>(json!({"a": 1, "b": "cd"}), " "))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"{
/// "a": 1,
/// "b": "cd"
/// }"#, result);
///
/// let result = diesel::select(json_pretty_with_indentation::<Json, _, _>(json!("abc"), " "))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#""abc""#, result);
///
/// let result = diesel::select(json_pretty_with_indentation::<Json, _, _>(json!(22), " "))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"22"#, result);
///
/// let result = diesel::select(json_pretty_with_indentation::<Json, _, _>(json!(false), None::<&str>))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"false"#, result);
///
/// let result = diesel::select(json_pretty_with_indentation::<Json, _, _>(json!(null), None::<&str>))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"null"#, result);
///
/// let result = diesel::select(json_pretty_with_indentation::<Json, _, _>(json!({}), " "))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"{}"#, result);
///
/// let result = diesel::select(json_pretty_with_indentation::<Nullable<Json>, _, _>(None::<Value>, None::<&str>))
/// .get_result::<Option<String>>(connection)?;
///
/// assert!(result.is_none());
///
/// let result = diesel::select(json_pretty_with_indentation::<Jsonb, _, _>(json!([{"f1":1,"f2":null},2,null,3]), " "))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"[
/// {
/// "f1": 1,
/// "f2": null
/// },
/// 2,
/// null,
/// 3
/// ]"#, result);
///
/// let result = diesel::select(json_pretty_with_indentation::<Jsonb, _, _>(json!([{"f1":1,"f2":null},2,null,3]), None::<&str>))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"[
/// {
/// "f1": 1,
/// "f2": null
/// },
/// 2,
/// null,
/// 3
/// ]"#, result);
///
/// let result = diesel::select(json_pretty_with_indentation::<Jsonb, _, _>(json!({"a": 1, "b": "cd"}), " "))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"{
/// "a": 1,
/// "b": "cd"
/// }"#, result);
///
/// let result = diesel::select(json_pretty_with_indentation::<Jsonb, _, _>(json!("abc"), " "))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#""abc""#, result);
///
/// let result = diesel::select(json_pretty::<Text, _>(r#"22"#))
/// let result = diesel::select(json_pretty_with_indentation::<Jsonb, _, _>(json!(22), " "))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"22"#, result);
///
/// let result = diesel::select(json_pretty::<Text, _>(r#"false"#))
/// let result = diesel::select(json_pretty_with_indentation::<Jsonb, _, _>(json!(false), None::<&str>))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"false"#, result);
///
/// let result = diesel::select(json_pretty::<Text, _>(r#"null"#))
/// let result = diesel::select(json_pretty_with_indentation::<Jsonb, _, _>(json!(null), None::<&str>))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"null"#, result);
///
/// let result = diesel::select(json_pretty::<Text, _>(r#"{}"#))
/// let result = diesel::select(json_pretty_with_indentation::<Jsonb, _, _>(json!({}), " "))
/// .get_result::<String>(connection)?;
///
/// assert_eq!(r#"{}"#, result);
///
/// let result = diesel::select(json_pretty::<Nullable<Text>, _>(None::<&str>))
/// let result = diesel::select(json_pretty_with_indentation::<Nullable<Jsonb>, _, _>(None::<Value>, None::<&str>))
/// .get_result::<Option<String>>(connection)?;
///
/// assert!(result.is_none());
///
/// # Ok(())
/// # }
/// ```
fn json_pretty<E: TextOrNullableTextOrBinaryOrNullableBinary + MaybeNullableValue<Text>>(e: E) -> E::Out;
#[sql_name = "json_pretty"]
fn json_pretty_with_indentation<J: JsonOrNullableJsonOrJsonbOrNullableJsonb + MaybeNullableValue<Text>>(j: J, indentation: Nullable<Text>) -> J::Out;
}
6 changes: 6 additions & 0 deletions diesel/src/sqlite/expression/helper_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,9 @@ pub type jsonb<E> = super::functions::jsonb<SqlTypeOf<E>, E>;
#[allow(non_camel_case_types)]
#[cfg(feature = "sqlite")]
pub type json_pretty<E> = super::functions::json_pretty<SqlTypeOf<E>, E>;

/// Return type of [`json_pretty(json, indent)`](super::functions::json_pretty_with_indentation())
#[allow(non_camel_case_types)]
#[cfg(feature = "sqlite")]
pub type json_pretty_with_indentation<J, I> =
super::functions::json_pretty_with_indentation<SqlTypeOf<J>, J, I>;
6 changes: 4 additions & 2 deletions diesel_derives/tests/auto_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,8 +489,10 @@ fn sqlite_functions() -> _ {
(
json(sqlite_extras::text),
jsonb(sqlite_extras::blob),
json_pretty(sqlite_extras::text),
json_pretty(sqlite_extras::blob),
json_pretty(sqlite_extras::json),
json_pretty(sqlite_extras::jsonb),
json_pretty_with_indentation(sqlite_extras::json, " "),
json_pretty_with_indentation(sqlite_extras::jsonb, " "),
)
}

Expand Down

0 comments on commit 31d2f1c

Please sign in to comment.