From ddf1e23f826a634f939ceb1ee3b97bcfe9a83932 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Thu, 17 Feb 2022 15:45:51 +0800 Subject: [PATCH 1/4] Fixing and testing `into_json` of various types --- src/query/json.rs | 54 +++++++++++++++++++++++++++++++++- tests/timestamp_tests.rs | 63 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 1 deletion(-) diff --git a/src/query/json.rs b/src/query/json.rs index 589f0fada3..e5c27d8595 100644 --- a/src/query/json.rs +++ b/src/query/json.rs @@ -28,6 +28,17 @@ impl FromQueryResult for JsonValue { } }; } + macro_rules! compatible_mysql_type { + ( $type: ty ) => { + if <$type as Type>::compatible(col_type) { + map.insert( + col.to_owned(), + json!(res.try_get::>(pre, &col)?), + ); + continue; + } + }; + } match_mysql_type!(bool); match_mysql_type!(i8); match_mysql_type!(i16); @@ -40,6 +51,18 @@ impl FromQueryResult for JsonValue { match_mysql_type!(f32); match_mysql_type!(f64); match_mysql_type!(String); + #[cfg(feature = "with-chrono")] + match_mysql_type!(chrono::NaiveDate); + #[cfg(feature = "with-chrono")] + match_mysql_type!(chrono::NaiveTime); + #[cfg(feature = "with-chrono")] + match_mysql_type!(chrono::NaiveDateTime); + #[cfg(feature = "with-chrono")] + match_mysql_type!(chrono::DateTime); + #[cfg(feature = "with-rust_decimal")] + match_mysql_type!(rust_decimal::Decimal); + #[cfg(feature = "with-json")] + compatible_mysql_type!(serde_json::Value); } Ok(JsonValue::Object(map)) } @@ -66,6 +89,17 @@ impl FromQueryResult for JsonValue { } }; } + macro_rules! compatible_postgres_type { + ( $type: ty ) => { + if <$type as Type>::compatible(col_type) { + map.insert( + col.to_owned(), + json!(res.try_get::>(pre, &col)?), + ); + continue; + } + }; + } match_postgres_type!(bool); match_postgres_type!(i8); match_postgres_type!(i16); @@ -77,7 +111,19 @@ impl FromQueryResult for JsonValue { // match_postgres_type!(u64); // unsupported by SQLx Postgres match_postgres_type!(f32); match_postgres_type!(f64); - match_postgres_type!(String); + #[cfg(feature = "with-chrono")] + match_postgres_type!(chrono::NaiveDate); + #[cfg(feature = "with-chrono")] + match_postgres_type!(chrono::NaiveTime); + #[cfg(feature = "with-chrono")] + match_postgres_type!(chrono::NaiveDateTime); + #[cfg(feature = "with-chrono")] + match_postgres_type!(chrono::DateTime); + #[cfg(feature = "with-rust_decimal")] + match_postgres_type!(rust_decimal::Decimal); + #[cfg(feature = "with-json")] + compatible_postgres_type!(serde_json::Value); + compatible_postgres_type!(String); } Ok(JsonValue::Object(map)) } @@ -116,6 +162,12 @@ impl FromQueryResult for JsonValue { match_sqlite_type!(f32); match_sqlite_type!(f64); match_sqlite_type!(String); + #[cfg(feature = "with-chrono")] + match_sqlite_type!(chrono::NaiveDate); + #[cfg(feature = "with-chrono")] + match_sqlite_type!(chrono::NaiveTime); + #[cfg(feature = "with-chrono")] + match_sqlite_type!(chrono::NaiveDateTime); } Ok(JsonValue::Object(map)) } diff --git a/tests/timestamp_tests.rs b/tests/timestamp_tests.rs index d0334a5cbc..b7718ef32c 100644 --- a/tests/timestamp_tests.rs +++ b/tests/timestamp_tests.rs @@ -1,6 +1,7 @@ pub mod common; pub use common::{features::*, setup::*, TestContext}; use sea_orm::{entity::prelude::*, DatabaseConnection, IntoActiveModel}; +use serde_json::json; #[sea_orm_macros::test] #[cfg(any( @@ -34,6 +35,37 @@ pub async fn create_applog(db: &DatabaseConnection) -> Result<(), DbErr> { assert_eq!(log.id, res.last_insert_id); assert_eq!(Applog::find().one(db).await?, Some(log.clone())); + #[cfg(feature = "sqlx-sqlite")] + assert_eq!( + Applog::find().into_json().one(db).await?, + Some(json!({ + "id": 1, + "action": "Testing", + "json": r#""HI""#, + "created_at": "2021-09-17 09:50:20", + })) + ); + #[cfg(feature = "sqlx-mysql")] + assert_eq!( + Applog::find().into_json().one(db).await?, + Some(json!({ + "id": 1, + "action": "Testing", + "json": "HI", + "created_at": "2021-09-17T09:50:20Z", + })) + ); + #[cfg(feature = "sqlx-postgres")] + assert_eq!( + Applog::find().into_json().one(db).await?, + Some(json!({ + "id": 1, + "action": "Testing", + "json": "HI", + "created_at": "2021-09-17T09:50:20+00:00", + })) + ); + Ok(()) } @@ -52,5 +84,36 @@ pub async fn create_satellites_log(db: &DatabaseConnection) -> Result<(), DbErr> assert_eq!(archive.id, res.last_insert_id); assert_eq!(Satellite::find().one(db).await?, Some(archive.clone())); + #[cfg(feature = "sqlx-sqlite")] + assert_eq!( + Satellite::find().into_json().one(db).await?, + Some(json!({ + "id": 1, + "satellite_name": "Sea-00001-2022", + "launch_date": "2022-01-07 12:11:23", + "deployment_date": "2022-01-07 12:11:23", + })) + ); + #[cfg(feature = "sqlx-mysql")] + assert_eq!( + Satellite::find().into_json().one(db).await?, + Some(json!({ + "id": 1, + "satellite_name": "Sea-00001-2022", + "launch_date": "2022-01-07T12:11:23Z", + "deployment_date": "2022-01-07T12:11:23Z", + })) + ); + #[cfg(feature = "sqlx-postgres")] + assert_eq!( + Satellite::find().into_json().one(db).await?, + Some(json!({ + "id": 1, + "satellite_name": "Sea-00001-2022", + "launch_date": "2022-01-07T12:11:23+00:00", + "deployment_date": "2022-01-07T12:11:23+00:00", + })) + ); + Ok(()) } From 5316a6f084a3a92f9c0cb8411ad3e8ba77be3cc7 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Tue, 22 Mar 2022 17:35:55 +0800 Subject: [PATCH 2/4] Support `into_json` for UUID --- src/query/json.rs | 75 +++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 45 deletions(-) diff --git a/src/query/json.rs b/src/query/json.rs index e5c27d8595..42cc55c6c4 100644 --- a/src/query/json.rs +++ b/src/query/json.rs @@ -4,12 +4,24 @@ pub use serde_json::Value as JsonValue; impl FromQueryResult for JsonValue { fn from_query_result(res: &QueryResult, pre: &str) -> Result { + let mut map = Map::new(); + #[allow(unused_macros)] + macro_rules! try_get_type { + ( $type: ty, $col: ident ) => { + if let Ok(v) = res.try_get::>(pre, &$col) { + map.insert( + $col.to_owned(), + json!(v), + ); + continue; + } + } + } match &res.row { #[cfg(feature = "sqlx-mysql")] QueryResultRow::SqlxMySql(row) => { use serde_json::json; use sqlx::{Column, MySql, Row, Type}; - let mut map = Map::new(); for column in row.columns() { let col = if !column.name().starts_with(pre) { continue; @@ -20,22 +32,7 @@ impl FromQueryResult for JsonValue { macro_rules! match_mysql_type { ( $type: ty ) => { if <$type as Type>::type_info().eq(col_type) { - map.insert( - col.to_owned(), - json!(res.try_get::>(pre, &col)?), - ); - continue; - } - }; - } - macro_rules! compatible_mysql_type { - ( $type: ty ) => { - if <$type as Type>::compatible(col_type) { - map.insert( - col.to_owned(), - json!(res.try_get::>(pre, &col)?), - ); - continue; + try_get_type!($type, col) } }; } @@ -61,8 +58,12 @@ impl FromQueryResult for JsonValue { match_mysql_type!(chrono::DateTime); #[cfg(feature = "with-rust_decimal")] match_mysql_type!(rust_decimal::Decimal); + try_get_type!(String, col); #[cfg(feature = "with-json")] - compatible_mysql_type!(serde_json::Value); + try_get_type!(serde_json::Value, col); + #[cfg(feature = "with-uuid")] + try_get_type!(uuid::Uuid, col); + try_get_type!(Vec, col); } Ok(JsonValue::Object(map)) } @@ -70,7 +71,6 @@ impl FromQueryResult for JsonValue { QueryResultRow::SqlxPostgres(row) => { use serde_json::json; use sqlx::{Column, Postgres, Row, Type}; - let mut map = Map::new(); for column in row.columns() { let col = if !column.name().starts_with(pre) { continue; @@ -81,22 +81,7 @@ impl FromQueryResult for JsonValue { macro_rules! match_postgres_type { ( $type: ty ) => { if <$type as Type>::type_info().eq(col_type) { - map.insert( - col.to_owned(), - json!(res.try_get::>(pre, &col)?), - ); - continue; - } - }; - } - macro_rules! compatible_postgres_type { - ( $type: ty ) => { - if <$type as Type>::compatible(col_type) { - map.insert( - col.to_owned(), - json!(res.try_get::>(pre, &col)?), - ); - continue; + try_get_type!($type, col) } }; } @@ -121,9 +106,12 @@ impl FromQueryResult for JsonValue { match_postgres_type!(chrono::DateTime); #[cfg(feature = "with-rust_decimal")] match_postgres_type!(rust_decimal::Decimal); + try_get_type!(String, col); #[cfg(feature = "with-json")] - compatible_postgres_type!(serde_json::Value); - compatible_postgres_type!(String); + try_get_type!(serde_json::Value, col); + #[cfg(feature = "with-uuid")] + try_get_type!(uuid::Uuid, col); + try_get_type!(Vec, col); } Ok(JsonValue::Object(map)) } @@ -131,7 +119,6 @@ impl FromQueryResult for JsonValue { QueryResultRow::SqlxSqlite(row) => { use serde_json::json; use sqlx::{Column, Row, Sqlite, Type}; - let mut map = Map::new(); for column in row.columns() { let col = if !column.name().starts_with(pre) { continue; @@ -142,11 +129,7 @@ impl FromQueryResult for JsonValue { macro_rules! match_sqlite_type { ( $type: ty ) => { if <$type as Type>::type_info().eq(col_type) { - map.insert( - col.to_owned(), - json!(res.try_get::>(pre, &col)?), - ); - continue; + try_get_type!($type, col) } }; } @@ -161,19 +144,21 @@ impl FromQueryResult for JsonValue { // match_sqlite_type!(u64); // unsupported by SQLx Sqlite match_sqlite_type!(f32); match_sqlite_type!(f64); - match_sqlite_type!(String); #[cfg(feature = "with-chrono")] match_sqlite_type!(chrono::NaiveDate); #[cfg(feature = "with-chrono")] match_sqlite_type!(chrono::NaiveTime); #[cfg(feature = "with-chrono")] match_sqlite_type!(chrono::NaiveDateTime); + try_get_type!(String, col); + #[cfg(feature = "with-uuid")] + try_get_type!(uuid::Uuid, col); + try_get_type!(Vec, col); } Ok(JsonValue::Object(map)) } #[cfg(feature = "mock")] QueryResultRow::Mock(row) => { - let mut map = Map::new(); for (column, value) in row.clone().into_column_value_tuples() { let col = if !column.starts_with(pre) { continue; From 0e99349bc50af4a53697abc7f068c40ce6a956fb Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Tue, 22 Mar 2022 17:36:22 +0800 Subject: [PATCH 3/4] Testing `into_json` for UUID --- tests/timestamp_tests.rs | 1 + tests/uuid_tests.rs | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/tests/timestamp_tests.rs b/tests/timestamp_tests.rs index b7718ef32c..0350e8b169 100644 --- a/tests/timestamp_tests.rs +++ b/tests/timestamp_tests.rs @@ -1,5 +1,6 @@ pub mod common; pub use common::{features::*, setup::*, TestContext}; +use pretty_assertions::assert_eq; use sea_orm::{entity::prelude::*, DatabaseConnection, IntoActiveModel}; use serde_json::json; diff --git a/tests/uuid_tests.rs b/tests/uuid_tests.rs index 1053bb55f1..20df50859a 100644 --- a/tests/uuid_tests.rs +++ b/tests/uuid_tests.rs @@ -1,7 +1,9 @@ pub mod common; pub use common::{features::*, setup::*, TestContext}; +use pretty_assertions::assert_eq; use sea_orm::{entity::prelude::*, entity::*, DatabaseConnection}; +use serde_json::json; #[sea_orm_macros::test] #[cfg(any( @@ -34,6 +36,25 @@ pub async fn insert_metadata(db: &DatabaseConnection) -> Result<(), DbErr> { assert_eq!(result, metadata); + let json = metadata::Entity::find() + .filter(metadata::Column::Uuid.eq(metadata.uuid)) + .into_json() + .one(db) + .await?; + + assert_eq!( + json, + Some(json!({ + "uuid": metadata.uuid, + "type": metadata.ty, + "key": metadata.key, + "value": metadata.value, + "bytes": metadata.bytes, + "date": metadata.date, + "time": metadata.time, + })) + ); + Ok(()) } From fe72cd993bad4ea6f1ece11934806fac28dfac66 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Tue, 22 Mar 2022 18:00:30 +0800 Subject: [PATCH 4/4] Fixup --- src/query/json.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/query/json.rs b/src/query/json.rs index 42cc55c6c4..307d001896 100644 --- a/src/query/json.rs +++ b/src/query/json.rs @@ -9,13 +9,10 @@ impl FromQueryResult for JsonValue { macro_rules! try_get_type { ( $type: ty, $col: ident ) => { if let Ok(v) = res.try_get::>(pre, &$col) { - map.insert( - $col.to_owned(), - json!(v), - ); + map.insert($col.to_owned(), json!(v)); continue; } - } + }; } match &res.row { #[cfg(feature = "sqlx-mysql")] @@ -58,9 +55,9 @@ impl FromQueryResult for JsonValue { match_mysql_type!(chrono::DateTime); #[cfg(feature = "with-rust_decimal")] match_mysql_type!(rust_decimal::Decimal); - try_get_type!(String, col); #[cfg(feature = "with-json")] try_get_type!(serde_json::Value, col); + try_get_type!(String, col); #[cfg(feature = "with-uuid")] try_get_type!(uuid::Uuid, col); try_get_type!(Vec, col); @@ -106,9 +103,9 @@ impl FromQueryResult for JsonValue { match_postgres_type!(chrono::DateTime); #[cfg(feature = "with-rust_decimal")] match_postgres_type!(rust_decimal::Decimal); - try_get_type!(String, col); #[cfg(feature = "with-json")] try_get_type!(serde_json::Value, col); + try_get_type!(String, col); #[cfg(feature = "with-uuid")] try_get_type!(uuid::Uuid, col); try_get_type!(Vec, col);