diff --git a/tests/common/bakery_chain/baker.rs b/tests/common/bakery_chain/baker.rs new file mode 100644 index 00000000..b359e7ef --- /dev/null +++ b/tests/common/bakery_chain/baker.rs @@ -0,0 +1,81 @@ +use sea_orm::entity::prelude::*; + +#[derive(Copy, Clone, Default, Debug, DeriveEntity)] +pub struct Entity; + +impl EntityName for Entity { + fn table_name(&self) -> &str { + "baker" + } +} + +#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)] +pub struct Model { + pub id: i32, + pub name: String, + pub bakery_id: Option, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] +pub enum Column { + Id, + Name, + BakeryId, +} + +#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] +pub enum PrimaryKey { + Id, +} + +impl PrimaryKeyTrait for PrimaryKey { + fn auto_increment() -> bool { + true + } +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation { + Bakery, +} + +impl ColumnTrait for Column { + type EntityName = Entity; + + fn def(&self) -> ColumnDef { + match self { + Self::Id => ColumnType::Integer.def(), + Self::Name => ColumnType::String(None).def(), + Self::BakeryId => ColumnType::Integer.def(), + } + } +} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + match self { + Self::Bakery => Entity::belongs_to(super::bakery::Entity) + .from(Column::BakeryId) + .to(super::bakery::Column::Id) + .into(), + } + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Bakery.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + super::cakes_bakers::Relation::Cake.def() + } + + fn via() -> Option { + Some(super::cakes_bakers::Relation::Baker.def().rev()) + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/tests/common/bakery_chain/bakery.rs b/tests/common/bakery_chain/bakery.rs new file mode 100644 index 00000000..61803329 --- /dev/null +++ b/tests/common/bakery_chain/bakery.rs @@ -0,0 +1,84 @@ +use sea_orm::entity::prelude::*; + +#[derive(Copy, Clone, Default, Debug, DeriveEntity)] +pub struct Entity; + +impl EntityName for Entity { + fn table_name(&self) -> &str { + "bakery" + } +} + +#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)] +pub struct Model { + pub id: i32, + pub name: String, + pub profit_margin: f64, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] +pub enum Column { + Id, + Name, + ProfitMargin, +} + +#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] +pub enum PrimaryKey { + Id, +} + +impl PrimaryKeyTrait for PrimaryKey { + fn auto_increment() -> bool { + true + } +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation { + Baker, + Order, + Cake, +} + +impl ColumnTrait for Column { + type EntityName = Entity; + + fn def(&self) -> ColumnDef { + match self { + Self::Id => ColumnType::Integer.def(), + Self::Name => ColumnType::String(None).def(), + Self::ProfitMargin => ColumnType::Float.def(), + } + } +} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + match self { + Self::Baker => Entity::has_many(super::baker::Entity).into(), + Self::Order => Entity::has_many(super::order::Entity).into(), + Self::Cake => Entity::has_many(super::cake::Entity).into(), + } + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Baker.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Order.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Cake.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/tests/common/bakery_chain/bakery_chain_erd.drawio b/tests/common/bakery_chain/bakery_chain_erd.drawio new file mode 100644 index 00000000..10084d0a --- /dev/null +++ b/tests/common/bakery_chain/bakery_chain_erd.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/tests/common/bakery_chain/bakery_chain_erd.jpg b/tests/common/bakery_chain/bakery_chain_erd.jpg new file mode 100644 index 00000000..f44da9aa Binary files /dev/null and b/tests/common/bakery_chain/bakery_chain_erd.jpg differ diff --git a/tests/common/bakery_chain/cake.rs b/tests/common/bakery_chain/cake.rs new file mode 100644 index 00000000..1e134de5 --- /dev/null +++ b/tests/common/bakery_chain/cake.rs @@ -0,0 +1,96 @@ +use rust_decimal::prelude::*; +use sea_orm::entity::prelude::*; + +#[derive(Copy, Clone, Default, Debug, DeriveEntity)] +pub struct Entity; + +impl EntityName for Entity { + fn table_name(&self) -> &str { + "cake" + } +} + +#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)] +pub struct Model { + pub id: i32, + pub name: String, + pub price: Decimal, + pub bakery_id: Option, + pub gluten_free: bool, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] +pub enum Column { + Id, + Name, + Price, + BakeryId, + GlutenFree, +} + +#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] +pub enum PrimaryKey { + Id, +} + +impl PrimaryKeyTrait for PrimaryKey { + fn auto_increment() -> bool { + true + } +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation { + Bakery, + Lineitem, +} + +impl ColumnTrait for Column { + type EntityName = Entity; + + fn def(&self) -> ColumnDef { + match self { + Self::Id => ColumnType::Integer.def(), + Self::Name => ColumnType::String(None).def(), + Self::Price => ColumnType::Decimal(Some((19, 4))).def(), + Self::BakeryId => ColumnType::Integer.def(), + Self::GlutenFree => ColumnType::Boolean.def(), + } + } +} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + match self { + Self::Bakery => Entity::belongs_to(super::bakery::Entity) + .from(Column::BakeryId) + .to(super::bakery::Column::Id) + .into(), + Self::Lineitem => Entity::has_many(super::lineitem::Entity).into(), + } + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Bakery.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + super::cakes_bakers::Relation::Baker.def() + } + + fn via() -> Option { + Some(super::cakes_bakers::Relation::Cake.def().rev()) + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Lineitem.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/tests/common/bakery_chain/cakes_bakers.rs b/tests/common/bakery_chain/cakes_bakers.rs new file mode 100644 index 00000000..8106bbdf --- /dev/null +++ b/tests/common/bakery_chain/cakes_bakers.rs @@ -0,0 +1,68 @@ +use sea_orm::entity::prelude::*; + +#[derive(Copy, Clone, Default, Debug, DeriveEntity)] +pub struct Entity; + +impl EntityName for Entity { + fn table_name(&self) -> &str { + "cakes_bakers" + } +} + +#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)] +pub struct Model { + pub cake_id: i32, + pub baker_id: i32, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] +pub enum Column { + CakeId, + BakerId, +} + +#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] +pub enum PrimaryKey { + CakeId, + BakerId, +} + +impl PrimaryKeyTrait for PrimaryKey { + fn auto_increment() -> bool { + false + } +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation { + Cake, + Baker, +} + +impl ColumnTrait for Column { + type EntityName = Entity; + + fn def(&self) -> ColumnDef { + match self { + Self::CakeId => ColumnType::Integer.def(), + Self::BakerId => ColumnType::Integer.def(), + } + } +} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + match self { + Self::Cake => Entity::belongs_to(super::cake::Entity) + .from(Column::CakeId) + .to(super::cake::Column::Id) + .into(), + Self::Baker => Entity::belongs_to(super::baker::Entity) + .from(Column::BakerId) + .to(super::baker::Column::Id) + .into(), + } + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/tests/common/bakery_chain/customer.rs b/tests/common/bakery_chain/customer.rs new file mode 100644 index 00000000..a7464082 --- /dev/null +++ b/tests/common/bakery_chain/customer.rs @@ -0,0 +1,68 @@ +use sea_orm::entity::prelude::*; + +#[derive(Copy, Clone, Default, Debug, DeriveEntity)] +pub struct Entity; + +impl EntityName for Entity { + fn table_name(&self) -> &str { + "customer" + } +} + +#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)] +pub struct Model { + pub id: i32, + pub name: String, + pub notes: String, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] +pub enum Column { + Id, + Name, + Notes, +} + +#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] +pub enum PrimaryKey { + Id, +} + +impl PrimaryKeyTrait for PrimaryKey { + fn auto_increment() -> bool { + true + } +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation { + Order, +} + +impl ColumnTrait for Column { + type EntityName = Entity; + + fn def(&self) -> ColumnDef { + match self { + Self::Id => ColumnType::Integer.def(), + Self::Name => ColumnType::String(None).def(), + Self::Notes => ColumnType::Text.def(), + } + } +} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + match self { + Self::Order => Entity::has_many(super::order::Entity).into(), + } + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Order.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/tests/common/bakery_chain/lineitem.rs b/tests/common/bakery_chain/lineitem.rs new file mode 100644 index 00000000..94b15cac --- /dev/null +++ b/tests/common/bakery_chain/lineitem.rs @@ -0,0 +1,89 @@ +use rust_decimal::prelude::*; +use sea_orm::entity::prelude::*; + +#[derive(Copy, Clone, Default, Debug, DeriveEntity)] +pub struct Entity; + +impl EntityName for Entity { + fn table_name(&self) -> &str { + "lineitem" + } +} + +#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)] +pub struct Model { + pub id: i32, + pub price: Decimal, + pub quantity: i32, + pub order_id: Option, + pub cake_id: Option, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] +pub enum Column { + Id, + Price, + Quantity, + OrderId, + CakeId, +} + +#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] +pub enum PrimaryKey { + Id, +} + +impl PrimaryKeyTrait for PrimaryKey { + fn auto_increment() -> bool { + true + } +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation { + Order, + Cake, +} + +impl ColumnTrait for Column { + type EntityName = Entity; + + fn def(&self) -> ColumnDef { + match self { + Self::Id => ColumnType::Integer.def(), + Self::Price => ColumnType::Money(Some((19, 4))).def(), + Self::Quantity => ColumnType::Integer.def(), + Self::OrderId => ColumnType::Integer.def(), + Self::CakeId => ColumnType::Integer.def(), + } + } +} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + match self { + Self::Order => Entity::belongs_to(super::order::Entity) + .from(Column::OrderId) + .to(super::order::Column::Id) + .into(), + Self::Cake => Entity::belongs_to(super::cake::Entity) + .from(Column::CakeId) + .to(super::cake::Column::Id) + .into(), + } + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Order.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Cake.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/tests/common/bakery_chain/mod.rs b/tests/common/bakery_chain/mod.rs new file mode 100644 index 00000000..89028aab --- /dev/null +++ b/tests/common/bakery_chain/mod.rs @@ -0,0 +1,15 @@ +pub mod baker; +pub mod bakery; +pub mod cake; +pub mod cakes_bakers; +pub mod customer; +pub mod lineitem; +pub mod order; + +pub use super::baker::Entity as Baker; +pub use super::bakery::Entity as Bakery; +pub use super::cake::Entity as Cake; +pub use super::cakes_bakers::Entity as CakesBakers; +pub use super::customer::Entity as Customer; +pub use super::lineitem::Entity as Lineitem; +pub use super::order::Entity as Order; diff --git a/tests/common/bakery_chain/order.rs b/tests/common/bakery_chain/order.rs new file mode 100644 index 00000000..de38df60 --- /dev/null +++ b/tests/common/bakery_chain/order.rs @@ -0,0 +1,97 @@ +use rust_decimal::prelude::*; +use sea_orm::entity::prelude::*; + +#[derive(Copy, Clone, Default, Debug, DeriveEntity)] +pub struct Entity; + +impl EntityName for Entity { + fn table_name(&self) -> &str { + "order" + } +} + +#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)] +pub struct Model { + pub id: i32, + pub total: Decimal, + pub bakery_id: Option, + pub customer_id: Option, + pub placed_at: String, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] +pub enum Column { + Id, + Total, + BakeryId, + CustomerId, + PlacedAt, +} + +#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] +pub enum PrimaryKey { + Id, +} + +impl PrimaryKeyTrait for PrimaryKey { + fn auto_increment() -> bool { + true + } +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation { + Bakery, + Customer, + Lineitem, +} + +impl ColumnTrait for Column { + type EntityName = Entity; + + fn def(&self) -> ColumnDef { + match self { + Self::Id => ColumnType::Integer.def(), + Self::Total => ColumnType::Decimal(Some((19, 4))).def(), + Self::BakeryId => ColumnType::Integer.def(), + Self::CustomerId => ColumnType::Integer.def(), + Self::PlacedAt => ColumnType::DateTime.def(), + } + } +} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + match self { + Self::Bakery => Entity::belongs_to(super::bakery::Entity) + .from(Column::BakeryId) + .to(super::bakery::Column::Id) + .into(), + Self::Customer => Entity::belongs_to(super::customer::Entity) + .from(Column::CustomerId) + .to(super::customer::Column::Id) + .into(), + Self::Lineitem => Entity::has_many(super::lineitem::Entity).into(), + } + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Bakery.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Customer.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Lineitem.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/tests/common/mod.rs b/tests/common/mod.rs new file mode 100644 index 00000000..c891b51a --- /dev/null +++ b/tests/common/mod.rs @@ -0,0 +1,50 @@ +pub mod schema; +use sea_orm::{Database, DatabaseConnection}; +pub mod bakery_chain; +pub use bakery_chain::*; + +macro_rules! function { + () => {{ + fn f() {} + fn type_name_of(_: T) -> &'static str { + std::any::type_name::() + } + let name = type_name_of(f); + &name[..name.len() - 3] + }}; +} + +pub struct TestContext { + base_url: String, + db_name: String, + pub db_conn: DatabaseConnection, +} + +impl TestContext { + pub async fn new(base_url: &str, db_name: &str) -> Self { + let db_conn = Database::connect("sqlite::memory:").await.unwrap(); + Self::setup_schema(&db_conn).await; + + Self { + base_url: base_url.to_string(), + db_name: db_name.to_string(), + db_conn, + } + } + + async fn setup_schema(db: &DatabaseConnection) { + assert!(schema::create_bakery_table(db).await.is_ok()); + assert!(schema::create_baker_table(db).await.is_ok()); + assert!(schema::create_customer_table(db).await.is_ok()); + assert!(schema::create_order_table(db).await.is_ok()); + assert!(schema::create_lineitem_table(db).await.is_ok()); + assert!(schema::create_cake_table(db).await.is_ok()); + assert!(schema::create_cakes_bakers_table(db).await.is_ok()); + } +} + +impl Drop for TestContext { + fn drop(&mut self) { + println!("dropping context"); + } +} diff --git a/tests/common/schema.rs b/tests/common/schema.rs new file mode 100644 index 00000000..6ebcc381 --- /dev/null +++ b/tests/common/schema.rs @@ -0,0 +1,211 @@ +use sea_orm::{error::*, sea_query, DbConn, ExecResult}; +use sea_query::{ColumnDef, ForeignKey, ForeignKeyAction, Index, TableCreateStatement}; + +pub use super::bakery_chain::*; + +async fn create_table(db: &DbConn, stmt: &TableCreateStatement) -> Result { + let builder = db.get_schema_builder_backend(); + db.execute(builder.build(stmt)).await +} + +pub async fn create_bakery_table(db: &DbConn) -> Result { + let stmt = sea_query::Table::create() + .table(bakery::Entity) + .if_not_exists() + .col( + ColumnDef::new(bakery::Column::Id) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col(ColumnDef::new(bakery::Column::Name).string()) + .col(ColumnDef::new(bakery::Column::ProfitMargin).float()) + .to_owned(); + + create_table(db, &stmt).await +} + +pub async fn create_baker_table(db: &DbConn) -> Result { + let stmt = sea_query::Table::create() + .table(baker::Entity) + .if_not_exists() + .col( + ColumnDef::new(baker::Column::Id) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col(ColumnDef::new(baker::Column::Name).string()) + .col(ColumnDef::new(baker::Column::BakeryId).integer()) + .foreign_key( + ForeignKey::create() + .name("FK_baker_bakery") + .from(baker::Entity, baker::Column::BakeryId) + .to(bakery::Entity, bakery::Column::Id) + .on_delete(ForeignKeyAction::Cascade) + .on_update(ForeignKeyAction::Cascade), + ) + .to_owned(); + + create_table(db, &stmt).await +} + +pub async fn create_customer_table(db: &DbConn) -> Result { + let stmt = sea_query::Table::create() + .table(customer::Entity) + .if_not_exists() + .col( + ColumnDef::new(customer::Column::Id) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col(ColumnDef::new(customer::Column::Name).string()) + .col(ColumnDef::new(customer::Column::Notes).text()) + .to_owned(); + + create_table(db, &stmt).await +} + +pub async fn create_order_table(db: &DbConn) -> Result { + let stmt = sea_query::Table::create() + .table(order::Entity) + .if_not_exists() + .col( + ColumnDef::new(order::Column::Id) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col(ColumnDef::new(order::Column::Total).float()) + .col(ColumnDef::new(order::Column::BakeryId).integer().not_null()) + .col( + ColumnDef::new(order::Column::CustomerId) + .integer() + .not_null(), + ) + .col( + ColumnDef::new(order::Column::PlacedAt) + .date_time() + .not_null(), + ) + .foreign_key( + ForeignKey::create() + .name("FK_order_bakery") + .from(order::Entity, order::Column::BakeryId) + .to(bakery::Entity, bakery::Column::Id) + .on_delete(ForeignKeyAction::Cascade) + .on_update(ForeignKeyAction::Cascade), + ) + .foreign_key( + ForeignKey::create() + .name("FK_order_customer") + .from(order::Entity, order::Column::CustomerId) + .to(customer::Entity, customer::Column::Id) + .on_delete(ForeignKeyAction::Cascade) + .on_update(ForeignKeyAction::Cascade), + ) + .to_owned(); + + create_table(db, &stmt).await +} + +pub async fn create_lineitem_table(db: &DbConn) -> Result { + let stmt = sea_query::Table::create() + .table(lineitem::Entity) + .if_not_exists() + .col( + ColumnDef::new(lineitem::Column::Id) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col(ColumnDef::new(lineitem::Column::Price).decimal()) + .col(ColumnDef::new(lineitem::Column::Quantity).integer()) + .col( + ColumnDef::new(lineitem::Column::OrderId) + .integer() + .not_null(), + ) + .col( + ColumnDef::new(lineitem::Column::CakeId) + .integer() + .not_null(), + ) + .foreign_key( + ForeignKey::create() + .name("FK_lineitem_order") + .from(lineitem::Entity, lineitem::Column::OrderId) + .to(order::Entity, order::Column::Id) + .on_delete(ForeignKeyAction::Cascade) + .on_update(ForeignKeyAction::Cascade), + ) + .foreign_key( + ForeignKey::create() + .name("FK_lineitem_cake") + .from(lineitem::Entity, lineitem::Column::CakeId) + .to(cake::Entity, cake::Column::Id) + .on_delete(ForeignKeyAction::Cascade) + .on_update(ForeignKeyAction::Cascade), + ) + .to_owned(); + + create_table(db, &stmt).await +} + +pub async fn create_cakes_bakers_table(db: &DbConn) -> Result { + let stmt = sea_query::Table::create() + .table(cakes_bakers::Entity) + .if_not_exists() + .col( + ColumnDef::new(cakes_bakers::Column::CakeId) + .integer() + .not_null(), + ) + .col( + ColumnDef::new(cakes_bakers::Column::BakerId) + .integer() + .not_null(), + ) + .primary_key( + Index::create() + .col(cakes_bakers::Column::CakeId) + .col(cakes_bakers::Column::BakerId), + ) + .to_owned(); + + create_table(db, &stmt).await +} + +pub async fn create_cake_table(db: &DbConn) -> Result { + let stmt = sea_query::Table::create() + .table(cake::Entity) + .if_not_exists() + .col( + ColumnDef::new(cake::Column::Id) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col(ColumnDef::new(cake::Column::Name).string()) + .col(ColumnDef::new(cake::Column::Price).float()) + .col(ColumnDef::new(cake::Column::BakeryId).integer().not_null()) + .foreign_key( + ForeignKey::create() + .name("FK_cake_bakery") + .from(cake::Entity, cake::Column::BakeryId) + .to(bakery::Entity, bakery::Column::Id) + .on_delete(ForeignKeyAction::Cascade) + .on_update(ForeignKeyAction::Cascade), + ) + .col(ColumnDef::new(cake::Column::GlutenFree).boolean()) + .to_owned(); + + create_table(db, &stmt).await +} diff --git a/tests/relational_tests.rs b/tests/relational_tests.rs new file mode 100644 index 00000000..edefa9ef --- /dev/null +++ b/tests/relational_tests.rs @@ -0,0 +1,37 @@ +use sea_orm::{entity::*, InsertResult}; + +pub mod bakery_chain; +pub use bakery_chain::*; + +pub mod common; +pub use common::TestContext; + +#[async_std::test] +// cargo test --test realtional_tests -- --nocapture +async fn main() { + test_left_join().await; +} + +pub async fn test_left_join() { + let ctx = TestContext::new("test", "test").await; + + let seaside_bakery = bakery::ActiveModel { + name: Set("SeaSide Bakery".to_owned()), + profit_margin: Set(10.4), + ..Default::default() + }; + let res: InsertResult = Bakery::insert(seaside_bakery) + .exec(&ctx.db_conn) + .await + .expect("could not insert bakery"); + + let bakery: Option = Bakery::find_by_id(res.last_insert_id) + .one(&ctx.db_conn) + .await + .expect("could not find bakery"); + + assert!(bakery.is_some()); + let bakery_model = bakery.unwrap(); + assert_eq!(bakery_model.name, "SeaSide Bakery"); + assert_eq!(bakery_model.profit_margin, 10.4); +}