From 9687819a7eb58221c1fdd4ee4e3e43d854ab85eb Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Sun, 13 Mar 2022 18:18:09 +0800 Subject: [PATCH 1/2] Supports `time` crate --- Cargo.toml | 8 +++- src/entity/prelude.rs | 33 ++++++++++++++++ src/executor/query.rs | 50 ++++++++++++++++++++++++ tests/common/features/mod.rs | 2 + tests/common/features/schema.rs | 36 +++++++++++++++++ tests/common/features/transaction_log.rs | 17 ++++++++ tests/time_crate_tests.rs | 46 ++++++++++++++++++++++ 7 files changed, 190 insertions(+), 2 deletions(-) create mode 100644 tests/common/features/transaction_log.rs create mode 100644 tests/time_crate_tests.rs diff --git a/Cargo.toml b/Cargo.toml index 903136328..eec669ee9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ futures-util = { version = "^0.3" } tracing = { version = "0.1", features = ["log"] } rust_decimal = { version = "^1", optional = true } sea-orm-macros = { version = "^0.6.0", path = "sea-orm-macros", optional = true } -sea-query = { version = "^0.21.0", features = ["thread-safe"] } +sea-query = { git = "https://github.com/billy1624/sea-query", branch = "pr/256", version = "^0.21.0", features = ["thread-safe"] } sea-strum = { version = "^0.23", features = ["derive", "sea-orm"] } serde = { version = "^1.0", features = ["derive"] } serde_json = { version = "^1", optional = true } @@ -39,6 +39,7 @@ uuid = { version = "0.8", features = ["serde", "v4"], optional = true } ouroboros = "0.14" url = "^2.2" once_cell = "1.8" +time = { version = "^0.2", optional = true } [dev-dependencies] smol = { version = "^1.2" } @@ -60,6 +61,7 @@ default = [ "with-chrono", "with-rust_decimal", "with-uuid", + "with-time", ] macros = ["sea-orm-macros"] mock = [] @@ -67,12 +69,14 @@ with-json = ["serde_json", "sea-query/with-json", "chrono/serde"] with-chrono = ["chrono", "sea-query/with-chrono"] with-rust_decimal = ["rust_decimal", "sea-query/with-rust_decimal"] with-uuid = ["uuid", "sea-query/with-uuid"] +with-time = ["time", "sea-query/with-time"] sqlx-all = ["sqlx-mysql", "sqlx-postgres", "sqlx-sqlite"] -sqlx-dep = ["sqlx-json", "sqlx-chrono", "sqlx-decimal", "sqlx-uuid"] +sqlx-dep = ["sqlx-json", "sqlx-chrono", "sqlx-decimal", "sqlx-uuid", "sqlx-time"] sqlx-json = ["sqlx/json", "with-json"] sqlx-chrono = ["sqlx/chrono", "with-chrono"] sqlx-decimal = ["sqlx/decimal", "with-rust_decimal"] sqlx-uuid = ["sqlx/uuid", "with-uuid"] +sqlx-time = ["sqlx/time", "with-time"] sqlx-mysql = ["sqlx-dep", "sea-query/sqlx-mysql", "sqlx/mysql"] sqlx-postgres = ["sqlx-dep", "sea-query/sqlx-postgres", "sqlx/postgres"] sqlx-sqlite = ["sqlx-dep", "sea-query/sqlx-sqlite", "sqlx/sqlite"] diff --git a/src/entity/prelude.rs b/src/entity/prelude.rs index c88f9d7a8..10b1bb503 100644 --- a/src/entity/prelude.rs +++ b/src/entity/prelude.rs @@ -36,6 +36,39 @@ pub type DateTimeUtc = chrono::DateTime; #[cfg(feature = "with-chrono")] pub type DateTimeLocal = chrono::DateTime; +#[cfg(feature = "with-chrono")] +pub use chrono::NaiveDate as ChronoDate; + +#[cfg(feature = "with-chrono")] +pub use chrono::NaiveTime as ChronoTime; + +#[cfg(feature = "with-chrono")] +pub use chrono::NaiveDateTime as ChronoDateTime; + +/// Date time with fixed offset +#[cfg(feature = "with-chrono")] +pub type ChronoDateTimeWithTimeZone = chrono::DateTime; + +/// Date time represented in UTC +#[cfg(feature = "with-chrono")] +pub type ChronoDateTimeUtc = chrono::DateTime; + +/// Date time represented in local time +#[cfg(feature = "with-chrono")] +pub type ChronoDateTimeLocal = chrono::DateTime; + +#[cfg(feature = "with-time")] +pub use time::Date as TimeDate; + +#[cfg(feature = "with-time")] +pub use time::Time as TimeTime; + +#[cfg(feature = "with-time")] +pub use time::PrimitiveDateTime as TimeDateTime; + +#[cfg(feature = "with-time")] +pub use time::OffsetDateTime as TimeDateTimeWithTimeZone; + #[cfg(feature = "with-rust_decimal")] pub use rust_decimal::Decimal; diff --git a/src/executor/query.rs b/src/executor/query.rs index 4b03e3121..918d513bd 100644 --- a/src/executor/query.rs +++ b/src/executor/query.rs @@ -252,6 +252,44 @@ macro_rules! try_getable_date_time { }; } +macro_rules! try_getable_time { + ( $type: ty ) => { + impl TryGetable for $type { + fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result { + let column = format!("{}{}", pre, col); + match &res.row { + #[cfg(feature = "sqlx-mysql")] + QueryResultRow::SqlxMySql(row) => { + use sqlx::Row; + row.try_get::, _>(column.as_str()) + .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) + .and_then(|opt| opt.ok_or(TryGetError::Null)) + } + #[cfg(feature = "sqlx-postgres")] + QueryResultRow::SqlxPostgres(row) => { + use sqlx::Row; + row.try_get::, _>(column.as_str()) + .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) + .and_then(|opt| opt.ok_or(TryGetError::Null)) + } + #[cfg(feature = "sqlx-sqlite")] + QueryResultRow::SqlxSqlite(_) => { + panic!("{} unsupported by sqlx-sqlite", stringify!($type)) + } + #[cfg(feature = "mock")] + #[allow(unused_variables)] + QueryResultRow::Mock(row) => row.try_get(column.as_str()).map_err(|e| { + debug_print!("{:#?}", e.to_string()); + TryGetError::Null + }), + #[allow(unreachable_patterns)] + _ => unreachable!(), + } + } + } + }; +} + try_getable_all!(bool); try_getable_all!(i8); try_getable_all!(i16); @@ -287,6 +325,18 @@ try_getable_all!(chrono::DateTime); #[cfg(feature = "with-chrono")] try_getable_all!(chrono::DateTime); +#[cfg(feature = "with-time")] +try_getable_time!(time::Date); + +#[cfg(feature = "with-time")] +try_getable_time!(time::Time); + +#[cfg(feature = "with-time")] +try_getable_time!(time::PrimitiveDateTime); + +#[cfg(feature = "with-time")] +try_getable_time!(time::OffsetDateTime); + #[cfg(feature = "with-rust_decimal")] use rust_decimal::Decimal; diff --git a/tests/common/features/mod.rs b/tests/common/features/mod.rs index 18c0ae78a..b5e91ca39 100644 --- a/tests/common/features/mod.rs +++ b/tests/common/features/mod.rs @@ -8,6 +8,7 @@ pub mod satellite; pub mod schema; pub mod sea_orm_active_enums; pub mod self_join; +pub mod transaction_log; pub use active_enum::Entity as ActiveEnum; pub use active_enum_child::Entity as ActiveEnumChild; @@ -19,3 +20,4 @@ pub use satellite::Entity as Satellite; pub use schema::*; pub use sea_orm_active_enums::*; pub use self_join::Entity as SelfJoin; +pub use transaction_log::Entity as TransactionLog; diff --git a/tests/common/features/schema.rs b/tests/common/features/schema.rs index c15192535..6e224fc64 100644 --- a/tests/common/features/schema.rs +++ b/tests/common/features/schema.rs @@ -17,6 +17,7 @@ pub async fn create_tables(db: &DatabaseConnection) -> Result<(), DbErr> { create_self_join_table(db).await?; create_byte_primary_key_table(db).await?; create_satellites_table(db).await?; + create_transaction_log_table(db).await?; let create_enum_stmts = match db_backend { DbBackend::MySql | DbBackend::Sqlite => Vec::new(), @@ -234,3 +235,38 @@ pub async fn create_satellites_table(db: &DbConn) -> Result { create_table(db, &stmt, Satellite).await } + +pub async fn create_transaction_log_table(db: &DbConn) -> Result { + let stmt = sea_query::Table::create() + .table(transaction_log::Entity) + .col( + ColumnDef::new(transaction_log::Column::Id) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col( + ColumnDef::new(transaction_log::Column::Date) + .date() + .not_null(), + ) + .col( + ColumnDef::new(transaction_log::Column::Time) + .time() + .not_null(), + ) + .col( + ColumnDef::new(transaction_log::Column::DateTime) + .date_time() + .not_null(), + ) + .col( + ColumnDef::new(transaction_log::Column::DateTimeTz) + .timestamp_with_time_zone() + .not_null(), + ) + .to_owned(); + + create_table(db, &stmt, TransactionLog).await +} diff --git a/tests/common/features/transaction_log.rs b/tests/common/features/transaction_log.rs new file mode 100644 index 000000000..06010db53 --- /dev/null +++ b/tests/common/features/transaction_log.rs @@ -0,0 +1,17 @@ +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "transaction_log")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub date: TimeDate, + pub time: TimeTime, + pub date_time: TimeDateTime, + pub date_time_tz: TimeDateTimeWithTimeZone, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/tests/time_crate_tests.rs b/tests/time_crate_tests.rs new file mode 100644 index 000000000..0fb4ba32a --- /dev/null +++ b/tests/time_crate_tests.rs @@ -0,0 +1,46 @@ +pub mod common; +pub use common::{features::*, setup::*, TestContext}; +use sea_orm::{entity::prelude::*, DatabaseConnection, IntoActiveModel}; +use time::{date, time}; + +#[sea_orm_macros::test] +#[cfg(any( + feature = "sqlx-mysql", + feature = "sqlx-sqlite", + feature = "sqlx-postgres" +))] +#[cfg_attr( + feature = "sqlx-sqlite", + should_panic(expected = "time::Date unsupported by sqlx-sqlite") +)] +async fn main() { + let ctx = TestContext::new("time_crate_tests").await; + create_tables(&ctx.db).await.unwrap(); + create_transaction_log(&ctx.db).await.unwrap(); + + ctx.delete().await; +} + +pub async fn create_transaction_log(db: &DatabaseConnection) -> Result<(), DbErr> { + let transaction_log = transaction_log::Model { + id: 1, + date: date!(2022 - 03 - 13), + time: time!(16:24:00), + date_time: date!(2022 - 03 - 13).with_time(time!(16:24:00)), + date_time_tz: date!(2022 - 03 - 13) + .with_time(time!(16:24:00)) + .assume_utc(), + }; + + let res = TransactionLog::insert(transaction_log.clone().into_active_model()) + .exec(db) + .await?; + + assert_eq!(transaction_log.id, res.last_insert_id); + assert_eq!( + TransactionLog::find().one(db).await?, + Some(transaction_log.clone()) + ); + + Ok(()) +} From 49b63a00d42255ccae99071f21dc61e3b942ddb0 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Tue, 15 Mar 2022 13:53:03 +0800 Subject: [PATCH 2/2] update sea-query --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index eec669ee9..c3ea2353b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,12 +25,13 @@ path = "src/lib.rs" async-stream = { version = "^0.3" } async-trait = { version = "^0.1" } chrono = { version = "^0", optional = true } +time = { version = "^0.2", optional = true } futures = { version = "^0.3" } futures-util = { version = "^0.3" } tracing = { version = "0.1", features = ["log"] } rust_decimal = { version = "^1", optional = true } sea-orm-macros = { version = "^0.6.0", path = "sea-orm-macros", optional = true } -sea-query = { git = "https://github.com/billy1624/sea-query", branch = "pr/256", version = "^0.21.0", features = ["thread-safe"] } +sea-query = { version = "^0.23.0", features = ["thread-safe"] } sea-strum = { version = "^0.23", features = ["derive", "sea-orm"] } serde = { version = "^1.0", features = ["derive"] } serde_json = { version = "^1", optional = true } @@ -39,7 +40,6 @@ uuid = { version = "0.8", features = ["serde", "v4"], optional = true } ouroboros = "0.14" url = "^2.2" once_cell = "1.8" -time = { version = "^0.2", optional = true } [dev-dependencies] smol = { version = "^1.2" }