Seaography example WIP (#1788)

* Seaography example WIP

* Seaography example

* Screenshot
This commit is contained in:
Chris Tsang 2023-07-30 05:08:28 +08:00 committed by GitHub
parent d7d45ae669
commit 7af76fc753
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 1170 additions and 0 deletions

View File

@ -0,0 +1,80 @@
# SeaORM Seaography Example
![Seaography screenshot with Bakery schema](<Seaography example.png>)
## Specifiy a database url
```
export DATABASE_URL=mysql://sea:sea@localhost/bakery
```
## Setup the Database first
Cd into `migration` folder, follow instructions there, but basically:
```
cargo run
```
## Install Seaography
```
cargo install seaography-cli@^1.0.0-rc.2
```
## Generate Seaography project
```
rm -rf graphql # this entire folder is generated
sea-orm-cli generate entity --output-dir graphql/src/entities --seaography
seaography-cli graphql graphql/src/entities $DATABASE_URL sea-orm-seaography-example
```
## Running the project
```
cd graphql
cargo run
```
## Run some queries
### Bakery -> Cake -> Baker
```graphql
{
bakery(pagination: { page: { limit: 10, page: 0 } }, orderBy: { name: ASC }) {
nodes {
name
cake {
nodes {
name
price
baker {
nodes {
name
}
}
}
}
}
}
}
```
### List gluten-free cakes and know where to buy them
```graphql
{
cake(filters: { glutenFree: { eq: 1 } }) {
nodes {
name
price
glutenFree
bakery {
name
}
}
}
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

View File

@ -0,0 +1,3 @@
DATABASE_URL="mysql://sea:sea@localhost/bakery"
# COMPLEXITY_LIMIT=
# DEPTH_LIMIT=

View File

@ -0,0 +1,27 @@
[package]
edition = "2021"
name = "sea-orm-seaography-example"
version = "0.3.0"
publish = false
[dependencies]
poem = { version = "1.3.56" }
async-graphql-poem = { version = "5.0.10" }
async-graphql = { version = "5.0.10", features = ["decimal", "chrono", "dataloader", "dynamic-schema"] }
async-trait = { version = "0.1.72" }
dotenv = "0.15.0"
sea-orm = { version = "0.12.0", features = ["sqlx-mysql", "runtime-async-std-native-tls", "seaography"] }
tokio = { version = "1.29.1", features = ["macros", "rt-multi-thread"] }
tracing = { version = "0.1.37" }
tracing-subscriber = { version = "0.3.17" }
lazy_static = { version = "1.4.0" }
[dependencies.seaography]
version = "1.0.0-rc.2" # seaography version
features = ["with-decimal", "with-chrono"]
[dev-dependencies]
serde_json = { version = "1.0.103" }
[workspace]
members = []

View File

@ -0,0 +1,60 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "baker")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub name: String,
pub contact: String,
pub bakery_id: Option<i32>,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::bakery::Entity",
from = "Column::BakeryId",
to = "super::bakery::Column::Id",
on_update = "Cascade",
on_delete = "Cascade"
)]
Bakery,
#[sea_orm(has_many = "super::cake_baker::Entity")]
CakeBaker,
}
impl Related<super::bakery::Entity> for Entity {
fn to() -> RelationDef {
Relation::Bakery.def()
}
}
impl Related<super::cake_baker::Entity> for Entity {
fn to() -> RelationDef {
Relation::CakeBaker.def()
}
}
impl Related<super::cake::Entity> for Entity {
fn to() -> RelationDef {
super::cake_baker::Relation::Cake.def()
}
fn via() -> Option<RelationDef> {
Some(super::cake_baker::Relation::Baker.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelatedEntity)]
pub enum RelatedEntity {
#[sea_orm(entity = "super::bakery::Entity")]
Bakery,
#[sea_orm(entity = "super::cake_baker::Entity")]
CakeBaker,
#[sea_orm(entity = "super::cake::Entity")]
Cake,
}

View File

@ -0,0 +1,43 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "bakery")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub name: String,
#[sea_orm(column_type = "Double")]
pub profit_margin: f64,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(has_many = "super::baker::Entity")]
Baker,
#[sea_orm(has_many = "super::cake::Entity")]
Cake,
}
impl Related<super::baker::Entity> for Entity {
fn to() -> RelationDef {
Relation::Baker.def()
}
}
impl Related<super::cake::Entity> for Entity {
fn to() -> RelationDef {
Relation::Cake.def()
}
}
impl ActiveModelBehavior for ActiveModel {}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelatedEntity)]
pub enum RelatedEntity {
#[sea_orm(entity = "super::baker::Entity")]
Baker,
#[sea_orm(entity = "super::cake::Entity")]
Cake,
}

View File

@ -0,0 +1,62 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "cake")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub name: String,
#[sea_orm(column_type = "Decimal(Some((19, 4)))")]
pub price: Decimal,
pub bakery_id: Option<i32>,
pub gluten_free: i8,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::bakery::Entity",
from = "Column::BakeryId",
to = "super::bakery::Column::Id",
on_update = "Cascade",
on_delete = "Cascade"
)]
Bakery,
#[sea_orm(has_many = "super::cake_baker::Entity")]
CakeBaker,
}
impl Related<super::bakery::Entity> for Entity {
fn to() -> RelationDef {
Relation::Bakery.def()
}
}
impl Related<super::cake_baker::Entity> for Entity {
fn to() -> RelationDef {
Relation::CakeBaker.def()
}
}
impl Related<super::baker::Entity> for Entity {
fn to() -> RelationDef {
super::cake_baker::Relation::Baker.def()
}
fn via() -> Option<RelationDef> {
Some(super::cake_baker::Relation::Cake.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelatedEntity)]
pub enum RelatedEntity {
#[sea_orm(entity = "super::bakery::Entity")]
Bakery,
#[sea_orm(entity = "super::cake_baker::Entity")]
CakeBaker,
#[sea_orm(entity = "super::baker::Entity")]
Baker,
}

View File

@ -0,0 +1,54 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "cake_baker")]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub cake_id: i32,
#[sea_orm(primary_key, auto_increment = false)]
pub baker_id: i32,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::baker::Entity",
from = "Column::BakerId",
to = "super::baker::Column::Id",
on_update = "Cascade",
on_delete = "Cascade"
)]
Baker,
#[sea_orm(
belongs_to = "super::cake::Entity",
from = "Column::CakeId",
to = "super::cake::Column::Id",
on_update = "Cascade",
on_delete = "Cascade"
)]
Cake,
}
impl Related<super::baker::Entity> for Entity {
fn to() -> RelationDef {
Relation::Baker.def()
}
}
impl Related<super::cake::Entity> for Entity {
fn to() -> RelationDef {
Relation::Cake.def()
}
}
impl ActiveModelBehavior for ActiveModel {}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelatedEntity)]
pub enum RelatedEntity {
#[sea_orm(entity = "super::baker::Entity")]
Baker,
#[sea_orm(entity = "super::cake::Entity")]
Cake,
}

View File

@ -0,0 +1,8 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1
pub mod prelude;
pub mod baker;
pub mod bakery;
pub mod cake;
pub mod cake_baker;

View File

@ -0,0 +1,6 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1
pub use super::baker::Entity as Baker;
pub use super::bakery::Entity as Bakery;
pub use super::cake::Entity as Cake;
pub use super::cake_baker::Entity as CakeBaker;

View File

@ -0,0 +1,8 @@
use sea_orm::prelude::*;
pub mod entities;
pub mod query_root;
pub struct OrmDataloader {
pub db: DatabaseConnection,
}

View File

@ -0,0 +1,64 @@
use async_graphql::{
dataloader::DataLoader,
http::{playground_source, GraphQLPlaygroundConfig},
};
use async_graphql_poem::GraphQL;
use dotenv::dotenv;
use lazy_static::lazy_static;
use poem::{get, handler, listener::TcpListener, web::Html, IntoResponse, Route, Server};
use sea_orm::Database;
use sea_orm_seaography_example::*;
use std::env;
lazy_static! {
static ref URL: String = env::var("URL").unwrap_or("0.0.0.0:8000".into());
static ref ENDPOINT: String = env::var("ENDPOINT").unwrap_or("/".into());
static ref DATABASE_URL: String =
env::var("DATABASE_URL").expect("DATABASE_URL environment variable not set");
static ref DEPTH_LIMIT: Option<usize> = env::var("DEPTH_LIMIT").map_or(None, |data| Some(
data.parse().expect("DEPTH_LIMIT is not a number")
));
static ref COMPLEXITY_LIMIT: Option<usize> = env::var("COMPLEXITY_LIMIT")
.map_or(None, |data| {
Some(data.parse().expect("COMPLEXITY_LIMIT is not a number"))
});
}
#[handler]
async fn graphql_playground() -> impl IntoResponse {
Html(playground_source(GraphQLPlaygroundConfig::new(&ENDPOINT)))
}
#[tokio::main]
async fn main() {
dotenv().ok();
tracing_subscriber::fmt()
.with_max_level(tracing::Level::INFO)
.with_test_writer()
.init();
let database = Database::connect(&*DATABASE_URL)
.await
.expect("Fail to initialize database connection");
let orm_dataloader: DataLoader<OrmDataloader> = DataLoader::new(
OrmDataloader {
db: database.clone(),
},
tokio::spawn,
);
let schema = sea_orm_seaography_example::query_root::schema(
database,
orm_dataloader,
*DEPTH_LIMIT,
*COMPLEXITY_LIMIT,
)
.unwrap();
let app = Route::new().at(
&*ENDPOINT,
get(graphql_playground).post(GraphQL::new(schema)),
);
println!("Visit GraphQL Playground at http://{}", *URL);
Server::new(TcpListener::bind(&*URL))
.run(app)
.await
.expect("Fail to start web server");
}

View File

@ -0,0 +1,28 @@
use crate::{entities::*, OrmDataloader};
use async_graphql::{dataloader::DataLoader, dynamic::*};
use sea_orm::DatabaseConnection;
use seaography::{Builder, BuilderContext};
lazy_static::lazy_static! { static ref CONTEXT : BuilderContext = BuilderContext :: default () ; }
pub fn schema(
database: DatabaseConnection,
orm_dataloader: DataLoader<OrmDataloader>,
depth: Option<usize>,
complexity: Option<usize>,
) -> Result<Schema, SchemaError> {
let mut builder = Builder::new(&CONTEXT);
seaography::register_entities!(builder, [baker, bakery, cake, cake_baker,]);
let schema = builder.schema_builder();
let schema = if let Some(depth) = depth {
schema.limit_depth(depth)
} else {
schema
};
let schema = if let Some(complexity) = complexity {
schema.limit_complexity(complexity)
} else {
schema
};
schema.data(database).data(orm_dataloader).finish()
}

View File

@ -0,0 +1,26 @@
[workspace]
[package]
name = "migration"
version = "0.1.0"
edition = "2021"
publish = false
[lib]
name = "migration"
path = "src/lib.rs"
[dependencies]
async-std = { version = "1", features = ["attributes", "tokio1"] }
[dependencies.sea-orm]
path = "../../.." # remove this line in your own project
version = "0.12.1" # sea-orm version
[dependencies.sea-orm-migration]
path = "../../../sea-orm-migration" # remove this line in your own project
version = "0.12.1" # sea-orm-migration version
features = [
"runtime-async-std-native-tls",
"sqlx-mysql",
]

View File

@ -0,0 +1,51 @@
# Bakery Schema
Assume the database is named `bakery`:
```sh
export DATABASE_URL=mysql://sea:sea@localhost/bakery
```
# Re-generate entities
```sh
sea-orm-cli generate entity --output-dir src/entity
```
# Running Migrator CLI
- Apply all pending migrations
```sh
cargo run
```
```sh
cargo run -- up
```
- Apply first 10 pending migrations
```sh
cargo run -- up -n 10
```
- Rollback last applied migrations
```sh
cargo run -- down
```
- Rollback last 10 applied migrations
```sh
cargo run -- down -n 10
```
- Drop all tables from the database, then reapply all migrations
```sh
cargo run -- fresh
```
- Rollback all applied migrations, then reapply all migrations
```sh
cargo run -- refresh
```
- Rollback all applied migrations
```sh
cargo run -- reset
```
- Check the status of all migrations
```sh
cargo run -- status
```

View File

@ -0,0 +1,50 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "baker")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub name: String,
pub contact: String,
pub bakery_id: Option<i32>,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::bakery::Entity",
from = "Column::BakeryId",
to = "super::bakery::Column::Id",
on_update = "Cascade",
on_delete = "Cascade"
)]
Bakery,
#[sea_orm(has_many = "super::cake_baker::Entity")]
CakeBaker,
}
impl Related<super::bakery::Entity> for Entity {
fn to() -> RelationDef {
Relation::Bakery.def()
}
}
impl Related<super::cake_baker::Entity> for Entity {
fn to() -> RelationDef {
Relation::CakeBaker.def()
}
}
impl Related<super::cake::Entity> for Entity {
fn to() -> RelationDef {
super::cake_baker::Relation::Cake.def()
}
fn via() -> Option<RelationDef> {
Some(super::cake_baker::Relation::Baker.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@ -0,0 +1,35 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "bakery")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub name: String,
#[sea_orm(column_type = "Double")]
pub profit_margin: f64,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(has_many = "super::baker::Entity")]
Baker,
#[sea_orm(has_many = "super::cake::Entity")]
Cake,
}
impl Related<super::baker::Entity> for Entity {
fn to() -> RelationDef {
Relation::Baker.def()
}
}
impl Related<super::cake::Entity> for Entity {
fn to() -> RelationDef {
Relation::Cake.def()
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@ -0,0 +1,52 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "cake")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub name: String,
#[sea_orm(column_type = "Decimal(Some((19, 4)))")]
pub price: Decimal,
pub bakery_id: Option<i32>,
pub gluten_free: i8,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::bakery::Entity",
from = "Column::BakeryId",
to = "super::bakery::Column::Id",
on_update = "Cascade",
on_delete = "Cascade"
)]
Bakery,
#[sea_orm(has_many = "super::cake_baker::Entity")]
CakeBaker,
}
impl Related<super::bakery::Entity> for Entity {
fn to() -> RelationDef {
Relation::Bakery.def()
}
}
impl Related<super::cake_baker::Entity> for Entity {
fn to() -> RelationDef {
Relation::CakeBaker.def()
}
}
impl Related<super::baker::Entity> for Entity {
fn to() -> RelationDef {
super::cake_baker::Relation::Baker.def()
}
fn via() -> Option<RelationDef> {
Some(super::cake_baker::Relation::Cake.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@ -0,0 +1,46 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "cake_baker")]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub cake_id: i32,
#[sea_orm(primary_key, auto_increment = false)]
pub baker_id: i32,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::baker::Entity",
from = "Column::BakerId",
to = "super::baker::Column::Id",
on_update = "Cascade",
on_delete = "Cascade"
)]
Baker,
#[sea_orm(
belongs_to = "super::cake::Entity",
from = "Column::CakeId",
to = "super::cake::Column::Id",
on_update = "Cascade",
on_delete = "Cascade"
)]
Cake,
}
impl Related<super::baker::Entity> for Entity {
fn to() -> RelationDef {
Relation::Baker.def()
}
}
impl Related<super::cake::Entity> for Entity {
fn to() -> RelationDef {
Relation::Cake.def()
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@ -0,0 +1,8 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1
pub mod prelude;
pub mod baker;
pub mod bakery;
pub mod cake;
pub mod cake_baker;

View File

@ -0,0 +1,6 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1
pub use super::baker::Entity as Baker;
pub use super::bakery::Entity as Bakery;
pub use super::cake::Entity as Cake;
pub use super::cake_baker::Entity as CakeBaker;

View File

@ -0,0 +1,29 @@
pub use sea_orm_migration::prelude::*;
mod entity;
mod m20230101_000001_create_bakery_table;
mod m20230101_000002_create_baker_table;
mod m20230101_000003_create_cake_table;
mod m20230101_000004_create_cake_baker_table;
mod m20230101_000005_create_customer_table;
mod m20230101_000006_create_order_table;
mod m20230101_000007_create_lineitem_table;
mod m20230102_000001_seed_bakery_data;
pub struct Migrator;
#[async_trait::async_trait]
impl MigratorTrait for Migrator {
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
vec![
Box::new(m20230101_000001_create_bakery_table::Migration),
Box::new(m20230101_000002_create_baker_table::Migration),
Box::new(m20230101_000003_create_cake_table::Migration),
Box::new(m20230101_000004_create_cake_baker_table::Migration),
// Box::new(m20230101_000005_create_customer_table::Migration),
// Box::new(m20230101_000006_create_order_table::Migration),
// Box::new(m20230101_000007_create_lineitem_table::Migration),
Box::new(m20230102_000001_seed_bakery_data::Migration),
]
}
}

View File

@ -0,0 +1,40 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(Bakery::Table)
.col(
ColumnDef::new(Bakery::Id)
.integer()
.not_null()
.auto_increment()
.primary_key(),
)
.col(ColumnDef::new(Bakery::Name).string().not_null())
.col(ColumnDef::new(Bakery::ProfitMargin).double().not_null())
.to_owned(),
)
.await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table(Table::drop().table(Bakery::Table).to_owned())
.await
}
}
#[derive(DeriveIden)]
enum Bakery {
Table,
Id,
Name,
ProfitMargin,
}

View File

@ -0,0 +1,56 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(Baker::Table)
.col(
ColumnDef::new(Baker::Id)
.integer()
.not_null()
.auto_increment()
.primary_key(),
)
.col(ColumnDef::new(Baker::Name).string().not_null())
.col(ColumnDef::new(Baker::Contact).string().not_null())
.col(ColumnDef::new(Baker::BakeryId).integer())
.foreign_key(
ForeignKey::create()
.name("fk-baker-bakery_id")
.from(Baker::Table, Baker::BakeryId)
.to(Bakery::Table, Bakery::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade),
)
.to_owned(),
)
.await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table(Table::drop().table(Baker::Table).to_owned())
.await
}
}
#[derive(DeriveIden)]
enum Baker {
Table,
Id,
Name,
Contact,
BakeryId,
}
#[derive(DeriveIden)]
enum Bakery {
Table,
Id,
}

View File

@ -0,0 +1,58 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(Cake::Table)
.col(
ColumnDef::new(Cake::Id)
.integer()
.not_null()
.auto_increment()
.primary_key(),
)
.col(ColumnDef::new(Cake::Name).string().not_null())
.col(ColumnDef::new(Cake::Price).decimal_len(19, 4).not_null())
.col(ColumnDef::new(Cake::BakeryId).integer())
.foreign_key(
ForeignKey::create()
.name("fk-cake-bakery_id")
.from(Cake::Table, Cake::BakeryId)
.to(Bakery::Table, Bakery::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade),
)
.col(ColumnDef::new(Cake::GlutenFree).boolean().not_null())
.to_owned(),
)
.await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table(Table::drop().table(Cake::Table).to_owned())
.await
}
}
#[derive(DeriveIden)]
enum Cake {
Table,
Id,
Name,
Price,
GlutenFree,
BakeryId,
}
#[derive(DeriveIden)]
enum Bakery {
Table,
Id,
}

View File

@ -0,0 +1,66 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(CakeBaker::Table)
.col(ColumnDef::new(CakeBaker::CakeId).integer().not_null())
.col(ColumnDef::new(CakeBaker::BakerId).integer().not_null())
.primary_key(
Index::create()
.name("pk-cake_baker")
.col(CakeBaker::CakeId)
.col(CakeBaker::BakerId),
)
.foreign_key(
ForeignKey::create()
.name("fk-cake_baker-cake_id")
.from(CakeBaker::Table, CakeBaker::CakeId)
.to(Cake::Table, Cake::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade),
)
.foreign_key(
ForeignKey::create()
.name("fk-cake_baker-baker_id")
.from(CakeBaker::Table, CakeBaker::BakerId)
.to(Baker::Table, Baker::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade),
)
.to_owned(),
)
.await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table(Table::drop().table(CakeBaker::Table).to_owned())
.await
}
}
#[derive(DeriveIden)]
enum CakeBaker {
Table,
CakeId,
BakerId,
}
#[derive(DeriveIden)]
enum Baker {
Table,
Id,
}
#[derive(DeriveIden)]
enum Cake {
Table,
Id,
}

View File

@ -0,0 +1,195 @@
use crate::entity::{prelude::*, *};
use sea_orm::entity::*;
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
let db = manager.get_connection();
let bakery = bakery::ActiveModel {
name: Set("SeaSide Bakery".to_owned()),
profit_margin: Set(10.4),
..Default::default()
};
let sea = Bakery::insert(bakery).exec(db).await?.last_insert_id;
let bakery = bakery::ActiveModel {
name: Set("LakeSide Bakery".to_owned()),
profit_margin: Set(5.8),
..Default::default()
};
let lake = Bakery::insert(bakery).exec(db).await?.last_insert_id;
let alice = baker::ActiveModel {
name: Set("Alice".to_owned()),
contact: Set("+44 15273388".to_owned()),
bakery_id: Set(Some(sea)),
..Default::default()
};
let alice = Baker::insert(alice).exec(db).await?.last_insert_id;
let bob = baker::ActiveModel {
name: Set("Bob".to_owned()),
contact: Set("+852 12345678".to_owned()),
bakery_id: Set(Some(lake)),
..Default::default()
};
let bob = Baker::insert(bob).exec(db).await?.last_insert_id;
let cake = cake::ActiveModel {
name: Set("Chocolate Cake".to_owned()),
price: Set("10.25".parse().unwrap()),
gluten_free: Set(0),
bakery_id: Set(Some(sea)),
..Default::default()
};
let choco = Cake::insert(cake).exec(db).await?.last_insert_id;
let mut cake = cake::ActiveModel {
name: Set("Double Chocolate".to_owned()),
price: Set("12.5".parse().unwrap()),
gluten_free: Set(0),
bakery_id: Set(Some(sea)),
..Default::default()
};
let double_1 = Cake::insert(cake.clone()).exec(db).await?.last_insert_id;
cake.bakery_id = Set(Some(lake));
let double_2 = Cake::insert(cake).exec(db).await?.last_insert_id;
let mut cake = cake::ActiveModel {
name: Set("Lemon Cake".to_owned()),
price: Set("8.8".parse().unwrap()),
gluten_free: Set(0),
bakery_id: Set(Some(sea)),
..Default::default()
};
let lemon_1 = Cake::insert(cake.clone()).exec(db).await?.last_insert_id;
cake.bakery_id = Set(Some(lake));
let lemon_2 = Cake::insert(cake).exec(db).await?.last_insert_id;
let mut cake = cake::ActiveModel {
name: Set("Strawberry Cake".to_owned()),
price: Set("9.9".parse().unwrap()),
gluten_free: Set(0),
bakery_id: Set(Some(sea)),
..Default::default()
};
let straw_1 = Cake::insert(cake.clone()).exec(db).await?.last_insert_id;
cake.bakery_id = Set(Some(lake));
let straw_2 = Cake::insert(cake).exec(db).await?.last_insert_id;
let cake = cake::ActiveModel {
name: Set("Orange Cake".to_owned()),
price: Set("6.5".parse().unwrap()),
gluten_free: Set(1),
bakery_id: Set(Some(lake)),
..Default::default()
};
let orange = Cake::insert(cake).exec(db).await?.last_insert_id;
let mut cake = cake::ActiveModel {
name: Set("New York Cheese".to_owned()),
price: Set("12.5".parse().unwrap()),
gluten_free: Set(0),
bakery_id: Set(Some(sea)),
..Default::default()
};
let cheese_1 = Cake::insert(cake.clone()).exec(db).await?.last_insert_id;
cake.bakery_id = Set(Some(lake));
let cheese_2 = Cake::insert(cake).exec(db).await?.last_insert_id;
let mut cake = cake::ActiveModel {
name: Set("Blueburry Cheese".to_owned()),
price: Set("11.5".parse().unwrap()),
gluten_free: Set(1),
bakery_id: Set(Some(sea)),
..Default::default()
};
let blue_1 = Cake::insert(cake.clone()).exec(db).await?.last_insert_id;
cake.bakery_id = Set(Some(lake));
let blue_2 = Cake::insert(cake).exec(db).await?.last_insert_id;
let rel = cake_baker::ActiveModel {
cake_id: Set(choco),
baker_id: Set(alice),
};
CakeBaker::insert(rel).exec(db).await?;
let rel = cake_baker::ActiveModel {
cake_id: Set(double_1),
baker_id: Set(alice),
};
CakeBaker::insert(rel).exec(db).await?;
let rel = cake_baker::ActiveModel {
cake_id: Set(double_2),
baker_id: Set(bob),
};
CakeBaker::insert(rel).exec(db).await?;
let rel = cake_baker::ActiveModel {
cake_id: Set(lemon_1),
baker_id: Set(alice),
};
CakeBaker::insert(rel).exec(db).await?;
let rel = cake_baker::ActiveModel {
cake_id: Set(lemon_2),
baker_id: Set(bob),
};
CakeBaker::insert(rel).exec(db).await?;
let rel = cake_baker::ActiveModel {
cake_id: Set(straw_1),
baker_id: Set(alice),
};
CakeBaker::insert(rel).exec(db).await?;
let rel = cake_baker::ActiveModel {
cake_id: Set(straw_2),
baker_id: Set(bob),
};
CakeBaker::insert(rel).exec(db).await?;
let rel = cake_baker::ActiveModel {
cake_id: Set(orange),
baker_id: Set(bob),
};
CakeBaker::insert(rel).exec(db).await?;
let rel = cake_baker::ActiveModel {
cake_id: Set(cheese_1),
baker_id: Set(alice),
};
CakeBaker::insert(rel).exec(db).await?;
let rel = cake_baker::ActiveModel {
cake_id: Set(cheese_2),
baker_id: Set(bob),
};
CakeBaker::insert(rel).exec(db).await?;
let rel = cake_baker::ActiveModel {
cake_id: Set(blue_1),
baker_id: Set(alice),
};
CakeBaker::insert(rel).exec(db).await?;
let rel = cake_baker::ActiveModel {
cake_id: Set(blue_2),
baker_id: Set(bob),
};
CakeBaker::insert(rel).exec(db).await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
let db = manager.get_connection();
Cake::delete_many().exec(db).await?;
Baker::delete_many().exec(db).await?;
Bakery::delete_many().exec(db).await?;
Ok(())
}
}

View File

@ -0,0 +1,6 @@
use sea_orm_migration::prelude::*;
#[async_std::main]
async fn main() {
cli::run_cli(migration::Migrator).await;
}