diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bea7112..b7757fb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## 0.2.2 - 2021-09-18 + +- [[#105]] Compact entity format +- [[#132]] Add ActiveModel `insert` & `update` +- [[#129]] Add `set` method to `UpdateMany` +- [[#118]] Initial lock support +- [[#167]] Add `FromQueryResult::find_by_statement` + +[#105]: https://github.com/SeaQL/sea-orm/issues/105 +[#132]: https://github.com/SeaQL/sea-orm/issues/132 +[#129]: https://github.com/SeaQL/sea-orm/issues/129 +[#118]: https://github.com/SeaQL/sea-orm/issues/118 +[#167]: https://github.com/SeaQL/sea-orm/issues/167 + ## 0.2.1 - 2021-09-04 - Update dependencies diff --git a/Cargo.toml b/Cargo.toml index 3641e030..3e5a9682 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = [".", "sea-orm-macros", "sea-orm-codegen"] [package] name = "sea-orm" -version = "0.2.1" +version = "0.2.2" authors = ["Chris Tsang "] edition = "2018" description = "🐚 An async & dynamic ORM for Rust" @@ -29,8 +29,8 @@ futures = { version = "^0.3" } futures-util = { version = "^0.3" } log = { version = "^0.4", optional = true } rust_decimal = { version = "^1", optional = true } -sea-orm-macros = { version = "^0.2", path = "sea-orm-macros", optional = true } -sea-query = { version = "^0.16.1", features = ["thread-safe"] } +sea-orm-macros = { version = "^0.2.2", path = "sea-orm-macros", optional = true } +sea-query = { version = "^0.16.3", features = ["thread-safe"] } sea-strum = { version = "^0.21", features = ["derive", "sea-orm"] } serde = { version = "^1.0", features = ["derive"] } serde_json = { version = "^1", optional = true } diff --git a/examples/rocket_example/Cargo.toml b/examples/rocket_example/Cargo.toml index 0dfab575..120c7290 100644 --- a/examples/rocket_example/Cargo.toml +++ b/examples/rocket_example/Cargo.toml @@ -23,11 +23,6 @@ rocket_dyn_templates = { git = "https://github.com/SergioBenitez/Rocket.git", fe sea-orm = { path = "../../", version = "^0.2", features = ["macros"], default-features = false } serde_json = { version = "^1" } -[dependencies.sqlx] -version = "^0.5" -default-features = false -features = ["macros", "offline", "migrate"] - [features] default = ["sqlx-postgres"] sqlx-mysql = ["sea-orm/sqlx-mysql", "rocket_db_pools/sqlx_mysql"] diff --git a/examples/rocket_example/src/main.rs b/examples/rocket_example/src/main.rs index 8e9928ea..1adf3436 100644 --- a/examples/rocket_example/src/main.rs +++ b/examples/rocket_example/src/main.rs @@ -10,7 +10,7 @@ use rocket::{Build, Request, Rocket}; use rocket_db_pools::{sqlx, Connection, Database}; use rocket_dyn_templates::{context, Template}; -use sea_orm::entity::*; +use sea_orm::{entity::*, query::*}; mod pool; use pool::RocketDbPool; @@ -81,7 +81,9 @@ async fn list( ) -> Template { let page = page.unwrap_or(0); let posts_per_page = posts_per_page.unwrap_or(DEFAULT_POSTS_PER_PAGE); - let paginator = Post::find().paginate(&conn, posts_per_page); + let paginator = Post::find() + .order_by_asc(post::Column::Id) + .paginate(&conn, posts_per_page); let num_pages = paginator.num_pages().await.ok().unwrap(); let posts = paginator diff --git a/examples/rocket_example/src/post.rs b/examples/rocket_example/src/post.rs index 0bce0e7a..9a56e271 100644 --- a/examples/rocket_example/src/post.rs +++ b/examples/rocket_example/src/post.rs @@ -1,65 +1,17 @@ use rocket::serde::{Deserialize, Serialize}; use sea_orm::entity::prelude::*; -#[derive(Copy, Clone, Default, Debug, DeriveEntity, Deserialize, Serialize)] -#[serde(crate = "rocket::serde")] -pub struct Entity; - -impl EntityName for Entity { - fn table_name(&self) -> &str { - "posts" - } -} - -#[derive( - Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Deserialize, Serialize, FromForm, -)] +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize, FromForm)] #[serde(crate = "rocket::serde")] +#[sea_orm(table_name = "posts")] pub struct Model { - #[serde(skip_deserializing, skip_serializing_if = "Option::is_none")] - pub id: Option, + #[sea_orm(primary_key)] + pub id: i32, pub title: String, pub text: String, } -#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] -pub enum Column { - Id, - Title, - Text, -} - -#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] -pub enum PrimaryKey { - Id, -} - -impl PrimaryKeyTrait for PrimaryKey { - type ValueType = i32; - - fn auto_increment() -> bool { - true - } -} - -#[derive(Copy, Clone, Debug, EnumIter)] +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation {} -impl ColumnTrait for Column { - type EntityName = Entity; - - fn def(&self) -> ColumnDef { - match self { - Self::Id => ColumnType::Integer.def(), - Self::Title => ColumnType::String(None).def(), - Self::Text => ColumnType::String(None).def(), - } - } -} - -impl RelationTrait for Relation { - fn def(&self) -> RelationDef { - panic!() - } -} impl ActiveModelBehavior for ActiveModel {} diff --git a/examples/rocket_example/templates/edit.html.tera b/examples/rocket_example/templates/edit.html.tera index 47882e65..2ccb81a1 100644 --- a/examples/rocket_example/templates/edit.html.tera +++ b/examples/rocket_example/templates/edit.html.tera @@ -5,6 +5,12 @@
+ New Post
+ &str { - "cake" - } -} - -#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)] +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "cake")] pub struct Model { + #[sea_orm(primary_key)] pub id: i32, pub name: String, } -#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] -pub enum Column { - Id, - Name, -} - -#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] -pub enum PrimaryKey { - Id, -} - -impl PrimaryKeyTrait for PrimaryKey { - type ValueType = i32; - - fn auto_increment() -> bool { - true - } -} - -#[derive(Copy, Clone, Debug, EnumIter)] +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation {} -impl ColumnTrait for Column { - type EntityName = Entity; - - fn def(&self) -> ColumnDef { - match self { - Self::Id => ColumnType::Integer.def(), - Self::Name => ColumnType::String(None).def(), - } - } -} - -impl RelationTrait for Relation { - fn def(&self) -> RelationDef { - unreachable!() - } -} - impl ActiveModelBehavior for ActiveModel {} diff --git a/sea-orm-cli/Cargo.toml b/sea-orm-cli/Cargo.toml index 484b6efb..09e20546 100644 --- a/sea-orm-cli/Cargo.toml +++ b/sea-orm-cli/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "sea-orm-cli" -version = "0.2.0" +version = "0.2.2" authors = [ "Billy Chan " ] edition = "2018" description = "Command line utility for SeaORM" @@ -21,8 +21,8 @@ path = "src/main.rs" clap = { version = "^2.33.3" } dotenv = { version = "^0.15" } async-std = { version = "^1.9", features = [ "attributes" ] } -sea-orm-codegen = { version = "^0.2.0", path = "../sea-orm-codegen" } -sea-schema = { version = "^0.2.8", git = "https://github.com/SeaQL/sea-schema.git", default-features = false, features = [ +sea-orm-codegen = { version = "^0.2.2", path = "../sea-orm-codegen" } +sea-schema = { version = "^0.2.8", default-features = false, features = [ "debug-print", "sqlx-mysql", "sqlx-postgres", diff --git a/sea-orm-codegen/Cargo.toml b/sea-orm-codegen/Cargo.toml index de38c992..f871fd5b 100644 --- a/sea-orm-codegen/Cargo.toml +++ b/sea-orm-codegen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sea-orm-codegen" -version = "0.2.0" +version = "0.2.2" authors = ["Billy Chan "] edition = "2018" description = "Code Generator for SeaORM" diff --git a/sea-orm-codegen/src/entity/column.rs b/sea-orm-codegen/src/entity/column.rs index dfec4b8e..2bab8766 100644 --- a/sea-orm-codegen/src/entity/column.rs +++ b/sea-orm-codegen/src/entity/column.rs @@ -38,6 +38,7 @@ impl Column { ColumnType::Double(_) => "f64", ColumnType::Json | ColumnType::JsonBinary => "Json", ColumnType::DateTime(_) | ColumnType::Timestamp(_) => "DateTime", + ColumnType::TimestampWithTimeZone(_) => "DateTimeWithTimeZone", ColumnType::Decimal(_) | ColumnType::Money(_) => "Decimal", ColumnType::Uuid => "Uuid", ColumnType::Binary(_) => "Vec", diff --git a/sea-orm-macros/Cargo.toml b/sea-orm-macros/Cargo.toml index 27ea856e..2e869316 100644 --- a/sea-orm-macros/Cargo.toml +++ b/sea-orm-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sea-orm-macros" -version = "0.2.0" +version = "0.2.2" authors = [ "Billy Chan " ] edition = "2018" description = "Derive macros for SeaORM" diff --git a/sea-orm-macros/src/derives/entity_model.rs b/sea-orm-macros/src/derives/entity_model.rs index 768d3b7c..f0772763 100644 --- a/sea-orm-macros/src/derives/entity_model.rs +++ b/sea-orm-macros/src/derives/entity_model.rs @@ -165,19 +165,22 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res "String" | "&str" => quote! { String(None) }, "u8" | "i8" => quote! { TinyInteger }, "u16" | "i16" => quote! { SmallInteger }, - "u32" | "u64" | "i32" | "i64" => quote! { Integer }, - "u128" | "i128" => quote! { BigInteger }, + "u32" | "i32" => quote! { Integer }, + "u64" | "i64" => quote! { BigInteger }, "f32" => quote! { Float }, "f64" => quote! { Double }, "bool" => quote! { Boolean }, "NaiveDate" => quote! { Date }, "NaiveTime" => quote! { Time }, - "DateTime" | "NaiveDateTime" | "DateTimeWithTimeZone" => { + "DateTime" | "NaiveDateTime" => { quote! { DateTime } } + "DateTimeWithTimeZone" => { + quote! { TimestampWithTimeZone } + } "Uuid" => quote! { Uuid }, "Json" => quote! { Json }, - "Decimal" => quote! { Decimal }, + "Decimal" => quote! { Decimal(None) }, "Vec" => quote! { Binary }, _ => { return Err(Error::new( diff --git a/src/database/connection.rs b/src/database/connection.rs index 6a39b240..995dde9d 100644 --- a/src/database/connection.rs +++ b/src/database/connection.rs @@ -1,6 +1,7 @@ use crate::{error::*, ExecResult, QueryResult, Statement, StatementBuilder}; use sea_query::{MysqlQueryBuilder, PostgresQueryBuilder, QueryBuilder, SqliteQueryBuilder}; +#[cfg_attr(not(feature = "mock"), derive(Clone))] pub enum DatabaseConnection { #[cfg(feature = "sqlx-mysql")] SqlxMySqlPoolConnection(crate::SqlxMySqlPoolConnection), @@ -143,3 +144,15 @@ impl DbBackend { } } } + +#[cfg(test)] +mod tests { + use crate::DatabaseConnection; + + #[test] + fn assert_database_connection_traits() { + fn assert_send_sync() {} + + assert_send_sync::(); + } +} diff --git a/src/driver/sqlx_mysql.rs b/src/driver/sqlx_mysql.rs index e91df037..be590b6e 100644 --- a/src/driver/sqlx_mysql.rs +++ b/src/driver/sqlx_mysql.rs @@ -13,7 +13,7 @@ use super::sqlx_common::*; #[derive(Debug)] pub struct SqlxMySqlConnector; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct SqlxMySqlPoolConnection { pool: MySqlPool, } diff --git a/src/driver/sqlx_postgres.rs b/src/driver/sqlx_postgres.rs index 086dc995..e7b9032a 100644 --- a/src/driver/sqlx_postgres.rs +++ b/src/driver/sqlx_postgres.rs @@ -13,7 +13,7 @@ use super::sqlx_common::*; #[derive(Debug)] pub struct SqlxPostgresConnector; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct SqlxPostgresPoolConnection { pool: PgPool, } diff --git a/src/driver/sqlx_sqlite.rs b/src/driver/sqlx_sqlite.rs index 5fa4bdcd..bd6f0399 100644 --- a/src/driver/sqlx_sqlite.rs +++ b/src/driver/sqlx_sqlite.rs @@ -13,7 +13,7 @@ use super::sqlx_common::*; #[derive(Debug)] pub struct SqlxSqliteConnector; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct SqlxSqlitePoolConnection { pool: SqlitePool, } diff --git a/src/entity/base_entity.rs b/src/entity/base_entity.rs index e09fa0a8..6f770162 100644 --- a/src/entity/base_entity.rs +++ b/src/entity/base_entity.rs @@ -541,3 +541,58 @@ pub trait EntityTrait: EntityName { Delete::many(Self::default()) } } + +#[cfg(test)] +mod tests { + #[test] + #[cfg(feature = "macros")] + fn entity_model_1() { + use crate::entity::*; + + mod hello { + use crate as sea_orm; + use crate::entity::prelude::*; + + #[derive(Clone, Debug, PartialEq, DeriveEntityModel)] + #[sea_orm(table_name = "hello")] + pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + } + + #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] + pub enum Relation {} + + impl ActiveModelBehavior for ActiveModel {} + } + + assert_eq!(hello::Entity.table_name(), "hello"); + assert_eq!(hello::Entity.schema_name(), None); + } + + #[test] + #[cfg(feature = "macros")] + fn entity_model_2() { + use crate::entity::*; + + mod hello { + use crate as sea_orm; + use crate::entity::prelude::*; + + #[derive(Clone, Debug, PartialEq, DeriveEntityModel)] + #[sea_orm(table_name = "hello", schema_name = "world")] + pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + } + + #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] + pub enum Relation {} + + impl ActiveModelBehavior for ActiveModel {} + } + + assert_eq!(hello::Entity.table_name(), "hello"); + assert_eq!(hello::Entity.schema_name(), Some("world")); + } +} diff --git a/src/entity/column.rs b/src/entity/column.rs index 6e871f4d..26d8ec0e 100644 --- a/src/entity/column.rs +++ b/src/entity/column.rs @@ -24,6 +24,7 @@ pub enum ColumnType { Decimal(Option<(u32, u32)>), DateTime, Timestamp, + TimestampWithTimeZone, Time, Date, Binary, @@ -278,6 +279,7 @@ impl From for sea_query::ColumnType { ColumnType::Decimal(s) => sea_query::ColumnType::Decimal(s), ColumnType::DateTime => sea_query::ColumnType::DateTime(None), ColumnType::Timestamp => sea_query::ColumnType::Timestamp(None), + ColumnType::TimestampWithTimeZone => sea_query::ColumnType::TimestampWithTimeZone(None), ColumnType::Time => sea_query::ColumnType::Time(None), ColumnType::Date => sea_query::ColumnType::Date, ColumnType::Binary => sea_query::ColumnType::Binary(None), @@ -309,6 +311,7 @@ impl From for ColumnType { sea_query::ColumnType::Decimal(s) => Self::Decimal(s), sea_query::ColumnType::DateTime(_) => Self::DateTime, sea_query::ColumnType::Timestamp(_) => Self::Timestamp, + sea_query::ColumnType::TimestampWithTimeZone(_) => Self::TimestampWithTimeZone, sea_query::ColumnType::Time(_) => Self::Time, sea_query::ColumnType::Date => Self::Date, sea_query::ColumnType::Binary(_) => Self::Binary, diff --git a/src/executor/query.rs b/src/executor/query.rs index ba8c8169..ae09f97c 100644 --- a/src/executor/query.rs +++ b/src/executor/query.rs @@ -314,29 +314,50 @@ where } } -impl TryGetableMany for (T, T) +impl TryGetableMany for (A, B) where - T: TryGetable, + A: TryGetable, + B: TryGetable, { fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result { try_get_many_with_slice_len_of(2, cols)?; Ok(( - T::try_get(res, pre, &cols[0])?, - T::try_get(res, pre, &cols[1])?, + A::try_get(res, pre, &cols[0])?, + B::try_get(res, pre, &cols[1])?, )) } } -impl TryGetableMany for (T, T, T) +impl TryGetableMany for (A, B, C) where - T: TryGetable, + A: TryGetable, + B: TryGetable, + C: TryGetable, { fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result { try_get_many_with_slice_len_of(3, cols)?; Ok(( - T::try_get(res, pre, &cols[0])?, - T::try_get(res, pre, &cols[1])?, - T::try_get(res, pre, &cols[2])?, + A::try_get(res, pre, &cols[0])?, + B::try_get(res, pre, &cols[1])?, + C::try_get(res, pre, &cols[2])?, + )) + } +} + +impl TryGetableMany for (A, B, C, D) +where + A: TryGetable, + B: TryGetable, + C: TryGetable, + D: TryGetable, +{ + fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result { + try_get_many_with_slice_len_of(4, cols)?; + Ok(( + A::try_get(res, pre, &cols[0])?, + B::try_get(res, pre, &cols[1])?, + C::try_get(res, pre, &cols[2])?, + D::try_get(res, pre, &cols[3])?, )) } } @@ -370,15 +391,27 @@ macro_rules! try_from_u64_err { } } }; -} -macro_rules! try_from_u64_tuple { - ( $type: ty ) => { - try_from_u64_err!(($type, $type)); - try_from_u64_err!(($type, $type, $type)); + ( $($gen_type: ident),* ) => { + impl<$( $gen_type, )*> TryFromU64 for ($( $gen_type, )*) + where + $( $gen_type: TryFromU64, )* + { + fn try_from_u64(_: u64) -> Result { + Err(DbErr::Exec(format!( + "{} cannot be converted from u64", + stringify!(($($gen_type,)*)) + ))) + } + } }; } +// impl TryFromU64 for tuples with generic types +try_from_u64_err!(A, B); +try_from_u64_err!(A, B, C); +try_from_u64_err!(A, B, C, D); + macro_rules! try_from_u64_numeric { ( $type: ty ) => { impl TryFromU64 for $type { @@ -393,7 +426,6 @@ macro_rules! try_from_u64_numeric { }) } } - try_from_u64_tuple!($type); }; } @@ -413,19 +445,10 @@ macro_rules! try_from_u64_string { Ok(n.to_string()) } } - try_from_u64_tuple!($type); }; } try_from_u64_string!(String); -macro_rules! try_from_u64_dummy { - ( $type: ty ) => { - try_from_u64_err!($type); - try_from_u64_err!(($type, $type)); - try_from_u64_err!(($type, $type, $type)); - }; -} - #[cfg(feature = "with-uuid")] -try_from_u64_dummy!(uuid::Uuid); +try_from_u64_err!(uuid::Uuid); diff --git a/src/schema/entity.rs b/src/schema/entity.rs index 7582aaee..a95b7047 100644 --- a/src/schema/entity.rs +++ b/src/schema/entity.rs @@ -116,7 +116,7 @@ where ); } - stmt.table(entity).if_not_exists().take() + stmt.table(entity).take() } #[cfg(test)] @@ -130,7 +130,6 @@ mod tests { Schema::create_table_from_entity(CakeFillingPrice).to_string(MysqlQueryBuilder), Table::create() .table(CakeFillingPrice) - .if_not_exists() .col( ColumnDef::new(cake_filling_price::Column::CakeId) .integer() diff --git a/tests/basic.rs b/tests/basic.rs index d617ba17..a0763d45 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -2,22 +2,21 @@ pub mod common; pub use sea_orm::{entity::*, error::*, sea_query, tests_cfg::*, Database, DbConn}; -// DATABASE_URL="sqlite::memory:" cargo test --features sqlx-sqlite,runtime-async-std-native-tls --test basic +// cargo test --features sqlx-sqlite,runtime-async-std-native-tls --test basic #[sea_orm_macros::test] #[cfg(feature = "sqlx-sqlite")] -async fn main() { - use std::env; - let base_url = env::var("DATABASE_URL").unwrap_or_else(|_| "sqlite::memory:".to_owned()); +async fn main() -> Result<(), DbErr> { + let base_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| "sqlite::memory:".to_owned()); - let db: DbConn = Database::connect(&base_url).await.unwrap(); + let db: DbConn = Database::connect(&base_url).await?; + setup_schema(&db).await?; + crud_cake(&db).await?; - setup_schema(&db).await; - - crud_cake(&db).await.unwrap(); + Ok(()) } #[cfg(feature = "sqlx-sqlite")] -async fn setup_schema(db: &DbConn) { +async fn setup_schema(db: &DbConn) -> Result<(), DbErr> { use sea_query::*; let stmt = sea_query::Table::create() @@ -33,8 +32,10 @@ async fn setup_schema(db: &DbConn) { .to_owned(); let builder = db.get_database_backend(); - let result = db.execute(builder.build(&stmt)).await; + let result = db.execute(builder.build(&stmt)).await?; println!("Create table cake: {:?}", result); + + Ok(()) } #[cfg(feature = "sqlx-sqlite")] diff --git a/tests/common/bakery_chain/Readme.md b/tests/common/bakery_chain/Readme.md index 1b5bf076..91d8006a 100644 --- a/tests/common/bakery_chain/Readme.md +++ b/tests/common/bakery_chain/Readme.md @@ -1,3 +1,5 @@ # Schema for SeaORM test suite +![Entity Relation Diagram](bakery_chain_erd.png) + ERD generated by DataGrip. \ No newline at end of file diff --git a/tests/common/bakery_chain/applog.rs b/tests/common/bakery_chain/applog.rs new file mode 100644 index 00000000..03b06d61 --- /dev/null +++ b/tests/common/bakery_chain/applog.rs @@ -0,0 +1,15 @@ +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "applog")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub json: Json, + pub created_at: DateTimeWithTimeZone, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/tests/common/bakery_chain/metadata.rs b/tests/common/bakery_chain/metadata.rs index 69579492..95a7a48b 100644 --- a/tests/common/bakery_chain/metadata.rs +++ b/tests/common/bakery_chain/metadata.rs @@ -1,5 +1,4 @@ use sea_orm::entity::prelude::*; -use uuid::Uuid; #[derive(Clone, Debug, PartialEq, DeriveEntityModel)] #[sea_orm(table_name = "metadata")] @@ -11,13 +10,7 @@ pub struct Model { pub bytes: Vec, } -#[derive(Copy, Clone, Debug, EnumIter)] +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation {} -impl RelationTrait for Relation { - fn def(&self) -> RelationDef { - unreachable!() - } -} - impl ActiveModelBehavior for ActiveModel {} diff --git a/tests/common/bakery_chain/mod.rs b/tests/common/bakery_chain/mod.rs index 3282766d..36f2a16e 100644 --- a/tests/common/bakery_chain/mod.rs +++ b/tests/common/bakery_chain/mod.rs @@ -1,3 +1,4 @@ +pub mod applog; pub mod baker; pub mod bakery; pub mod cake; @@ -7,6 +8,7 @@ pub mod lineitem; pub mod metadata; pub mod order; +pub use super::applog::Entity as Applog; pub use super::baker::Entity as Baker; pub use super::bakery::Entity as Bakery; pub use super::cake::Entity as Cake; diff --git a/tests/common/setup/mod.rs b/tests/common/setup/mod.rs index 74e35b45..d982b2b7 100644 --- a/tests/common/setup/mod.rs +++ b/tests/common/setup/mod.rs @@ -53,6 +53,7 @@ pub async fn setup(base_url: &str, db_name: &str) -> DatabaseConnection { schema::create_cakes_bakers_table(&db).await.unwrap(); schema::create_lineitem_table(&db).await.unwrap(); schema::create_metadata_table(&db).await.unwrap(); + schema::create_log_table(&db).await.unwrap(); db } diff --git a/tests/common/setup/schema.rs b/tests/common/setup/schema.rs index 78947c36..64f31dfe 100644 --- a/tests/common/setup/schema.rs +++ b/tests/common/setup/schema.rs @@ -1,18 +1,30 @@ pub use super::super::bakery_chain::*; use pretty_assertions::assert_eq; -use sea_orm::{error::*, sea_query, DbConn, EntityTrait, ExecResult, Schema}; -use sea_query::{ColumnDef, ForeignKey, ForeignKeyAction, Index, Table, TableCreateStatement}; +use sea_orm::{error::*, sea_query, DbBackend, DbConn, EntityTrait, ExecResult, Schema}; +use sea_query::{ + Alias, ColumnDef, ForeignKey, ForeignKeyAction, Index, Table, TableCreateStatement, +}; async fn create_table( db: &DbConn, - stmt: &TableCreateStatement, + create: &TableCreateStatement, entity: E, ) -> Result where E: EntityTrait, { let builder = db.get_database_backend(); - let stmt = builder.build(stmt); + if builder != DbBackend::Sqlite { + let stmt = builder.build( + Table::drop() + .table(Alias::new(create.get_table_name().unwrap().as_ref())) + .if_exists() + .cascade(), + ); + db.execute(stmt).await?; + } + + let stmt = builder.build(create); assert_eq!( builder.build(&Schema::create_table_from_entity(entity)), stmt @@ -23,7 +35,6 @@ where pub async fn create_bakery_table(db: &DbConn) -> Result { let stmt = Table::create() .table(bakery::Entity) - .if_not_exists() .col( ColumnDef::new(bakery::Column::Id) .integer() @@ -45,7 +56,6 @@ pub async fn create_bakery_table(db: &DbConn) -> Result { pub async fn create_baker_table(db: &DbConn) -> Result { let stmt = Table::create() .table(baker::Entity) - .if_not_exists() .col( ColumnDef::new(baker::Column::Id) .integer() @@ -76,7 +86,6 @@ pub async fn create_baker_table(db: &DbConn) -> Result { pub async fn create_customer_table(db: &DbConn) -> Result { let stmt = Table::create() .table(customer::Entity) - .if_not_exists() .col( ColumnDef::new(customer::Column::Id) .integer() @@ -94,7 +103,6 @@ pub async fn create_customer_table(db: &DbConn) -> Result { pub async fn create_order_table(db: &DbConn) -> Result { let stmt = Table::create() .table(order::Entity) - .if_not_exists() .col( ColumnDef::new(order::Column::Id) .integer() @@ -142,7 +150,6 @@ pub async fn create_order_table(db: &DbConn) -> Result { pub async fn create_lineitem_table(db: &DbConn) -> Result { let stmt = Table::create() .table(lineitem::Entity) - .if_not_exists() .col( ColumnDef::new(lineitem::Column::Id) .integer() @@ -194,7 +201,6 @@ pub async fn create_lineitem_table(db: &DbConn) -> Result { pub async fn create_cakes_bakers_table(db: &DbConn) -> Result { let stmt = Table::create() .table(cakes_bakers::Entity) - .if_not_exists() .col( ColumnDef::new(cakes_bakers::Column::CakeId) .integer() @@ -235,7 +241,6 @@ pub async fn create_cakes_bakers_table(db: &DbConn) -> Result pub async fn create_cake_table(db: &DbConn) -> Result { let stmt = Table::create() .table(cake::Entity) - .if_not_exists() .col( ColumnDef::new(cake::Column::Id) .integer() @@ -272,7 +277,6 @@ pub async fn create_cake_table(db: &DbConn) -> Result { pub async fn create_metadata_table(db: &DbConn) -> Result { let stmt = sea_query::Table::create() .table(metadata::Entity) - .if_not_exists() .col( ColumnDef::new(metadata::Column::Uuid) .uuid() @@ -286,3 +290,24 @@ pub async fn create_metadata_table(db: &DbConn) -> Result { create_table(db, &stmt, Metadata).await } + +pub async fn create_log_table(db: &DbConn) -> Result { + let stmt = sea_query::Table::create() + .table(applog::Entity) + .col( + ColumnDef::new(applog::Column::Id) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col(ColumnDef::new(applog::Column::Json).json().not_null()) + .col( + ColumnDef::new(applog::Column::CreatedAt) + .timestamp_with_time_zone() + .not_null(), + ) + .to_owned(); + + create_table(db, &stmt, Applog).await +} diff --git a/tests/timestamp_tests.rs b/tests/timestamp_tests.rs new file mode 100644 index 00000000..1897323c --- /dev/null +++ b/tests/timestamp_tests.rs @@ -0,0 +1,31 @@ +pub mod common; + +pub use common::{bakery_chain::*, setup::*, TestContext}; +use sea_orm::{entity::prelude::*, DatabaseConnection, IntoActiveModel}; + +#[sea_orm_macros::test] +#[cfg(feature = "sqlx-postgres")] +async fn main() -> Result<(), DbErr> { + let ctx = TestContext::new("bakery_chain_schema_timestamp_tests").await; + create_applog(&ctx.db).await?; + ctx.delete().await; + + Ok(()) +} + +pub async fn create_applog(db: &DatabaseConnection) -> Result<(), DbErr> { + let log = applog::Model { + id: 1, + json: Json::String("HI".to_owned()), + created_at: "2021-09-17T17:50:20+08:00".parse().unwrap(), + }; + + let res = Applog::insert(log.clone().into_active_model()) + .exec(db) + .await?; + + assert_eq!(log.id.clone(), res.last_insert_id); + assert_eq!(Applog::find().one(db).await?, Some(log.clone())); + + Ok(()) +} diff --git a/tests/primary_key_tests.rs b/tests/uuid_tests.rs similarity index 91% rename from tests/primary_key_tests.rs rename to tests/uuid_tests.rs index 06b2a13a..e58daca4 100644 --- a/tests/primary_key_tests.rs +++ b/tests/uuid_tests.rs @@ -2,7 +2,6 @@ pub mod common; pub use common::{bakery_chain::*, setup::*, TestContext}; use sea_orm::{entity::prelude::*, DatabaseConnection, IntoActiveModel}; -use uuid::Uuid; #[sea_orm_macros::test] #[cfg(any( @@ -11,10 +10,8 @@ use uuid::Uuid; feature = "sqlx-postgres" ))] async fn main() -> Result<(), DbErr> { - let ctx = TestContext::new("bakery_chain_schema_primary_key_tests").await; - + let ctx = TestContext::new("bakery_chain_schema_uuid_tests").await; create_metadata(&ctx.db).await?; - ctx.delete().await; Ok(())