Merge pull request #34 from SeaQL/ss/bakery
Design and implement the Bakery Chain schema
This commit is contained in:
commit
883bd1605d
@ -35,6 +35,7 @@ async-stream = { version = "^0.3" }
|
||||
chrono = { version = "^0", optional = true }
|
||||
futures = { version = "^0.3" }
|
||||
futures-util = { version = "^0.3" }
|
||||
rust_decimal = { version = "^1", optional = true }
|
||||
sea-query = { version = "^0.12" }
|
||||
sea-orm-macros = { path = "sea-orm-macros", optional = true }
|
||||
serde = { version = "^1.0", features = [ "derive" ] }
|
||||
@ -45,6 +46,7 @@ serde_json = { version = "^1", optional = true }
|
||||
[dev-dependencies]
|
||||
async-std = { version = "^1.9", features = [ "attributes" ] }
|
||||
maplit = { version = "^1" }
|
||||
rust_decimal_macros = { version = "^1" }
|
||||
sea-orm = { path = ".", features = ["sqlx-sqlite", "sqlx-json", "sqlx-chrono", "sqlx-decimal", "runtime-async-std-native-tls"] }
|
||||
|
||||
[features]
|
||||
@ -54,7 +56,7 @@ macros = [ "sea-orm-macros" ]
|
||||
mock = []
|
||||
with-json = [ "serde_json", "sea-query/with-json" ]
|
||||
with-chrono = [ "chrono", "sea-query/with-chrono" ]
|
||||
with-rust_decimal = [ "sea-query/with-rust_decimal" ]
|
||||
with-rust_decimal = [ "rust_decimal", "sea-query/with-rust_decimal" ]
|
||||
sqlx-dep = [ "sqlx" ]
|
||||
sqlx-json = [ "sqlx/json", "with-json" ]
|
||||
sqlx-chrono = [ "sqlx/chrono", "with-chrono" ]
|
||||
|
@ -160,3 +160,59 @@ try_getable_mysql!(u64);
|
||||
try_getable_all!(f32);
|
||||
try_getable_all!(f64);
|
||||
try_getable_all!(String);
|
||||
|
||||
#[cfg(feature = "with-rust_decimal")]
|
||||
use rust_decimal::Decimal;
|
||||
|
||||
#[cfg(feature = "with-rust_decimal")]
|
||||
impl TryGetable for Decimal {
|
||||
fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result<Self, DbErr> {
|
||||
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(crate::sqlx_error_to_query_err)
|
||||
}
|
||||
#[cfg(feature = "sqlx-sqlite")]
|
||||
QueryResultRow::SqlxSqlite(row) => {
|
||||
use sqlx::Row;
|
||||
let val: f64 = row.try_get(column.as_str()).map_err(crate::sqlx_error_to_query_err)?;
|
||||
use rust_decimal::prelude::FromPrimitive;
|
||||
Decimal::from_f64(val).ok_or_else(|| DbErr::Query("Failed to convert f64 into Decimal".to_owned()))
|
||||
}
|
||||
#[cfg(feature = "mock")]
|
||||
QueryResultRow::Mock(row) => Ok(row.try_get(column.as_str())?),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "with-rust_decimal")]
|
||||
impl TryGetable for Option<Decimal> {
|
||||
fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result<Self, DbErr> {
|
||||
let column = format!("{}{}", pre, col);
|
||||
match &res.row {
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
QueryResultRow::SqlxMySql(row) => {
|
||||
use sqlx::Row;
|
||||
match row.try_get(column.as_str()) {
|
||||
Ok(v) => Ok(Some(v)),
|
||||
Err(_) => Ok(None),
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "sqlx-sqlite")]
|
||||
QueryResultRow::SqlxSqlite(_) => {
|
||||
let result: Result<Decimal, _> = TryGetable::try_get(res, pre, col);
|
||||
match result {
|
||||
Ok(v) => Ok(Some(v)),
|
||||
Err(_) => Ok(None),
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "mock")]
|
||||
QueryResultRow::Mock(row) => match row.try_get(column.as_str()) {
|
||||
Ok(v) => Ok(Some(v)),
|
||||
Err(_) => Ok(None),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
81
tests/bakery_chain/baker.rs
Normal file
81
tests/bakery_chain/baker.rs
Normal file
@ -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<i32>,
|
||||
}
|
||||
|
||||
#[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<super::bakery::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Bakery.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::cake::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
super::cakes_bakers::Relation::Cake.def()
|
||||
}
|
||||
|
||||
fn via() -> Option<RelationDef> {
|
||||
Some(super::cakes_bakers::Relation::Baker.def().rev())
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
84
tests/bakery_chain/bakery.rs
Normal file
84
tests/bakery_chain/bakery.rs
Normal file
@ -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<super::baker::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Baker.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::order::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Order.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::cake::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Cake.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
1
tests/bakery_chain/bakery_chain_erd.drawio
Normal file
1
tests/bakery_chain/bakery_chain_erd.drawio
Normal file
@ -0,0 +1 @@
|
||||
<mxfile host="Electron" modified="2021-06-30T11:15:47.471Z" agent="5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/14.6.13 Chrome/89.0.4389.128 Electron/12.0.7 Safari/537.36" etag="CL5AmeQl6dz-rdIIukNg" version="14.6.13" type="device"><diagram id="R2lEEEUBdFMjLlhIrx00" name="Page-1">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</diagram></mxfile>
|
BIN
tests/bakery_chain/bakery_chain_erd.jpg
Normal file
BIN
tests/bakery_chain/bakery_chain_erd.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 50 KiB |
96
tests/bakery_chain/cake.rs
Normal file
96
tests/bakery_chain/cake.rs
Normal file
@ -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<i32>,
|
||||
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<super::bakery::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Bakery.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::baker::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
super::cakes_bakers::Relation::Baker.def()
|
||||
}
|
||||
|
||||
fn via() -> Option<RelationDef> {
|
||||
Some(super::cakes_bakers::Relation::Cake.def().rev())
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::lineitem::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Lineitem.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
68
tests/bakery_chain/cakes_bakers.rs
Normal file
68
tests/bakery_chain/cakes_bakers.rs
Normal file
@ -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 {}
|
68
tests/bakery_chain/customer.rs
Normal file
68
tests/bakery_chain/customer.rs
Normal file
@ -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<super::order::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Order.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
89
tests/bakery_chain/lineitem.rs
Normal file
89
tests/bakery_chain/lineitem.rs
Normal file
@ -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<i32>,
|
||||
pub cake_id: Option<i32>,
|
||||
}
|
||||
|
||||
#[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<super::order::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Order.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::cake::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Cake.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
15
tests/bakery_chain/mod.rs
Normal file
15
tests/bakery_chain/mod.rs
Normal file
@ -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;
|
97
tests/bakery_chain/order.rs
Normal file
97
tests/bakery_chain/order.rs
Normal file
@ -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<i32>,
|
||||
pub customer_id: Option<i32>,
|
||||
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<super::bakery::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Bakery.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::customer::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Customer.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::lineitem::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Lineitem.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
34
tests/bakery_chain_tests.rs
Normal file
34
tests/bakery_chain_tests.rs
Normal file
@ -0,0 +1,34 @@
|
||||
use sea_orm::DbConn;
|
||||
|
||||
pub mod bakery_chain;
|
||||
mod setup;
|
||||
pub use bakery_chain::*;
|
||||
mod crud;
|
||||
mod schema;
|
||||
|
||||
#[async_std::test]
|
||||
// cargo test --test bakery_chain_tests -- --nocapture
|
||||
async fn main() {
|
||||
let db: DbConn = setup::setup().await;
|
||||
setup_schema(&db).await;
|
||||
create_entities(&db).await;
|
||||
}
|
||||
|
||||
async fn setup_schema(db: &DbConn) {
|
||||
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());
|
||||
}
|
||||
|
||||
async fn create_entities(db: &DbConn) {
|
||||
crud::test_create_bakery(db).await;
|
||||
crud::test_create_baker(db).await;
|
||||
crud::test_create_customer(db).await;
|
||||
crud::create_cake::test_create_cake(db).await;
|
||||
crud::create_lineitem::test_create_lineitem(db).await;
|
||||
crud::create_order::test_create_order(db).await;
|
||||
}
|
90
tests/crud/create_cake.rs
Normal file
90
tests/crud/create_cake.rs
Normal file
@ -0,0 +1,90 @@
|
||||
pub use super::*;
|
||||
use rust_decimal_macros::dec;
|
||||
|
||||
pub async fn test_create_cake(db: &DbConn) {
|
||||
let seaside_bakery = bakery::ActiveModel {
|
||||
name: Set("SeaSide Bakery".to_owned()),
|
||||
profit_margin: Set(10.4),
|
||||
..Default::default()
|
||||
};
|
||||
let bakery_insert_res: InsertResult = Bakery::insert(seaside_bakery)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert bakery");
|
||||
|
||||
let baker_bob = baker::ActiveModel {
|
||||
name: Set("Baker Bob".to_owned()),
|
||||
bakery_id: Set(Some(bakery_insert_res.last_insert_id as i32)),
|
||||
..Default::default()
|
||||
};
|
||||
let baker_insert_res: InsertResult = Baker::insert(baker_bob)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert baker");
|
||||
|
||||
let mud_cake = cake::ActiveModel {
|
||||
name: Set("Mud Cake".to_owned()),
|
||||
price: Set(dec!(10.25)),
|
||||
gluten_free: Set(false),
|
||||
bakery_id: Set(Some(bakery_insert_res.last_insert_id as i32)),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let cake_insert_res: InsertResult = Cake::insert(mud_cake)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert cake");
|
||||
|
||||
let cake: Option<cake::Model> = Cake::find_by_id(cake_insert_res.last_insert_id)
|
||||
.one(db)
|
||||
.await
|
||||
.expect("could not find cake");
|
||||
|
||||
let cake_baker = cakes_bakers::ActiveModel {
|
||||
cake_id: Set(cake_insert_res.last_insert_id as i32),
|
||||
baker_id: Set(baker_insert_res.last_insert_id as i32),
|
||||
..Default::default()
|
||||
};
|
||||
let _cake_baker_res: InsertResult = CakesBakers::insert(cake_baker)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert cake_baker");
|
||||
|
||||
assert!(cake.is_some());
|
||||
let cake_model = cake.unwrap();
|
||||
assert_eq!(cake_model.name, "Mud Cake");
|
||||
assert_eq!(cake_model.price, dec!(10.25));
|
||||
assert_eq!(cake_model.gluten_free, false);
|
||||
assert_eq!(
|
||||
cake_model
|
||||
.find_related(Bakery)
|
||||
.one(db)
|
||||
.await
|
||||
.expect("Bakery not found")
|
||||
.unwrap()
|
||||
.name,
|
||||
"SeaSide Bakery"
|
||||
);
|
||||
|
||||
let related_bakers: Vec<baker::Model> = cake_model
|
||||
.find_related(Baker)
|
||||
.all(db)
|
||||
.await
|
||||
.expect("could not find related bakers");
|
||||
assert_eq!(related_bakers.len(), 1);
|
||||
assert_eq!(related_bakers[0].name, "Baker Bob");
|
||||
|
||||
let baker: Option<baker::Model> = Baker::find_by_id(baker_insert_res.last_insert_id)
|
||||
.one(db)
|
||||
.await
|
||||
.expect("could not find baker");
|
||||
|
||||
let related_cakes: Vec<cake::Model> = baker
|
||||
.unwrap()
|
||||
.find_related(Cake)
|
||||
.all(db)
|
||||
.await
|
||||
.expect("could not find related cakes");
|
||||
assert_eq!(related_cakes.len(), 1);
|
||||
assert_eq!(related_cakes[0].name, "Mud Cake")
|
||||
}
|
115
tests/crud/create_lineitem.rs
Normal file
115
tests/crud/create_lineitem.rs
Normal file
@ -0,0 +1,115 @@
|
||||
pub use super::*;
|
||||
use rust_decimal_macros::dec;
|
||||
|
||||
pub async fn test_create_lineitem(db: &DbConn) {
|
||||
// Bakery
|
||||
let seaside_bakery = bakery::ActiveModel {
|
||||
name: Set("SeaSide Bakery".to_owned()),
|
||||
profit_margin: Set(10.4),
|
||||
..Default::default()
|
||||
};
|
||||
let bakery_insert_res: InsertResult = Bakery::insert(seaside_bakery)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert bakery");
|
||||
|
||||
// Baker
|
||||
let baker_bob = baker::ActiveModel {
|
||||
name: Set("Baker Bob".to_owned()),
|
||||
bakery_id: Set(Some(bakery_insert_res.last_insert_id as i32)),
|
||||
..Default::default()
|
||||
};
|
||||
let baker_insert_res: InsertResult = Baker::insert(baker_bob)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert baker");
|
||||
|
||||
// Cake
|
||||
let mud_cake = cake::ActiveModel {
|
||||
name: Set("Mud Cake".to_owned()),
|
||||
price: Set(dec!(10.25)),
|
||||
gluten_free: Set(false),
|
||||
bakery_id: Set(Some(bakery_insert_res.last_insert_id as i32)),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let cake_insert_res: InsertResult = Cake::insert(mud_cake)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert cake");
|
||||
|
||||
// Cake_Baker
|
||||
let cake_baker = cakes_bakers::ActiveModel {
|
||||
cake_id: Set(cake_insert_res.last_insert_id as i32),
|
||||
baker_id: Set(baker_insert_res.last_insert_id as i32),
|
||||
..Default::default()
|
||||
};
|
||||
let _cake_baker_res: InsertResult = CakesBakers::insert(cake_baker)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert cake_baker");
|
||||
|
||||
// Customer
|
||||
let customer_kate = customer::ActiveModel {
|
||||
name: Set("Kate".to_owned()),
|
||||
notes: Set("Loves cheese cake".to_owned()),
|
||||
..Default::default()
|
||||
};
|
||||
let customer_insert_res: InsertResult = Customer::insert(customer_kate)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert customer");
|
||||
|
||||
// Order
|
||||
let order_1 = order::ActiveModel {
|
||||
bakery_id: Set(Some(bakery_insert_res.last_insert_id as i32)),
|
||||
customer_id: Set(Some(customer_insert_res.last_insert_id as i32)),
|
||||
placed_at: Set("placeholder".to_string()),
|
||||
..Default::default()
|
||||
};
|
||||
let order_insert_res: InsertResult = Order::insert(order_1)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert order");
|
||||
|
||||
// Lineitem
|
||||
let lineitem_1 = lineitem::ActiveModel {
|
||||
cake_id: Set(Some(cake_insert_res.last_insert_id as i32)),
|
||||
order_id: Set(Some(order_insert_res.last_insert_id as i32)),
|
||||
price: Set(dec!(7.55)),
|
||||
..Default::default()
|
||||
};
|
||||
let lineitem_insert_res: InsertResult = Lineitem::insert(lineitem_1)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert lineitem");
|
||||
|
||||
let lineitem: Option<lineitem::Model> =
|
||||
Lineitem::find_by_id(lineitem_insert_res.last_insert_id)
|
||||
.one(db)
|
||||
.await
|
||||
.expect("could not find lineitem");
|
||||
|
||||
assert!(lineitem.is_some());
|
||||
let lineitem_model = lineitem.unwrap();
|
||||
assert_eq!(lineitem_model.price, dec!(7.55));
|
||||
|
||||
let cake: Option<cake::Model> = Cake::find_by_id(lineitem_model.cake_id)
|
||||
.one(db)
|
||||
.await
|
||||
.expect("could not find cake");
|
||||
|
||||
let cake_model = cake.unwrap();
|
||||
assert_eq!(cake_model.name, "Mud Cake");
|
||||
|
||||
let order: Option<order::Model> = Order::find_by_id(lineitem_model.order_id)
|
||||
.one(db)
|
||||
.await
|
||||
.expect("could not find order");
|
||||
|
||||
let order_model = order.unwrap();
|
||||
assert_eq!(
|
||||
order_model.customer_id.unwrap(),
|
||||
customer_insert_res.last_insert_id as i32
|
||||
);
|
||||
}
|
122
tests/crud/create_order.rs
Normal file
122
tests/crud/create_order.rs
Normal file
@ -0,0 +1,122 @@
|
||||
pub use super::*;
|
||||
use rust_decimal_macros::dec;
|
||||
|
||||
pub async fn test_create_order(db: &DbConn) {
|
||||
// Bakery
|
||||
let seaside_bakery = bakery::ActiveModel {
|
||||
name: Set("SeaSide Bakery".to_owned()),
|
||||
profit_margin: Set(10.4),
|
||||
..Default::default()
|
||||
};
|
||||
let bakery_insert_res: InsertResult = Bakery::insert(seaside_bakery)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert bakery");
|
||||
|
||||
// Baker
|
||||
let baker_bob = baker::ActiveModel {
|
||||
name: Set("Baker Bob".to_owned()),
|
||||
bakery_id: Set(Some(bakery_insert_res.last_insert_id as i32)),
|
||||
..Default::default()
|
||||
};
|
||||
let baker_insert_res: InsertResult = Baker::insert(baker_bob)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert baker");
|
||||
|
||||
// Cake
|
||||
let mud_cake = cake::ActiveModel {
|
||||
name: Set("Mud Cake".to_owned()),
|
||||
price: Set(dec!(10.25)),
|
||||
gluten_free: Set(false),
|
||||
bakery_id: Set(Some(bakery_insert_res.last_insert_id as i32)),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let cake_insert_res: InsertResult = Cake::insert(mud_cake)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert cake");
|
||||
|
||||
// Cake_Baker
|
||||
let cake_baker = cakes_bakers::ActiveModel {
|
||||
cake_id: Set(cake_insert_res.last_insert_id as i32),
|
||||
baker_id: Set(baker_insert_res.last_insert_id as i32),
|
||||
..Default::default()
|
||||
};
|
||||
let _cake_baker_res: InsertResult = CakesBakers::insert(cake_baker)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert cake_baker");
|
||||
|
||||
// Customer
|
||||
let customer_kate = customer::ActiveModel {
|
||||
name: Set("Kate".to_owned()),
|
||||
notes: Set("Loves cheese cake".to_owned()),
|
||||
..Default::default()
|
||||
};
|
||||
let customer_insert_res: InsertResult = Customer::insert(customer_kate)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert customer");
|
||||
|
||||
// Order
|
||||
let order_1 = order::ActiveModel {
|
||||
bakery_id: Set(Some(bakery_insert_res.last_insert_id as i32)),
|
||||
customer_id: Set(Some(customer_insert_res.last_insert_id as i32)),
|
||||
total: Set(dec!(15.10)),
|
||||
placed_at: Set("placeholder".to_string()),
|
||||
..Default::default()
|
||||
};
|
||||
let order_insert_res: InsertResult = Order::insert(order_1)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert order");
|
||||
|
||||
// Lineitem
|
||||
let lineitem_1 = lineitem::ActiveModel {
|
||||
cake_id: Set(Some(cake_insert_res.last_insert_id as i32)),
|
||||
order_id: Set(Some(order_insert_res.last_insert_id as i32)),
|
||||
price: Set(dec!(7.55)),
|
||||
quantity: Set(2),
|
||||
..Default::default()
|
||||
};
|
||||
let _lineitem_insert_res: InsertResult = Lineitem::insert(lineitem_1)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert lineitem");
|
||||
|
||||
let order: Option<order::Model> = Order::find_by_id(order_insert_res.last_insert_id)
|
||||
.one(db)
|
||||
.await
|
||||
.expect("could not find order");
|
||||
|
||||
assert!(order.is_some());
|
||||
let order_model = order.unwrap();
|
||||
assert_eq!(order_model.total, dec!(15.10));
|
||||
|
||||
let customer: Option<customer::Model> = Customer::find_by_id(order_model.customer_id)
|
||||
.one(db)
|
||||
.await
|
||||
.expect("could not find customer");
|
||||
|
||||
let customer_model = customer.unwrap();
|
||||
assert_eq!(customer_model.name, "Kate");
|
||||
|
||||
let bakery: Option<bakery::Model> = Bakery::find_by_id(order_model.bakery_id)
|
||||
.one(db)
|
||||
.await
|
||||
.expect("could not find bakery");
|
||||
|
||||
let bakery_model = bakery.unwrap();
|
||||
assert_eq!(bakery_model.name, "SeaSide Bakery");
|
||||
|
||||
let related_lineitems: Vec<lineitem::Model> = order_model
|
||||
.find_related(Lineitem)
|
||||
.all(db)
|
||||
.await
|
||||
.expect("could not find related lineitems");
|
||||
assert_eq!(related_lineitems.len(), 1);
|
||||
assert_eq!(related_lineitems[0].price, dec!(7.55));
|
||||
assert_eq!(related_lineitems[0].quantity, 2);
|
||||
}
|
106
tests/crud/mod.rs
Normal file
106
tests/crud/mod.rs
Normal file
@ -0,0 +1,106 @@
|
||||
use sea_orm::{entity::*, DbConn, InsertResult};
|
||||
|
||||
pub use super::bakery_chain::*;
|
||||
|
||||
pub mod create_cake;
|
||||
pub mod create_lineitem;
|
||||
pub mod create_order;
|
||||
|
||||
pub async fn test_create_bakery(db: &DbConn) {
|
||||
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(db)
|
||||
.await
|
||||
.expect("could not insert bakery");
|
||||
|
||||
let bakery: Option<bakery::Model> = Bakery::find_by_id(res.last_insert_id)
|
||||
.one(db)
|
||||
.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);
|
||||
}
|
||||
|
||||
pub async fn test_create_baker(db: &DbConn) {
|
||||
let seaside_bakery = bakery::ActiveModel {
|
||||
name: Set("SeaSide Bakery".to_owned()),
|
||||
profit_margin: Set(10.4),
|
||||
..Default::default()
|
||||
};
|
||||
let bakery_insert_res: InsertResult = Bakery::insert(seaside_bakery)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert bakery");
|
||||
|
||||
let baker_bob = baker::ActiveModel {
|
||||
name: Set("Baker Bob".to_owned()),
|
||||
bakery_id: Set(Some(bakery_insert_res.last_insert_id as i32)),
|
||||
..Default::default()
|
||||
};
|
||||
let res: InsertResult = Baker::insert(baker_bob)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert baker");
|
||||
|
||||
let baker: Option<baker::Model> = Baker::find_by_id(res.last_insert_id)
|
||||
.one(db)
|
||||
.await
|
||||
.expect("could not find baker");
|
||||
|
||||
assert!(baker.is_some());
|
||||
let baker_model = baker.unwrap();
|
||||
assert_eq!(baker_model.name, "Baker Bob");
|
||||
assert_eq!(
|
||||
baker_model
|
||||
.find_related(Bakery)
|
||||
.one(db)
|
||||
.await
|
||||
.expect("Bakery not found")
|
||||
.unwrap()
|
||||
.name,
|
||||
"SeaSide Bakery"
|
||||
);
|
||||
|
||||
let bakery: Option<bakery::Model> = Bakery::find_by_id(bakery_insert_res.last_insert_id)
|
||||
.one(db)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let related_bakers: Vec<baker::Model> = bakery
|
||||
.unwrap()
|
||||
.find_related(Baker)
|
||||
.all(db)
|
||||
.await
|
||||
.expect("could not find related bakers");
|
||||
assert_eq!(related_bakers.len(), 1);
|
||||
assert_eq!(related_bakers[0].name, "Baker Bob")
|
||||
}
|
||||
|
||||
pub async fn test_create_customer(db: &DbConn) {
|
||||
let customer_kate = customer::ActiveModel {
|
||||
name: Set("Kate".to_owned()),
|
||||
notes: Set("Loves cheese cake".to_owned()),
|
||||
..Default::default()
|
||||
};
|
||||
let res: InsertResult = Customer::insert(customer_kate)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert customer");
|
||||
|
||||
let customer: Option<customer::Model> = Customer::find_by_id(res.last_insert_id)
|
||||
.one(db)
|
||||
.await
|
||||
.expect("could not find customer");
|
||||
|
||||
assert!(customer.is_some());
|
||||
let customer_model = customer.unwrap();
|
||||
assert_eq!(customer_model.name, "Kate");
|
||||
assert_eq!(customer_model.notes, "Loves cheese cake");
|
||||
}
|
211
tests/schema/mod.rs
Normal file
211
tests/schema/mod.rs
Normal file
@ -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<ExecResult, DbErr> {
|
||||
let builder = db.get_schema_builder_backend();
|
||||
db.execute(builder.build(stmt)).await
|
||||
}
|
||||
|
||||
pub async fn create_bakery_table(db: &DbConn) -> Result<ExecResult, DbErr> {
|
||||
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<ExecResult, DbErr> {
|
||||
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<ExecResult, DbErr> {
|
||||
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<ExecResult, DbErr> {
|
||||
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<ExecResult, DbErr> {
|
||||
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<ExecResult, DbErr> {
|
||||
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<ExecResult, DbErr> {
|
||||
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
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user