commit
f11f7e1c19
55
.github/workflows/rust.yml
vendored
55
.github/workflows/rust.yml
vendored
@ -139,3 +139,58 @@ jobs:
|
||||
args: >
|
||||
--all
|
||||
--features default,sqlx-postgres,runtime-${{ matrix.runtime }}
|
||||
|
||||
mysql:
|
||||
name: MySQL
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
# runtime: [async-std-native-tls, async-std-rustls, actix-native-tls, actix-rustls, tokio-native-tls, tokio-rustls]
|
||||
runtime: [async-std-native-tls]
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
env:
|
||||
MYSQL_HOST: 127.0.0.1
|
||||
MYSQL_DB: mysql
|
||||
MYSQL_USER: sea
|
||||
MYSQL_PASSWORD: sea
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
||||
MYSQL_ROOT_PASSWORD:
|
||||
ports:
|
||||
- "3306:3306"
|
||||
options: >-
|
||||
--health-cmd="mysqladmin ping"
|
||||
--health-interval=10s
|
||||
--health-timeout=5s
|
||||
--health-retries=3
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: stable
|
||||
override: true
|
||||
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: ${{ runner.os }}-mysql-${{ matrix.runtime }}-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: >
|
||||
--all
|
||||
--features default,runtime-${{ matrix.runtime }}
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: >
|
||||
--all
|
||||
--features default,sqlx-mysql,runtime-${{ matrix.runtime }}
|
||||
|
108
Cargo.toml
108
Cargo.toml
@ -12,18 +12,24 @@ members = [
|
||||
[package]
|
||||
name = "sea-orm"
|
||||
version = "0.1.0"
|
||||
authors = [ "Chris Tsang <tyt2y7@gmail.com>" ]
|
||||
authors = ["Chris Tsang <tyt2y7@gmail.com>"]
|
||||
edition = "2018"
|
||||
description = "🐚 An async & dynamic ORM for Rust"
|
||||
license = "MIT OR Apache-2.0"
|
||||
documentation = "https://docs.rs/sea-orm"
|
||||
repository = "https://github.com/SeaQL/sea-orm"
|
||||
categories = [ "database" ]
|
||||
keywords = [ "orm", "database", "sql", "mysql", "postgres", "sqlite", "async" ]
|
||||
categories = ["database"]
|
||||
keywords = ["orm", "database", "sql", "mysql", "postgres", "sqlite", "async"]
|
||||
publish = false
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["default", "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", "runtime-async-std-native-tls"]
|
||||
features = [
|
||||
"default",
|
||||
"sqlx-mysql",
|
||||
"sqlx-postgres",
|
||||
"sqlx-sqlite",
|
||||
"runtime-async-std-native-tls",
|
||||
]
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[lib]
|
||||
@ -36,59 +42,75 @@ 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-query = { version = "~0.12.8" }
|
||||
# sea-query = { path = "../sea-query" }
|
||||
sea-orm-macros = { path = "sea-orm-macros", optional = true }
|
||||
sea-orm-codegen = { path = "sea-orm-codegen", optional = true }
|
||||
serde = { version = "^1.0", features = [ "derive" ] }
|
||||
serde = { version = "^1.0", features = ["derive"] }
|
||||
sqlx = { version = "^0.5", optional = true }
|
||||
strum = { git = "https://github.com/SeaQL/strum.git", branch = "sea-orm", version = "^0.21", features = [ "derive", "sea-orm" ] }
|
||||
sqlx-core = { version = "^0.5", optional = true }
|
||||
sqlx-macros = { version = "^0.5", optional = true }
|
||||
strum = { git = "https://github.com/SeaQL/strum.git", branch = "sea-orm", version = "^0.21", features = [
|
||||
"derive",
|
||||
"sea-orm",
|
||||
] }
|
||||
serde_json = { version = "^1", optional = true }
|
||||
uuid = { version = "0.8", features = ["serde", "v4"], optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
async-std = { version = "^1.9", features = [ "attributes" ] }
|
||||
async-std = { version = "^1.9", features = ["attributes"] }
|
||||
tokio = { version = "^1.6", features = ["full"] }
|
||||
actix-rt = { version = "2.2.0" }
|
||||
maplit = { version = "^1" }
|
||||
rust_decimal_macros = { version = "^1" }
|
||||
sea-orm = { path = ".", features = ["sqlx-json", "sqlx-chrono", "sqlx-decimal", "debug-print"] }
|
||||
sea-orm = { path = ".", features = ["debug-print"] }
|
||||
|
||||
[features]
|
||||
debug-print = []
|
||||
default = [ "macros", "codegen", "with-json", "with-chrono", "with-rust_decimal", "mock" ]
|
||||
macros = [ "sea-orm-macros" ]
|
||||
codegen = [ "sea-orm-codegen" ]
|
||||
default = [
|
||||
"macros",
|
||||
"codegen",
|
||||
"with-json",
|
||||
"with-chrono",
|
||||
"with-rust_decimal",
|
||||
"mock",
|
||||
"with-uuid",
|
||||
]
|
||||
macros = ["sea-orm-macros"]
|
||||
codegen = ["sea-orm-codegen"]
|
||||
mock = []
|
||||
with-json = [ "serde_json", "sea-query/with-json" ]
|
||||
with-chrono = [ "chrono", "sea-query/with-chrono" ]
|
||||
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" ]
|
||||
sqlx-decimal = [ "sqlx/decimal", "with-rust_decimal" ]
|
||||
sqlx-mysql = [ "sqlx-dep", "sea-query/sqlx-mysql", "sqlx/mysql" ]
|
||||
sqlx-postgres = [ "sqlx-dep", "sea-query/sqlx-postgres", "sqlx/postgres" ]
|
||||
sqlx-sqlite = [ "sqlx-dep", "sea-query/sqlx-sqlite", "sqlx/sqlite" ]
|
||||
with-json = ["serde_json", "sea-query/with-json", "sqlx-json"]
|
||||
with-chrono = ["chrono", "sea-query/with-chrono", "sqlx-chrono"]
|
||||
with-rust_decimal = [
|
||||
"rust_decimal",
|
||||
"sea-query/with-rust_decimal",
|
||||
"sqlx-decimal",
|
||||
]
|
||||
with-uuid = [
|
||||
"uuid",
|
||||
"sea-query/with-uuid",
|
||||
"sqlx-core/uuid",
|
||||
"sqlx-macros/uuid",
|
||||
]
|
||||
sqlx-dep = ["sqlx"]
|
||||
sqlx-json = ["sqlx/json", "with-json"]
|
||||
sqlx-chrono = ["sqlx/chrono", "with-chrono"]
|
||||
sqlx-decimal = ["sqlx/decimal", "with-rust_decimal"]
|
||||
sqlx-mysql = ["sqlx-dep", "sea-query/sqlx-mysql", "sqlx/mysql"]
|
||||
sqlx-postgres = ["sqlx-dep", "sea-query/sqlx-postgres", "sqlx/postgres"]
|
||||
sqlx-sqlite = ["sqlx-dep", "sea-query/sqlx-sqlite", "sqlx/sqlite"]
|
||||
runtime-async-std = []
|
||||
runtime-async-std-native-tls = [ "sqlx/runtime-async-std-native-tls", "runtime-async-std" ]
|
||||
runtime-async-std-rustls = [ "sqlx/runtime-async-std-rustls", "runtime-async-std" ]
|
||||
runtime-async-std-native-tls = [
|
||||
"sqlx/runtime-async-std-native-tls",
|
||||
"runtime-async-std",
|
||||
]
|
||||
runtime-async-std-rustls = [
|
||||
"sqlx/runtime-async-std-rustls",
|
||||
"runtime-async-std",
|
||||
]
|
||||
runtime-actix = []
|
||||
runtime-actix-native-tls = [ "sqlx/runtime-actix-native-tls", "runtime-actix" ]
|
||||
runtime-actix-rustls = [ "sqlx/runtime-actix-rustls", "runtime-actix" ]
|
||||
runtime-actix-native-tls = ["sqlx/runtime-actix-native-tls", "runtime-actix"]
|
||||
runtime-actix-rustls = ["sqlx/runtime-actix-rustls", "runtime-actix"]
|
||||
runtime-tokio = []
|
||||
runtime-tokio-native-tls = [ "sqlx/runtime-tokio-native-tls", "runtime-tokio" ]
|
||||
runtime-tokio-rustls = [ "sqlx/runtime-tokio-rustls", "runtime-tokio" ]
|
||||
|
||||
[[test]]
|
||||
name = "sqlite-basic"
|
||||
path = "tests/basic.rs"
|
||||
required-features = ["sqlx-sqlite"]
|
||||
|
||||
[[test]]
|
||||
name = "sqlite"
|
||||
path = "tests/bakery_chain_tests.rs"
|
||||
required-features = ["sqlx-sqlite"]
|
||||
|
||||
[[test]]
|
||||
name = "postgres"
|
||||
path = "tests/pg_tests.rs"
|
||||
required-features = ["sqlx-postgres"]
|
||||
runtime-tokio-native-tls = ["sqlx/runtime-tokio-native-tls", "runtime-tokio"]
|
||||
runtime-tokio-rustls = ["sqlx/runtime-tokio-rustls", "runtime-tokio"]
|
||||
|
@ -5,10 +5,10 @@ edition = "2018"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
async-std = { version = "^1.9", features = [ "attributes" ] }
|
||||
async-std = { version = "^1.9", features = ["attributes"] }
|
||||
sea-orm = { path = "../../" }
|
||||
sea-orm-codegen = { path = "../../sea-orm-codegen" }
|
||||
sea-query = { version = "^0.12" }
|
||||
strum = { version = "^0.20", features = [ "derive" ] }
|
||||
sea-query = { version = "~0.12.8" }
|
||||
strum = { version = "^0.20", features = ["derive"] }
|
||||
serde_json = { version = "^1" }
|
||||
quote = { version = "^1" }
|
||||
|
@ -1,14 +1,14 @@
|
||||
[package]
|
||||
name = "sea-orm-codegen"
|
||||
version = "0.1.0"
|
||||
authors = [ "Billy Chan <ccw.billy.123@gmail.com>" ]
|
||||
authors = ["Billy Chan <ccw.billy.123@gmail.com>"]
|
||||
edition = "2018"
|
||||
description = ""
|
||||
license = "MIT OR Apache-2.0"
|
||||
documentation = "https://docs.rs/sea-orm"
|
||||
repository = "https://github.com/SeaQL/sea-orm"
|
||||
categories = [ "database" ]
|
||||
keywords = [ "orm", "database", "sql", "mysql", "postgres", "sqlite" ]
|
||||
categories = ["database"]
|
||||
keywords = ["orm", "database", "sql", "mysql", "postgres", "sqlite"]
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
@ -16,16 +16,25 @@ name = "sea_orm_codegen"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
sea-schema = { version = "^0.2", default-features = false, features = [ "sqlx-mysql", "discovery", "writer" ] }
|
||||
sea-query = { version = "^0.12" }
|
||||
sqlx = { version = "^0.5", default-features = false, features = [ "mysql" ] }
|
||||
syn = { version = "^1", default-features = false, features = [ "derive", "parsing", "proc-macro", "printing" ] }
|
||||
sea-schema = { version = "^0.2", default-features = false, features = [
|
||||
"sqlx-mysql",
|
||||
"discovery",
|
||||
"writer",
|
||||
] }
|
||||
sea-query = { version = "~0.12.8" }
|
||||
sqlx = { version = "^0.5", default-features = false, features = ["mysql"] }
|
||||
syn = { version = "^1", default-features = false, features = [
|
||||
"derive",
|
||||
"parsing",
|
||||
"proc-macro",
|
||||
"printing",
|
||||
] }
|
||||
quote = "^1"
|
||||
heck = "^0.3"
|
||||
proc-macro2 = "^1"
|
||||
|
||||
[dev-dependencies]
|
||||
async-std = { version = "^1.9", features = [ "attributes" ] }
|
||||
async-std = { version = "^1.9", features = ["attributes"] }
|
||||
sea-orm = { path = "../" }
|
||||
|
||||
[features]
|
||||
|
@ -32,6 +32,7 @@ impl Column {
|
||||
| ColumnType::Date
|
||||
| ColumnType::Json
|
||||
| ColumnType::JsonBinary
|
||||
| ColumnType::Uuid
|
||||
| ColumnType::Custom(_) => "String",
|
||||
ColumnType::TinyInteger(_) => "i8",
|
||||
ColumnType::SmallInteger(_) => "i16",
|
||||
@ -83,6 +84,7 @@ impl Column {
|
||||
},
|
||||
ColumnType::Json => quote! { ColumnType::Json.def() },
|
||||
ColumnType::JsonBinary => quote! { ColumnType::JsonBinary.def() },
|
||||
ColumnType::Uuid => quote! { ColumnType::Uuid.def() },
|
||||
ColumnType::Custom(s) => {
|
||||
let s = s.to_string();
|
||||
quote! { ColumnType::Custom(#s.to_owned()).def() }
|
||||
|
@ -31,6 +31,7 @@ pub enum ColumnType {
|
||||
Json,
|
||||
JsonBinary,
|
||||
Custom(String),
|
||||
Uuid,
|
||||
}
|
||||
|
||||
macro_rules! bind_oper {
|
||||
@ -270,6 +271,7 @@ impl From<ColumnType> for sea_query::ColumnType {
|
||||
ColumnType::Custom(s) => {
|
||||
sea_query::ColumnType::Custom(sea_query::SeaRc::new(sea_query::Alias::new(&s)))
|
||||
}
|
||||
ColumnType::Uuid => sea_query::ColumnType::Uuid,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -297,6 +299,7 @@ impl From<sea_query::ColumnType> for ColumnType {
|
||||
sea_query::ColumnType::Json => Self::Json,
|
||||
sea_query::ColumnType::JsonBinary => Self::JsonBinary,
|
||||
sea_query::ColumnType::Custom(s) => Self::Custom(s.to_string()),
|
||||
sea_query::ColumnType::Uuid => Self::Uuid,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::DbErr;
|
||||
use chrono::NaiveDateTime;
|
||||
use serde_json::Value as Json;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -254,6 +255,13 @@ try_getable_all!(f32);
|
||||
try_getable_all!(f64);
|
||||
try_getable_all!(String);
|
||||
try_getable_all!(NaiveDateTime);
|
||||
try_getable_all!(Json);
|
||||
|
||||
#[cfg(feature = "with-uuid")]
|
||||
use uuid::Uuid;
|
||||
|
||||
#[cfg(feature = "with-uuid")]
|
||||
try_getable_all!(Uuid);
|
||||
|
||||
#[cfg(feature = "with-rust_decimal")]
|
||||
use rust_decimal::Decimal;
|
||||
|
@ -1 +0,0 @@
|
||||
<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>
|
Binary file not shown.
Before Width: | Height: | Size: 50 KiB |
@ -1,37 +1,34 @@
|
||||
use sea_orm::DbConn;
|
||||
use sea_orm::DatabaseConnection;
|
||||
|
||||
pub mod common;
|
||||
pub use common::{bakery_chain::*, setup::*, TestContext};
|
||||
|
||||
pub mod bakery_chain;
|
||||
mod setup;
|
||||
pub use bakery_chain::*;
|
||||
mod crud;
|
||||
mod schema;
|
||||
|
||||
// cargo test --test bakery_chain_tests -- --nocapture
|
||||
#[cfg_attr(feature = "runtime-async-std", async_std::main)]
|
||||
#[cfg_attr(feature = "runtime-actix", actix_rt::main)]
|
||||
#[cfg_attr(feature = "runtime-tokio", tokio::main)]
|
||||
#[cfg(feature = "sqlx-sqlite")]
|
||||
#[async_std::test]
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
async fn main() {
|
||||
let db: DbConn = setup::setup().await;
|
||||
setup_schema(&db).await;
|
||||
let base_url = "mysql://root:@localhost";
|
||||
let db_name = "bakery_chain_schema_crud_tests";
|
||||
|
||||
let db: DatabaseConnection = common::setup::setup(base_url, db_name).await;
|
||||
create_entities(&db).await;
|
||||
common::setup::tear_down(base_url, db_name).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) {
|
||||
async fn create_entities(db: &DatabaseConnection) {
|
||||
crud::test_create_bakery(db).await;
|
||||
crud::test_create_baker(db).await;
|
||||
crud::create_baker::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;
|
||||
|
||||
crud::updates::test_update_cake(db).await;
|
||||
crud::updates::test_update_bakery(db).await;
|
||||
crud::updates::test_update_deleted_customer(db).await;
|
||||
|
||||
crud::deletes::test_delete_cake(db).await;
|
||||
crud::deletes::test_delete_bakery(db).await;
|
||||
}
|
||||
|
@ -3,9 +3,9 @@ use sea_orm::{entity::*, error::*, sea_query, tests_cfg::*, DbBackend, DbConn, S
|
||||
mod setup;
|
||||
|
||||
// cargo test --test basic -- --nocapture
|
||||
#[cfg_attr(feature = "runtime-async-std", async_std::main)]
|
||||
#[cfg_attr(feature = "runtime-actix", actix_rt::main)]
|
||||
#[cfg_attr(feature = "runtime-tokio", tokio::main)]
|
||||
#[cfg_attr(feature = "runtime-async-std", async_std::test)]
|
||||
#[cfg_attr(feature = "runtime-actix", actix_rt::test)]
|
||||
#[cfg_attr(feature = "runtime-tokio", tokio::test)]
|
||||
#[cfg(feature = "sqlx-sqlite")]
|
||||
async fn main() {
|
||||
let db: DbConn = setup::setup().await;
|
||||
|
@ -1,4 +1,5 @@
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde_json::Value as Json;
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||
pub struct Entity;
|
||||
@ -13,6 +14,7 @@ impl EntityName for Entity {
|
||||
pub struct Model {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub contact_details: Json,
|
||||
pub bakery_id: Option<i32>,
|
||||
}
|
||||
|
||||
@ -20,6 +22,7 @@ pub struct Model {
|
||||
pub enum Column {
|
||||
Id,
|
||||
Name,
|
||||
ContactDetails,
|
||||
BakeryId,
|
||||
}
|
||||
|
||||
@ -46,6 +49,7 @@ impl ColumnTrait for Column {
|
||||
match self {
|
||||
Self::Id => ColumnType::Integer.def(),
|
||||
Self::Name => ColumnType::String(None).def(),
|
||||
Self::ContactDetails => ColumnType::Json.def(),
|
||||
Self::BakeryId => ColumnType::Integer.def(),
|
||||
}
|
||||
}
|
1
tests/common/bakery_chain/bakery_chain_erd.drawio
Normal file
1
tests/common/bakery_chain/bakery_chain_erd.drawio
Normal file
@ -0,0 +1 @@
|
||||
<mxfile host="Electron" modified="2021-07-24T10:17:39.768Z" 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="-nL14gemvUpu6Q8vDMJo" version="14.6.13" type="device"><diagram id="R2lEEEUBdFMjLlhIrx00" name="Page-1">7Z1tc9o4EIB/DR+bMX7DfAwk6csld52knTafMootQBfb4mxRoL/+VrGEwVICwdhOZzST6aBFyLKeXXl3vXZ7zjhZfczQfHZDIxz3bCta9ZyLnm0PXR/+5YJ1IegHllNIphmJhKwU3JHfWAgtIV2QCOc7HRmlMSPzXWFI0xSHbEeGsowud7tNaLx71DmaYkVwF6JYlf4gEZsV0sCzSvknTKYzeeS+Jb5JkOwsBPkMRXS5I8IrdkVTJqb4FWcJSnHK4JsblD3hrOddzhjjZ3res6/gb8J7n00pncYYzUl+FtIExGEOXa4mKCExX+etgUZiIDicc9lzxhmlrPiUrMY45qwkhmJOVy98u1mHjI97wA+eRqv8/skNv4zSYPhj9uFptv73gxjlF4oXYn1H539d3t6DbPzp/PPfYqXYWi4/gyXqOaMZS2IQ9OFjzjL6hMc0phlIUppCz9GExHFFhGIyTaEZwnxhAZzRL5wxAmDPxRcJiSJ+mNFyRhi+m6OQH3MJagyyjC7SCPNTsfjwsOxCNR1btsUkNQsjzxIOiFdbIrFQHzFNMMvW0EV8a7tCIYSVfBj6QrAsdc4ZCNlsS9+kHiKhQ9PN2CUa+CDovIWUp6JCoElrBVG+JEmMCgxb68LXLZyROLpGa7rg080ZCp9kazSjGfkN/VEJFmVylW1/p8cd/6UYM8M59Pkql7tfEd2g1U7Ha5QzORsax2iek0fBzRklKJuSdEQZAzMqOilqs8W+70L7BLgdp4I70ODuuxrctuU3xdtXePP+sO9Yn2ElpsUeorPNQw0yBwsj6fQaT/jJuKXkVpwfF1FYxUn8vE3OwD5x+myLDDH0uNGqOSViz/RG8AfLNLbOvJ4HcxpDu1+24Y93z9iYpjBNRJ6RYVCJJeZqsQPX1sJ93Tj2IxeIbf8wwE5j9jxQ+KYowQXhO5YBBwO4BmCvc8CBAviRb9i5wVoDa9A11sBWsNIsMljrYe33u+baHypcQzBXg7UWVrdrrIF6mZ1ndELYQ+FrFtfbq5giZkjXIT3omrStiWXRk8ZNNvHRW+Mjb3BsfLRRi9PjVq/DJj7aaxt/TnxkOyY+ahJw5/HRUE1ohXzzDNlDhBkicZFltb7kNDWka5DuPGSyXYX0oz51abD+SSGTrbFgEzLVxdp5yGSrmecxYDV+dH0/unqfwQs0frSngW37jfnRaoBs/Oi9plHLj9YBbs6a1TS08aNPCFjnR7cK2FcTl/OMhILwDSAyflYdwDr3uVXAA3WHNu5zbaxa97lVrnJgc4PwpFx1/nO79qpmJmMCYOBnDCeGbi26utsMrdIN1OhoGi8YTh8mGRYX3RGlMUYma1XLcba6Jj1UM9A5zgiPWznk798/XxjCdQg7XRN21SuwQhRHUyxTGzh+pMvLUqCs1VZZLE6jc17uDM3L2wSla5npUKSwrtn65+Zn0LjnVAGXaF7IzEbRWouWCkYkJHK6yEL8GiuRuIPpTPFrUOXK80V4Fek2QkuDcCPMcIwY+YV3JqwDK47xlSt2mUFxbe9MTF7mUFyroh7F6YsflhqijOWpY3nVsYoVUsYChmi91U2Y34vTHki13hzI3ynWhg/FkKUubxa3hnqrjkh76i13OC67InziNZVW1tPtVVp5u+HdKK3jW1VFG1T3tEOV1lXHCqpjvaC0J1Mr9br4D6+AU3TLJIgPviTKb/3KPuHLx262ddXW6GpzheiBepE0CeK9tlErQawD3JwTZO7ONoBVlxZuF6vm5uwih+3M2GstsLp0cKtgB6q9MspkVGry/XUBaxPD7ZqummIyCcRT0dWlh1ulG2ju18UoxNEDYoUNXyCGv5FErbgwoGtmilsF7auO83VpxiZaqh0tKY/tOrpyGm1k31hZuq8+hWCipb0WUita0gFuzvtSr82hrjjOQK0XK7UK1VcTpaaE5oSAdTFTu4DVlOV/C5QywtZmbz4VZW3g1O7mrF58aZGZhpk5/fL+gyF8HGFd8NSuIavJj/FLWS3jUNd2qLW3H7QOtduYQ63mMY1Dvdc8/iCHWuVr6tNPCLh751qNmMwLU2pj7dylDjTPZ1OGxUO73zhKw/d4vt0707764JBC9JTVQ3hF2E9BjH/eKoKDVlkDxxv1S+DkrrS3mkjeR30/1URBxUlzhsfWElVHcqsjNVxJJF8r0raK9d+gYpvqzE2j6epM91DVlOGuUc0GVLOj3e99q6Z8Sdp+1Ry8N9WsvsLIPboCszqS13L9ZaBmuZpVzSPVrN0Lunwv4/4L+nsrD7are93g2Ip2VTWrr6M+UT17X0kU7b58vJl69uFbFf85wX/7TIemNSzgeK0cHKqV8r7iu9FKp/oKdKeqSwdrZXUk90Ct3K830CxfoF90L//XA+fyfw==</diagram></mxfile>
|
BIN
tests/common/bakery_chain/bakery_chain_erd.jpg
Normal file
BIN
tests/common/bakery_chain/bakery_chain_erd.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 52 KiB |
@ -1,5 +1,6 @@
|
||||
use rust_decimal::prelude::*;
|
||||
use sea_orm::entity::prelude::*;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||
pub struct Entity;
|
||||
@ -17,6 +18,7 @@ pub struct Model {
|
||||
pub price: Decimal,
|
||||
pub bakery_id: Option<i32>,
|
||||
pub gluten_free: bool,
|
||||
pub serial: Uuid,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
@ -26,6 +28,7 @@ pub enum Column {
|
||||
Price,
|
||||
BakeryId,
|
||||
GlutenFree,
|
||||
Serial,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||
@ -55,6 +58,7 @@ impl ColumnTrait for Column {
|
||||
Self::Price => ColumnType::Decimal(Some((19, 4))).def(),
|
||||
Self::BakeryId => ColumnType::Integer.def(),
|
||||
Self::GlutenFree => ColumnType::Boolean.def(),
|
||||
Self::Serial => ColumnType::String(None).def(),
|
||||
}
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ impl EntityName for Entity {
|
||||
pub struct Model {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub notes: String,
|
||||
pub notes: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
26
tests/common/mod.rs
Normal file
26
tests/common/mod.rs
Normal file
@ -0,0 +1,26 @@
|
||||
pub mod setup;
|
||||
use sea_orm::DatabaseConnection;
|
||||
pub mod bakery_chain;
|
||||
pub use bakery_chain::*;
|
||||
|
||||
pub struct TestContext {
|
||||
base_url: String,
|
||||
db_name: String,
|
||||
pub db: DatabaseConnection,
|
||||
}
|
||||
|
||||
impl TestContext {
|
||||
pub async fn new(base_url: &str, db_name: &str) -> Self {
|
||||
let db: DatabaseConnection = setup::setup(base_url, db_name).await;
|
||||
|
||||
Self {
|
||||
base_url: base_url.to_string(),
|
||||
db_name: db_name.to_string(),
|
||||
db,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn delete(&self) {
|
||||
setup::tear_down(&self.base_url, &self.db_name).await;
|
||||
}
|
||||
}
|
44
tests/common/setup/mod.rs
Normal file
44
tests/common/setup/mod.rs
Normal file
@ -0,0 +1,44 @@
|
||||
use sea_orm::{Database, DatabaseBackend, DatabaseConnection, Statement};
|
||||
pub mod schema;
|
||||
pub use schema::*;
|
||||
|
||||
pub async fn setup(base_url: &str, db_name: &str) -> DatabaseConnection {
|
||||
let url = format!("{}/mysql", base_url);
|
||||
let db = Database::connect(&url).await.unwrap();
|
||||
let _drop_db_result = db
|
||||
.execute(Statement::from_string(
|
||||
DatabaseBackend::MySql,
|
||||
format!("DROP DATABASE IF EXISTS `{}`;", db_name),
|
||||
))
|
||||
.await;
|
||||
|
||||
let _create_db_result = db
|
||||
.execute(Statement::from_string(
|
||||
DatabaseBackend::MySql,
|
||||
format!("CREATE DATABASE `{}`;", db_name),
|
||||
))
|
||||
.await;
|
||||
|
||||
let url = format!("{}/{}", base_url, db_name);
|
||||
let db = Database::connect(&url).await.unwrap();
|
||||
|
||||
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_cake_table(&db).await.is_ok());
|
||||
assert!(schema::create_cakes_bakers_table(&db).await.is_ok());
|
||||
assert!(schema::create_lineitem_table(&db).await.is_ok());
|
||||
db
|
||||
}
|
||||
|
||||
pub async fn tear_down(base_url: &str, db_name: &str) {
|
||||
let url = format!("{}/mysql", base_url);
|
||||
let db = Database::connect(&url).await.unwrap();
|
||||
let _drop_db_result = db
|
||||
.execute(Statement::from_string(
|
||||
DatabaseBackend::MySql,
|
||||
format!("DROP DATABASE IF EXISTS `{}`;", db_name),
|
||||
))
|
||||
.await;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
use sea_orm::{error::*, sea_query, DbConn, ExecResult};
|
||||
use sea_query::{ColumnDef, ForeignKey, ForeignKeyAction, Index, TableCreateStatement};
|
||||
|
||||
pub use super::bakery_chain::*;
|
||||
pub use super::super::bakery_chain::*;
|
||||
|
||||
async fn create_table(db: &DbConn, stmt: &TableCreateStatement) -> Result<ExecResult, DbErr> {
|
||||
let builder = db.get_database_backend();
|
||||
@ -20,7 +20,7 @@ pub async fn create_bakery_table(db: &DbConn) -> Result<ExecResult, DbErr> {
|
||||
.primary_key(),
|
||||
)
|
||||
.col(ColumnDef::new(bakery::Column::Name).string())
|
||||
.col(ColumnDef::new(bakery::Column::ProfitMargin).float())
|
||||
.col(ColumnDef::new(bakery::Column::ProfitMargin).double())
|
||||
.to_owned();
|
||||
|
||||
create_table(db, &stmt).await
|
||||
@ -38,6 +38,7 @@ pub async fn create_baker_table(db: &DbConn) -> Result<ExecResult, DbErr> {
|
||||
.primary_key(),
|
||||
)
|
||||
.col(ColumnDef::new(baker::Column::Name).string())
|
||||
.col(ColumnDef::new(baker::Column::ContactDetails).json())
|
||||
.col(ColumnDef::new(baker::Column::BakeryId).integer())
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
@ -81,7 +82,7 @@ pub async fn create_order_table(db: &DbConn) -> Result<ExecResult, DbErr> {
|
||||
.auto_increment()
|
||||
.primary_key(),
|
||||
)
|
||||
.col(ColumnDef::new(order::Column::Total).float())
|
||||
.col(ColumnDef::new(order::Column::Total).decimal_len(19, 4))
|
||||
.col(ColumnDef::new(order::Column::BakeryId).integer().not_null())
|
||||
.col(
|
||||
ColumnDef::new(order::Column::CustomerId)
|
||||
@ -125,7 +126,7 @@ pub async fn create_lineitem_table(db: &DbConn) -> Result<ExecResult, DbErr> {
|
||||
.auto_increment()
|
||||
.primary_key(),
|
||||
)
|
||||
.col(ColumnDef::new(lineitem::Column::Price).decimal())
|
||||
.col(ColumnDef::new(lineitem::Column::Price).decimal_len(19, 4))
|
||||
.col(ColumnDef::new(lineitem::Column::Quantity).integer())
|
||||
.col(
|
||||
ColumnDef::new(lineitem::Column::OrderId)
|
||||
@ -194,7 +195,7 @@ pub async fn create_cake_table(db: &DbConn) -> Result<ExecResult, DbErr> {
|
||||
.primary_key(),
|
||||
)
|
||||
.col(ColumnDef::new(cake::Column::Name).string())
|
||||
.col(ColumnDef::new(cake::Column::Price).float())
|
||||
.col(ColumnDef::new(cake::Column::Price).decimal_len(19, 4))
|
||||
.col(ColumnDef::new(cake::Column::BakeryId).integer().not_null())
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
@ -205,6 +206,7 @@ pub async fn create_cake_table(db: &DbConn) -> Result<ExecResult, DbErr> {
|
||||
.on_update(ForeignKeyAction::Cascade),
|
||||
)
|
||||
.col(ColumnDef::new(cake::Column::GlutenFree).boolean())
|
||||
.col(ColumnDef::new(cake::Column::Serial).uuid())
|
||||
.to_owned();
|
||||
|
||||
create_table(db, &stmt).await
|
79
tests/crud/create_baker.rs
Normal file
79
tests/crud/create_baker.rs
Normal file
@ -0,0 +1,79 @@
|
||||
pub use super::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
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");
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct ContactDetails {
|
||||
mobile: String,
|
||||
home: String,
|
||||
address: String,
|
||||
}
|
||||
|
||||
let baker_bob_contact = ContactDetails {
|
||||
mobile: "+61424000000".to_owned(),
|
||||
home: "0395555555".to_owned(),
|
||||
address: "12 Test St, Testville, Vic, Australia".to_owned(),
|
||||
};
|
||||
let baker_bob = baker::ActiveModel {
|
||||
name: Set("Baker Bob".to_owned()),
|
||||
contact_details: Set(serde_json::json!(baker_bob_contact)),
|
||||
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.contact_details["mobile"],
|
||||
baker_bob_contact.mobile
|
||||
);
|
||||
assert_eq!(baker_model.contact_details["home"], baker_bob_contact.home);
|
||||
assert_eq!(
|
||||
baker_model.contact_details["address"],
|
||||
baker_bob_contact.address
|
||||
);
|
||||
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")
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
pub use super::*;
|
||||
use rust_decimal_macros::dec;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub async fn test_create_cake(db: &DbConn) {
|
||||
let seaside_bakery = bakery::ActiveModel {
|
||||
@ -14,6 +15,11 @@ pub async fn test_create_cake(db: &DbConn) {
|
||||
|
||||
let baker_bob = baker::ActiveModel {
|
||||
name: Set("Baker Bob".to_owned()),
|
||||
contact_details: Set(serde_json::json!({
|
||||
"mobile": "+61424000000",
|
||||
"home": "0395555555",
|
||||
"address": "12 Test St, Testville, Vic, Australia"
|
||||
})),
|
||||
bakery_id: Set(Some(bakery_insert_res.last_insert_id as i32)),
|
||||
..Default::default()
|
||||
};
|
||||
@ -21,11 +27,13 @@ pub async fn test_create_cake(db: &DbConn) {
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert baker");
|
||||
let uuid = Uuid::new_v4();
|
||||
|
||||
let mud_cake = cake::ActiveModel {
|
||||
name: Set("Mud Cake".to_owned()),
|
||||
price: Set(dec!(10.25)),
|
||||
gluten_free: Set(false),
|
||||
serial: Set(uuid),
|
||||
bakery_id: Set(Some(bakery_insert_res.last_insert_id as i32)),
|
||||
..Default::default()
|
||||
};
|
||||
@ -65,6 +73,7 @@ pub async fn test_create_cake(db: &DbConn) {
|
||||
.name,
|
||||
"SeaSide Bakery"
|
||||
);
|
||||
assert_eq!(cake_model.serial, uuid);
|
||||
|
||||
let related_bakers: Vec<baker::Model> = cake_model
|
||||
.find_related(Baker)
|
||||
|
@ -1,6 +1,7 @@
|
||||
pub use super::*;
|
||||
use chrono::offset::Utc;
|
||||
use rust_decimal_macros::dec;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub async fn test_create_lineitem(db: &DbConn) {
|
||||
// Bakery
|
||||
@ -17,6 +18,11 @@ pub async fn test_create_lineitem(db: &DbConn) {
|
||||
// Baker
|
||||
let baker_bob = baker::ActiveModel {
|
||||
name: Set("Baker Bob".to_owned()),
|
||||
contact_details: Set(serde_json::json!({
|
||||
"mobile": "+61424000000",
|
||||
"home": "0395555555",
|
||||
"address": "12 Test St, Testville, Vic, Australia"
|
||||
})),
|
||||
bakery_id: Set(Some(bakery_insert_res.last_insert_id as i32)),
|
||||
..Default::default()
|
||||
};
|
||||
@ -30,6 +36,7 @@ pub async fn test_create_lineitem(db: &DbConn) {
|
||||
name: Set("Mud Cake".to_owned()),
|
||||
price: Set(dec!(10.25)),
|
||||
gluten_free: Set(false),
|
||||
serial: Set(Uuid::new_v4()),
|
||||
bakery_id: Set(Some(bakery_insert_res.last_insert_id as i32)),
|
||||
..Default::default()
|
||||
};
|
||||
@ -53,7 +60,7 @@ pub async fn test_create_lineitem(db: &DbConn) {
|
||||
// Customer
|
||||
let customer_kate = customer::ActiveModel {
|
||||
name: Set("Kate".to_owned()),
|
||||
notes: Set("Loves cheese cake".to_owned()),
|
||||
notes: Set(Some("Loves cheese cake".to_owned())),
|
||||
..Default::default()
|
||||
};
|
||||
let customer_insert_res: InsertResult = Customer::insert(customer_kate)
|
||||
@ -65,6 +72,7 @@ pub async fn test_create_lineitem(db: &DbConn) {
|
||||
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!(7.55)),
|
||||
placed_at: Set(Utc::now().naive_utc()),
|
||||
..Default::default()
|
||||
};
|
||||
@ -78,6 +86,7 @@ pub async fn test_create_lineitem(db: &DbConn) {
|
||||
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(1),
|
||||
..Default::default()
|
||||
};
|
||||
let lineitem_insert_res: InsertResult = Lineitem::insert(lineitem_1)
|
||||
|
@ -1,6 +1,7 @@
|
||||
pub use super::*;
|
||||
use chrono::offset::Utc;
|
||||
use rust_decimal_macros::dec;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub async fn test_create_order(db: &DbConn) {
|
||||
// Bakery
|
||||
@ -17,6 +18,11 @@ pub async fn test_create_order(db: &DbConn) {
|
||||
// Baker
|
||||
let baker_bob = baker::ActiveModel {
|
||||
name: Set("Baker Bob".to_owned()),
|
||||
contact_details: Set(serde_json::json!({
|
||||
"mobile": "+61424000000",
|
||||
"home": "0395555555",
|
||||
"address": "12 Test St, Testville, Vic, Australia"
|
||||
})),
|
||||
bakery_id: Set(Some(bakery_insert_res.last_insert_id as i32)),
|
||||
..Default::default()
|
||||
};
|
||||
@ -30,6 +36,7 @@ pub async fn test_create_order(db: &DbConn) {
|
||||
name: Set("Mud Cake".to_owned()),
|
||||
price: Set(dec!(10.25)),
|
||||
gluten_free: Set(false),
|
||||
serial: Set(Uuid::new_v4()),
|
||||
bakery_id: Set(Some(bakery_insert_res.last_insert_id as i32)),
|
||||
..Default::default()
|
||||
};
|
||||
@ -53,7 +60,7 @@ pub async fn test_create_order(db: &DbConn) {
|
||||
// Customer
|
||||
let customer_kate = customer::ActiveModel {
|
||||
name: Set("Kate".to_owned()),
|
||||
notes: Set("Loves cheese cake".to_owned()),
|
||||
notes: Set(Some("Loves cheese cake".to_owned())),
|
||||
..Default::default()
|
||||
};
|
||||
let customer_insert_res: InsertResult = Customer::insert(customer_kate)
|
||||
|
61
tests/crud/deletes.rs
Normal file
61
tests/crud/deletes.rs
Normal file
@ -0,0 +1,61 @@
|
||||
pub use super::*;
|
||||
use rust_decimal_macros::dec;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub async fn test_delete_cake(db: &DbConn) {
|
||||
let initial_cakes = Cake::find().all(db).await.unwrap().len();
|
||||
|
||||
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 mud_cake = cake::ActiveModel {
|
||||
name: Set("Mud Cake".to_owned()),
|
||||
price: Set(dec!(10.25)),
|
||||
gluten_free: Set(false),
|
||||
serial: Set(Uuid::new_v4()),
|
||||
bakery_id: Set(Some(bakery_insert_res.last_insert_id as i32)),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let cake = mud_cake.save(db).await.expect("could not insert cake");
|
||||
|
||||
let cakes = Cake::find().all(db).await.unwrap();
|
||||
assert_eq!(cakes.len(), initial_cakes + 1);
|
||||
|
||||
let _result = cake.delete(db).await.expect("failed to delete cake");
|
||||
|
||||
let cakes = Cake::find().all(db).await.unwrap();
|
||||
assert_eq!(cakes.len(), initial_cakes);
|
||||
}
|
||||
|
||||
pub async fn test_delete_bakery(db: &DbConn) {
|
||||
let initial_bakeries = Bakery::find().all(db).await.unwrap().len();
|
||||
|
||||
let bakery = bakery::ActiveModel {
|
||||
name: Set("SeaSide Bakery".to_owned()),
|
||||
profit_margin: Set(10.4),
|
||||
..Default::default()
|
||||
}
|
||||
.save(db)
|
||||
.await
|
||||
.expect("could not insert bakery");
|
||||
|
||||
assert_eq!(
|
||||
Bakery::find().all(db).await.unwrap().len(),
|
||||
initial_bakeries + 1
|
||||
);
|
||||
|
||||
let _result = bakery.delete(db).await.expect("failed to delete bakery");
|
||||
|
||||
assert_eq!(
|
||||
Bakery::find().all(db).await.unwrap().len(),
|
||||
initial_bakeries
|
||||
);
|
||||
}
|
@ -1,10 +1,13 @@
|
||||
use sea_orm::{entity::*, DbConn, InsertResult};
|
||||
|
||||
pub use super::bakery_chain::*;
|
||||
pub use super::common::bakery_chain::*;
|
||||
|
||||
pub mod create_baker;
|
||||
pub mod create_cake;
|
||||
pub mod create_lineitem;
|
||||
pub mod create_order;
|
||||
pub mod deletes;
|
||||
pub mod updates;
|
||||
|
||||
pub async fn test_create_bakery(db: &DbConn) {
|
||||
let seaside_bakery = bakery::ActiveModel {
|
||||
@ -28,65 +31,10 @@ pub async fn test_create_bakery(db: &DbConn) {
|
||||
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()),
|
||||
notes: Set(Some("Loves cheese cake".to_owned())),
|
||||
..Default::default()
|
||||
};
|
||||
let res: InsertResult = Customer::insert(customer_kate)
|
||||
@ -102,5 +50,5 @@ pub async fn test_create_customer(db: &DbConn) {
|
||||
assert!(customer.is_some());
|
||||
let customer_model = customer.unwrap();
|
||||
assert_eq!(customer_model.name, "Kate");
|
||||
assert_eq!(customer_model.notes, "Loves cheese cake");
|
||||
assert_eq!(customer_model.notes, Some("Loves cheese cake".to_owned()));
|
||||
}
|
||||
|
139
tests/crud/updates.rs
Normal file
139
tests/crud/updates.rs
Normal file
@ -0,0 +1,139 @@
|
||||
pub use super::*;
|
||||
use rust_decimal_macros::dec;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub async fn test_update_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 mud_cake = cake::ActiveModel {
|
||||
name: Set("Mud Cake".to_owned()),
|
||||
price: Set(dec!(10.25)),
|
||||
gluten_free: Set(false),
|
||||
serial: Set(Uuid::new_v4()),
|
||||
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");
|
||||
|
||||
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);
|
||||
|
||||
let mut cake_am: cake::ActiveModel = cake_model.into();
|
||||
cake_am.name = Set("Extra chocolate mud cake".to_owned());
|
||||
cake_am.price = Set(dec!(20.00));
|
||||
|
||||
let _cake_update_res: cake::ActiveModel = Cake::update(cake_am)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not update 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_model = cake.unwrap();
|
||||
assert_eq!(cake_model.name, "Extra chocolate mud cake");
|
||||
assert_eq!(cake_model.price, dec!(20.00));
|
||||
}
|
||||
|
||||
pub async fn test_update_bakery(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 bakery: Option<bakery::Model> = Bakery::find_by_id(bakery_insert_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);
|
||||
|
||||
let mut bakery_am: bakery::ActiveModel = bakery_model.into();
|
||||
bakery_am.name = Set("SeaBreeze Bakery".to_owned());
|
||||
bakery_am.profit_margin = Set(12.00);
|
||||
|
||||
let _bakery_update_res: bakery::ActiveModel = Bakery::update(bakery_am)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not update bakery");
|
||||
|
||||
let bakery: Option<bakery::Model> = Bakery::find_by_id(bakery_insert_res.last_insert_id)
|
||||
.one(db)
|
||||
.await
|
||||
.expect("could not find bakery");
|
||||
let bakery_model = bakery.unwrap();
|
||||
assert_eq!(bakery_model.name, "SeaBreeze Bakery");
|
||||
assert_eq!(bakery_model.profit_margin, 12.00);
|
||||
}
|
||||
|
||||
pub async fn test_update_deleted_customer(db: &DbConn) {
|
||||
let init_n_customers = Customer::find().count(db).await.unwrap();
|
||||
|
||||
let customer = customer::ActiveModel {
|
||||
name: Set("John".to_owned()),
|
||||
notes: Set(None),
|
||||
..Default::default()
|
||||
}
|
||||
.save(db)
|
||||
.await
|
||||
.expect("could not insert customer");
|
||||
|
||||
assert_eq!(
|
||||
Customer::find().count(db).await.unwrap(),
|
||||
init_n_customers + 1
|
||||
);
|
||||
|
||||
let customer_id = customer.id.clone();
|
||||
|
||||
let _ = customer.delete(db).await;
|
||||
assert_eq!(Customer::find().count(db).await.unwrap(), init_n_customers);
|
||||
|
||||
let customer = customer::ActiveModel {
|
||||
id: customer_id.clone(),
|
||||
name: Set("John 2".to_owned()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let _customer_update_res: customer::ActiveModel = Customer::update(customer)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not update customer");
|
||||
|
||||
assert_eq!(Customer::find().count(db).await.unwrap(), init_n_customers);
|
||||
|
||||
let customer: Option<customer::Model> = Customer::find_by_id(customer_id.clone().unwrap())
|
||||
.one(db)
|
||||
.await
|
||||
.expect("could not find customer");
|
||||
|
||||
assert_eq!(customer, None);
|
||||
}
|
@ -3,14 +3,15 @@ use sea_orm::{
|
||||
Statement,
|
||||
};
|
||||
|
||||
pub mod bakery_chain;
|
||||
pub use bakery_chain::*;
|
||||
pub mod common;
|
||||
pub use common::bakery_chain::*;
|
||||
|
||||
use sea_query::{ColumnDef, TableCreateStatement};
|
||||
|
||||
// cargo test --test pg_tests -- --nocapture
|
||||
#[cfg_attr(feature = "runtime-async-std", async_std::main)]
|
||||
#[cfg_attr(feature = "runtime-actix", actix_rt::main)]
|
||||
#[cfg_attr(feature = "runtime-tokio", tokio::main)]
|
||||
#[cfg_attr(feature = "runtime-async-std", async_std::test)]
|
||||
#[cfg_attr(feature = "runtime-actix", actix_rt::test)]
|
||||
#[cfg_attr(feature = "runtime-tokio", tokio::test)]
|
||||
#[cfg(feature = "sqlx-postgres")]
|
||||
async fn main() {
|
||||
let base_url = "postgres://root:root@localhost";
|
||||
|
183
tests/query_tests.rs
Normal file
183
tests/query_tests.rs
Normal file
@ -0,0 +1,183 @@
|
||||
// cargo test --test query_tests -- --nocapture
|
||||
use sea_orm::entity::*;
|
||||
use sea_orm::QueryFilter;
|
||||
|
||||
pub mod common;
|
||||
pub use common::{bakery_chain::*, setup::*, TestContext};
|
||||
|
||||
#[async_std::test]
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
pub async fn find_one_with_no_result() {
|
||||
let ctx = TestContext::new("mysql://root:@localhost", "find_one_with_no_result").await;
|
||||
|
||||
let bakery = Bakery::find().one(&ctx.db).await.unwrap();
|
||||
assert_eq!(bakery, None);
|
||||
|
||||
ctx.delete().await;
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
pub async fn find_one_with_result() {
|
||||
let ctx = TestContext::new("mysql://root:@localhost", "find_one_with_result").await;
|
||||
|
||||
let bakery = bakery::ActiveModel {
|
||||
name: Set("SeaSide Bakery".to_owned()),
|
||||
profit_margin: Set(10.4),
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert bakery");
|
||||
|
||||
let result = Bakery::find().one(&ctx.db).await.unwrap().unwrap();
|
||||
|
||||
assert_eq!(result.id, bakery.id.unwrap());
|
||||
|
||||
ctx.delete().await;
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
pub async fn find_by_id_with_no_result() {
|
||||
let ctx = TestContext::new("mysql://root:@localhost", "find_by_id_with_no_result").await;
|
||||
|
||||
let bakery = Bakery::find_by_id(999).one(&ctx.db).await.unwrap();
|
||||
assert_eq!(bakery, None);
|
||||
|
||||
ctx.delete().await;
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
pub async fn find_by_id_with_result() {
|
||||
let ctx = TestContext::new("mysql://root:@localhost", "find_by_id_with_result").await;
|
||||
|
||||
let bakery = bakery::ActiveModel {
|
||||
name: Set("SeaSide Bakery".to_owned()),
|
||||
profit_margin: Set(10.4),
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert bakery");
|
||||
|
||||
let result = Bakery::find_by_id(bakery.id.clone().unwrap())
|
||||
.one(&ctx.db)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(result.id, bakery.id.unwrap());
|
||||
|
||||
ctx.delete().await;
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
pub async fn find_all_with_no_result() {
|
||||
let ctx = TestContext::new("mysql://root:@localhost", "find_all_with_no_result").await;
|
||||
|
||||
let bakeries = Bakery::find().all(&ctx.db).await.unwrap();
|
||||
assert_eq!(bakeries.len(), 0);
|
||||
|
||||
ctx.delete().await;
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
pub async fn find_all_with_result() {
|
||||
let ctx = TestContext::new("mysql://root:@localhost", "find_all_with_result").await;
|
||||
|
||||
let _ = bakery::ActiveModel {
|
||||
name: Set("SeaSide Bakery".to_owned()),
|
||||
profit_margin: Set(10.4),
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert bakery");
|
||||
|
||||
let _ = bakery::ActiveModel {
|
||||
name: Set("Top Bakery".to_owned()),
|
||||
profit_margin: Set(15.0),
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert bakery");
|
||||
|
||||
let bakeries = Bakery::find().all(&ctx.db).await.unwrap();
|
||||
|
||||
assert_eq!(bakeries.len(), 2);
|
||||
|
||||
ctx.delete().await;
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
pub async fn find_all_filter_no_result() {
|
||||
let ctx = TestContext::new("mysql://root:@localhost", "find_all_filter_no_result").await;
|
||||
|
||||
let _ = bakery::ActiveModel {
|
||||
name: Set("SeaSide Bakery".to_owned()),
|
||||
profit_margin: Set(10.4),
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert bakery");
|
||||
|
||||
let _ = bakery::ActiveModel {
|
||||
name: Set("Top Bakery".to_owned()),
|
||||
profit_margin: Set(15.0),
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert bakery");
|
||||
|
||||
let bakeries = Bakery::find()
|
||||
.filter(bakery::Column::Name.contains("Good"))
|
||||
.all(&ctx.db)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(bakeries.len(), 0);
|
||||
|
||||
ctx.delete().await;
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
pub async fn find_all_filter_with_results() {
|
||||
let ctx = TestContext::new("mysql://root:@localhost", "find_all_filter_with_results").await;
|
||||
|
||||
let _ = bakery::ActiveModel {
|
||||
name: Set("SeaSide Bakery".to_owned()),
|
||||
profit_margin: Set(10.4),
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert bakery");
|
||||
|
||||
let _ = bakery::ActiveModel {
|
||||
name: Set("Top Bakery".to_owned()),
|
||||
profit_margin: Set(15.0),
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert bakery");
|
||||
|
||||
let bakeries = Bakery::find()
|
||||
.filter(bakery::Column::Name.contains("bakery"))
|
||||
.all(&ctx.db)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(bakeries.len(), 2);
|
||||
|
||||
ctx.delete().await;
|
||||
}
|
460
tests/relational_tests.rs
Normal file
460
tests/relational_tests.rs
Normal file
@ -0,0 +1,460 @@
|
||||
// cargo test --test realtional_tests -- --nocapture
|
||||
|
||||
use chrono::offset::Utc;
|
||||
use rust_decimal::prelude::*;
|
||||
use rust_decimal_macros::dec;
|
||||
use sea_orm::{entity::*, query::*, FromQueryResult};
|
||||
|
||||
pub mod common;
|
||||
pub use common::{bakery_chain::*, setup::*, TestContext};
|
||||
|
||||
#[async_std::test]
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
pub async fn left_join() {
|
||||
let ctx = TestContext::new("mysql://root:@localhost", "test_left_join").await;
|
||||
|
||||
let bakery = bakery::ActiveModel {
|
||||
name: Set("SeaSide Bakery".to_owned()),
|
||||
profit_margin: Set(10.4),
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert bakery");
|
||||
|
||||
let _baker_1 = baker::ActiveModel {
|
||||
name: Set("Baker 1".to_owned()),
|
||||
contact_details: Set(serde_json::json!({
|
||||
"mobile": "+61424000000",
|
||||
"home": "0395555555",
|
||||
"address": "12 Test St, Testville, Vic, Australia"
|
||||
})),
|
||||
bakery_id: Set(Some(bakery.id.clone().unwrap())),
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert baker");
|
||||
|
||||
let _baker_2 = baker::ActiveModel {
|
||||
name: Set("Baker 2".to_owned()),
|
||||
contact_details: Set(serde_json::json!({})),
|
||||
bakery_id: Set(None),
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert baker");
|
||||
|
||||
#[derive(Debug, FromQueryResult)]
|
||||
struct SelectResult {
|
||||
name: String,
|
||||
bakery_name: Option<String>,
|
||||
}
|
||||
|
||||
let select = baker::Entity::find()
|
||||
.left_join(bakery::Entity)
|
||||
.select_only()
|
||||
.column(baker::Column::Name)
|
||||
.column_as(bakery::Column::Name, "bakery_name")
|
||||
.filter(baker::Column::Name.contains("Baker 1"));
|
||||
|
||||
let result = select
|
||||
.into_model::<SelectResult>()
|
||||
.one(&ctx.db)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(result.bakery_name, Some("SeaSide Bakery".to_string()));
|
||||
|
||||
let select = baker::Entity::find()
|
||||
.left_join(bakery::Entity)
|
||||
.select_only()
|
||||
.column(baker::Column::Name)
|
||||
.column_as(bakery::Column::Name, "bakery_name")
|
||||
.filter(baker::Column::Name.contains("Baker 2"));
|
||||
|
||||
let result = select
|
||||
.into_model::<SelectResult>()
|
||||
.one(&ctx.db)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(result.bakery_name, None);
|
||||
|
||||
ctx.delete().await;
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
pub async fn right_join() {
|
||||
let ctx = TestContext::new("mysql://root:@localhost", "test_right_join").await;
|
||||
|
||||
let bakery = bakery::ActiveModel {
|
||||
name: Set("SeaSide Bakery".to_owned()),
|
||||
profit_margin: Set(10.4),
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert bakery");
|
||||
|
||||
let customer_kate = customer::ActiveModel {
|
||||
name: Set("Kate".to_owned()),
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert customer");
|
||||
|
||||
let _customer_jim = customer::ActiveModel {
|
||||
name: Set("Jim".to_owned()),
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert customer");
|
||||
|
||||
let _order = order::ActiveModel {
|
||||
bakery_id: Set(Some(bakery.id.clone().unwrap())),
|
||||
customer_id: Set(Some(customer_kate.id.clone().unwrap())),
|
||||
total: Set(dec!(15.10)),
|
||||
placed_at: Set(Utc::now().naive_utc()),
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert order");
|
||||
|
||||
#[derive(Debug, FromQueryResult)]
|
||||
struct SelectResult {
|
||||
name: String,
|
||||
order_total: Option<Decimal>,
|
||||
}
|
||||
|
||||
let select = order::Entity::find()
|
||||
.right_join(customer::Entity)
|
||||
.select_only()
|
||||
.column(customer::Column::Name)
|
||||
.column_as(order::Column::Total, "order_total")
|
||||
.filter(customer::Column::Name.contains("Kate"));
|
||||
|
||||
let result = select
|
||||
.into_model::<SelectResult>()
|
||||
.one(&ctx.db)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(result.order_total, Some(dec!(15.10)));
|
||||
|
||||
let select = order::Entity::find()
|
||||
.right_join(customer::Entity)
|
||||
.select_only()
|
||||
.column(customer::Column::Name)
|
||||
.column_as(order::Column::Total, "order_total")
|
||||
.filter(customer::Column::Name.contains("Jim"));
|
||||
|
||||
let result = select
|
||||
.into_model::<SelectResult>()
|
||||
.one(&ctx.db)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(result.order_total, None);
|
||||
|
||||
ctx.delete().await;
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
pub async fn inner_join() {
|
||||
let ctx = TestContext::new("mysql://root:@localhost", "test_inner_join").await;
|
||||
|
||||
let bakery = bakery::ActiveModel {
|
||||
name: Set("SeaSide Bakery".to_owned()),
|
||||
profit_margin: Set(10.4),
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert bakery");
|
||||
|
||||
let customer_kate = customer::ActiveModel {
|
||||
name: Set("Kate".to_owned()),
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert customer");
|
||||
|
||||
let _customer_jim = customer::ActiveModel {
|
||||
name: Set("Jim".to_owned()),
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert customer");
|
||||
|
||||
let kate_order_1 = order::ActiveModel {
|
||||
bakery_id: Set(Some(bakery.id.clone().unwrap())),
|
||||
customer_id: Set(Some(customer_kate.id.clone().unwrap())),
|
||||
total: Set(dec!(15.10)),
|
||||
placed_at: Set(Utc::now().naive_utc()),
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert order");
|
||||
|
||||
let kate_order_2 = order::ActiveModel {
|
||||
bakery_id: Set(Some(bakery.id.clone().unwrap())),
|
||||
customer_id: Set(Some(customer_kate.id.clone().unwrap())),
|
||||
total: Set(dec!(100.00)),
|
||||
placed_at: Set(Utc::now().naive_utc()),
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert order");
|
||||
|
||||
#[derive(Debug, FromQueryResult)]
|
||||
struct SelectResult {
|
||||
name: String,
|
||||
order_total: Option<Decimal>,
|
||||
}
|
||||
|
||||
let select = order::Entity::find()
|
||||
.inner_join(customer::Entity)
|
||||
.select_only()
|
||||
.column(customer::Column::Name)
|
||||
.column_as(order::Column::Total, "order_total");
|
||||
|
||||
let results = select
|
||||
.into_model::<SelectResult>()
|
||||
.all(&ctx.db)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(results.len(), 2);
|
||||
assert!((&results)
|
||||
.into_iter()
|
||||
.any(|result| result.name == customer_kate.name.clone().unwrap()
|
||||
&& result.order_total == Some(kate_order_1.total.clone().unwrap())));
|
||||
assert!((&results)
|
||||
.into_iter()
|
||||
.any(|result| result.name == customer_kate.name.clone().unwrap()
|
||||
&& result.order_total == Some(kate_order_2.total.clone().unwrap())));
|
||||
|
||||
ctx.delete().await;
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
pub async fn group_by() {
|
||||
let ctx = TestContext::new("mysql://root:@localhost", "test_group_by").await;
|
||||
|
||||
let bakery = bakery::ActiveModel {
|
||||
name: Set("SeaSide Bakery".to_owned()),
|
||||
profit_margin: Set(10.4),
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert bakery");
|
||||
|
||||
let customer_kate = customer::ActiveModel {
|
||||
name: Set("Kate".to_owned()),
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert customer");
|
||||
|
||||
let kate_order_1 = order::ActiveModel {
|
||||
bakery_id: Set(Some(bakery.id.clone().unwrap())),
|
||||
customer_id: Set(Some(customer_kate.id.clone().unwrap())),
|
||||
total: Set(dec!(99.95)),
|
||||
placed_at: Set(Utc::now().naive_utc()),
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert order");
|
||||
|
||||
let kate_order_2 = order::ActiveModel {
|
||||
bakery_id: Set(Some(bakery.id.clone().unwrap())),
|
||||
customer_id: Set(Some(customer_kate.id.clone().unwrap())),
|
||||
total: Set(dec!(200.00)),
|
||||
placed_at: Set(Utc::now().naive_utc()),
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert order");
|
||||
|
||||
#[derive(Debug, FromQueryResult)]
|
||||
struct SelectResult {
|
||||
name: String,
|
||||
number_orders: Option<i32>,
|
||||
total_spent: Option<Decimal>,
|
||||
min_spent: Option<Decimal>,
|
||||
max_spent: Option<Decimal>,
|
||||
}
|
||||
|
||||
let select = customer::Entity::find()
|
||||
.left_join(order::Entity)
|
||||
.select_only()
|
||||
.column(customer::Column::Name)
|
||||
.column_as(order::Column::Total.count(), "number_orders")
|
||||
.column_as(order::Column::Total.sum(), "total_spent")
|
||||
.column_as(order::Column::Total.min(), "min_spent")
|
||||
.column_as(order::Column::Total.max(), "max_spent")
|
||||
.group_by(customer::Column::Name);
|
||||
|
||||
let result = select
|
||||
.into_model::<SelectResult>()
|
||||
.one(&ctx.db)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(result.number_orders, Some(2));
|
||||
assert_eq!(
|
||||
result.total_spent,
|
||||
Some(kate_order_1.total.clone().unwrap() + kate_order_2.total.clone().unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
result.min_spent,
|
||||
Some(
|
||||
kate_order_1
|
||||
.total
|
||||
.clone()
|
||||
.unwrap()
|
||||
.min(kate_order_2.total.clone().unwrap())
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
result.max_spent,
|
||||
Some(
|
||||
kate_order_1
|
||||
.total
|
||||
.clone()
|
||||
.unwrap()
|
||||
.max(kate_order_2.total.clone().unwrap())
|
||||
)
|
||||
);
|
||||
ctx.delete().await;
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
pub async fn having() {
|
||||
// customers with orders with total equal to $90
|
||||
let ctx = TestContext::new("mysql://root:@localhost", "test_having").await;
|
||||
|
||||
let bakery = bakery::ActiveModel {
|
||||
name: Set("SeaSide Bakery".to_owned()),
|
||||
profit_margin: Set(10.4),
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert bakery");
|
||||
|
||||
let customer_kate = customer::ActiveModel {
|
||||
name: Set("Kate".to_owned()),
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert customer");
|
||||
|
||||
let kate_order_1 = order::ActiveModel {
|
||||
bakery_id: Set(Some(bakery.id.clone().unwrap())),
|
||||
customer_id: Set(Some(customer_kate.id.clone().unwrap())),
|
||||
total: Set(dec!(100.00)),
|
||||
placed_at: Set(Utc::now().naive_utc()),
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert order");
|
||||
|
||||
let _kate_order_2 = order::ActiveModel {
|
||||
bakery_id: Set(Some(bakery.id.clone().unwrap())),
|
||||
customer_id: Set(Some(customer_kate.id.clone().unwrap())),
|
||||
total: Set(dec!(12.00)),
|
||||
placed_at: Set(Utc::now().naive_utc()),
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert order");
|
||||
|
||||
let customer_bob = customer::ActiveModel {
|
||||
name: Set("Bob".to_owned()),
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert customer");
|
||||
|
||||
let _bob_order_1 = order::ActiveModel {
|
||||
bakery_id: Set(Some(bakery.id.clone().unwrap())),
|
||||
customer_id: Set(Some(customer_bob.id.clone().unwrap())),
|
||||
total: Set(dec!(50.0)),
|
||||
placed_at: Set(Utc::now().naive_utc()),
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert order");
|
||||
|
||||
let _bob_order_2 = order::ActiveModel {
|
||||
bakery_id: Set(Some(bakery.id.clone().unwrap())),
|
||||
customer_id: Set(Some(customer_bob.id.clone().unwrap())),
|
||||
total: Set(dec!(50.0)),
|
||||
placed_at: Set(Utc::now().naive_utc()),
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
.save(&ctx.db)
|
||||
.await
|
||||
.expect("could not insert order");
|
||||
|
||||
#[derive(Debug, FromQueryResult)]
|
||||
struct SelectResult {
|
||||
name: String,
|
||||
order_total: Option<Decimal>,
|
||||
}
|
||||
|
||||
let results = customer::Entity::find()
|
||||
.inner_join(order::Entity)
|
||||
.select_only()
|
||||
.column(customer::Column::Name)
|
||||
.column_as(order::Column::Total, "order_total")
|
||||
.group_by(customer::Column::Name)
|
||||
.group_by(order::Column::Total)
|
||||
.having(order::Column::Total.gt(dec!(90.00)))
|
||||
.into_model::<SelectResult>()
|
||||
.all(&ctx.db)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(results.len(), 1);
|
||||
assert_eq!(results[0].name, customer_kate.name.clone().unwrap());
|
||||
assert_eq!(
|
||||
results[0].order_total,
|
||||
Some(kate_order_1.total.clone().unwrap())
|
||||
);
|
||||
|
||||
ctx.delete().await;
|
||||
}
|
269
tests/sequential_op_tests.rs
Normal file
269
tests/sequential_op_tests.rs
Normal file
@ -0,0 +1,269 @@
|
||||
use chrono::offset::Utc;
|
||||
use rust_decimal::prelude::*;
|
||||
use rust_decimal_macros::dec;
|
||||
use sea_orm::{entity::*, query::*, DatabaseConnection, FromQueryResult};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub mod common;
|
||||
pub use common::{bakery_chain::*, setup::*, TestContext};
|
||||
|
||||
#[async_std::test]
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
pub async fn test_multiple_operations() {
|
||||
let ctx = TestContext::new("mysql://root:@localhost", "multiple_sequential_operations").await;
|
||||
|
||||
init_setup(&ctx.db).await;
|
||||
let baker_least_sales = find_baker_least_sales(&ctx.db).await.unwrap();
|
||||
assert_eq!(baker_least_sales.name, "Baker 2");
|
||||
|
||||
let new_cake = create_cake(&ctx.db, baker_least_sales).await.unwrap();
|
||||
create_order(&ctx.db, new_cake).await;
|
||||
|
||||
let baker_least_sales = find_baker_least_sales(&ctx.db).await.unwrap();
|
||||
assert_eq!(baker_least_sales.name, "Baker 1");
|
||||
}
|
||||
|
||||
async fn init_setup(db: &DatabaseConnection) {
|
||||
let bakery = bakery::ActiveModel {
|
||||
name: Set("SeaSide Bakery".to_owned()),
|
||||
profit_margin: Set(10.4),
|
||||
..Default::default()
|
||||
}
|
||||
.save(db)
|
||||
.await
|
||||
.expect("could not insert bakery");
|
||||
|
||||
let baker_1 = baker::ActiveModel {
|
||||
name: Set("Baker 1".to_owned()),
|
||||
contact_details: Set(serde_json::json!({})),
|
||||
bakery_id: Set(Some(bakery.id.clone().unwrap())),
|
||||
..Default::default()
|
||||
}
|
||||
.save(db)
|
||||
.await
|
||||
.expect("could not insert baker");
|
||||
|
||||
let _baker_2 = baker::ActiveModel {
|
||||
name: Set("Baker 2".to_owned()),
|
||||
contact_details: Set(serde_json::json!({})),
|
||||
bakery_id: Set(Some(bakery.id.clone().unwrap())),
|
||||
..Default::default()
|
||||
}
|
||||
.save(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),
|
||||
serial: Set(Uuid::new_v4()),
|
||||
bakery_id: Set(Some(bakery.id.clone().unwrap())),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let cake_insert_res: InsertResult = Cake::insert(mud_cake)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert cake");
|
||||
|
||||
let cake_baker = cakes_bakers::ActiveModel {
|
||||
cake_id: Set(cake_insert_res.last_insert_id as i32),
|
||||
baker_id: Set(baker_1.id.clone().unwrap()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let _cake_baker_res: InsertResult = CakesBakers::insert(cake_baker)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert cake_baker");
|
||||
|
||||
let customer_kate = customer::ActiveModel {
|
||||
name: Set("Kate".to_owned()),
|
||||
..Default::default()
|
||||
}
|
||||
.save(db)
|
||||
.await
|
||||
.expect("could not insert customer");
|
||||
|
||||
let kate_order_1 = order::ActiveModel {
|
||||
bakery_id: Set(Some(bakery.id.clone().unwrap())),
|
||||
customer_id: Set(Some(customer_kate.id.clone().unwrap())),
|
||||
total: Set(dec!(99.95)),
|
||||
placed_at: Set(Utc::now().naive_utc()),
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
.save(db)
|
||||
.await
|
||||
.expect("could not insert order");
|
||||
|
||||
let _lineitem = lineitem::ActiveModel {
|
||||
cake_id: Set(Some(cake_insert_res.last_insert_id as i32)),
|
||||
price: Set(dec!(10.00)),
|
||||
quantity: Set(12),
|
||||
order_id: Set(Some(kate_order_1.id.clone().unwrap())),
|
||||
..Default::default()
|
||||
}
|
||||
.save(db)
|
||||
.await
|
||||
.expect("could not insert order");
|
||||
|
||||
let _lineitem2 = lineitem::ActiveModel {
|
||||
cake_id: Set(Some(cake_insert_res.last_insert_id as i32)),
|
||||
price: Set(dec!(50.00)),
|
||||
quantity: Set(2),
|
||||
order_id: Set(Some(kate_order_1.id.clone().unwrap())),
|
||||
..Default::default()
|
||||
}
|
||||
.save(db)
|
||||
.await
|
||||
.expect("could not insert order");
|
||||
}
|
||||
|
||||
async fn find_baker_least_sales(db: &DatabaseConnection) -> Option<baker::Model> {
|
||||
#[derive(Debug, FromQueryResult)]
|
||||
struct SelectResult {
|
||||
id: i32,
|
||||
cakes_sold_opt: Option<Decimal>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct LeastSalesBakerResult {
|
||||
id: i32,
|
||||
cakes_sold: Decimal,
|
||||
}
|
||||
|
||||
let rel: RelationDef = cakes_bakers::Entity::belongs_to(baker::Entity)
|
||||
.from(cakes_bakers::Column::BakerId)
|
||||
.to(baker::Column::Id)
|
||||
.into();
|
||||
|
||||
let rel2: RelationDef = cakes_bakers::Entity::belongs_to(cake::Entity)
|
||||
.from(cakes_bakers::Column::CakeId)
|
||||
.to(cake::Column::Id)
|
||||
.into();
|
||||
|
||||
let rel3: RelationDef = cake::Entity::has_many(lineitem::Entity)
|
||||
.from(cake::Column::Id)
|
||||
.to(lineitem::Column::CakeId)
|
||||
.into();
|
||||
|
||||
let select = cakes_bakers::Entity::find()
|
||||
.join(JoinType::RightJoin, rel)
|
||||
.join(JoinType::LeftJoin, rel2)
|
||||
.join(JoinType::LeftJoin, rel3)
|
||||
.select_only()
|
||||
.column(baker::Column::Id)
|
||||
.column_as(lineitem::Column::Quantity.sum(), "cakes_sold_opt")
|
||||
.group_by(baker::Column::Id);
|
||||
|
||||
let mut results: Vec<LeastSalesBakerResult> = select
|
||||
.into_model::<SelectResult>()
|
||||
.all(&db)
|
||||
.await
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|b| LeastSalesBakerResult {
|
||||
id: b.id.clone(),
|
||||
cakes_sold: b.cakes_sold_opt.unwrap_or(dec!(0)),
|
||||
})
|
||||
.collect();
|
||||
|
||||
results.sort_by(|a, b| b.cakes_sold.cmp(&a.cakes_sold));
|
||||
|
||||
Baker::find_by_id(results.last().unwrap().id)
|
||||
.one(db)
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
async fn create_cake(db: &DatabaseConnection, baker: baker::Model) -> Option<cake::Model> {
|
||||
let new_cake = cake::ActiveModel {
|
||||
name: Set("New Cake".to_owned()),
|
||||
price: Set(dec!(8.00)),
|
||||
gluten_free: Set(false),
|
||||
serial: Set(Uuid::new_v4()),
|
||||
bakery_id: Set(Some(baker.bakery_id.clone().unwrap())),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let cake_insert_res: InsertResult = Cake::insert(new_cake)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert cake");
|
||||
|
||||
let cake_baker = cakes_bakers::ActiveModel {
|
||||
cake_id: Set(cake_insert_res.last_insert_id as i32),
|
||||
baker_id: Set(baker.id),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let _cake_baker_res: InsertResult = CakesBakers::insert(cake_baker)
|
||||
.exec(db)
|
||||
.await
|
||||
.expect("could not insert cake_baker");
|
||||
|
||||
Cake::find_by_id(cake_insert_res.last_insert_id)
|
||||
.one(db)
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
async fn create_order(db: &DatabaseConnection, cake: cake::Model) {
|
||||
let another_customer = customer::ActiveModel {
|
||||
name: Set("John".to_owned()),
|
||||
..Default::default()
|
||||
}
|
||||
.save(db)
|
||||
.await
|
||||
.expect("could not insert customer");
|
||||
|
||||
let order = order::ActiveModel {
|
||||
bakery_id: Set(Some(cake.bakery_id.unwrap())),
|
||||
customer_id: Set(Some(another_customer.id.clone().unwrap())),
|
||||
total: Set(dec!(200.00)),
|
||||
placed_at: Set(Utc::now().naive_utc()),
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
.save(db)
|
||||
.await
|
||||
.expect("could not insert order");
|
||||
|
||||
let _lineitem = lineitem::ActiveModel {
|
||||
cake_id: Set(Some(cake.id)),
|
||||
price: Set(dec!(10.00)),
|
||||
quantity: Set(300),
|
||||
order_id: Set(Some(order.id.clone().unwrap())),
|
||||
..Default::default()
|
||||
}
|
||||
.save(db)
|
||||
.await
|
||||
.expect("could not insert order");
|
||||
}
|
||||
|
||||
pub async fn test_delete_bakery(db: &DatabaseConnection) {
|
||||
let initial_bakeries = Bakery::find().all(db).await.unwrap().len();
|
||||
|
||||
let bakery = bakery::ActiveModel {
|
||||
name: Set("SeaSide Bakery".to_owned()),
|
||||
profit_margin: Set(10.4),
|
||||
..Default::default()
|
||||
}
|
||||
.save(db)
|
||||
.await
|
||||
.expect("could not insert bakery");
|
||||
|
||||
assert_eq!(
|
||||
Bakery::find().all(db).await.unwrap().len(),
|
||||
initial_bakeries + 1
|
||||
);
|
||||
|
||||
let _result = bakery.delete(db).await.expect("failed to delete bakery");
|
||||
|
||||
assert_eq!(
|
||||
Bakery::find().all(db).await.unwrap().len(),
|
||||
initial_bakeries
|
||||
);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user