Merge branch 'master' into select-into-tuple

This commit is contained in:
Billy Chan 2022-12-20 15:51:06 +08:00
commit 2f00a8757d
No known key found for this signature in database
GPG Key ID: A2D690CAC7DF3CC7
87 changed files with 1989 additions and 348 deletions

View File

@ -10,11 +10,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### New Features
* Transactions Isolation level and Access mode https://github.com/SeaQL/sea-orm/pull/1230
* [sea-orm-cli] Generate `#[serde(skip_deserializing)]` for primary key columns https://github.com/SeaQL/sea-orm/pull/846, https://github.com/SeaQL/sea-orm/pull/1186, https://github.com/SeaQL/sea-orm/pull/1318
* [sea-orm-cli] Generate `#[serde(skip)]` for hidden columns https://github.com/SeaQL/sea-orm/pull/1171, https://github.com/SeaQL/sea-orm/pull/1320
* [sea-orm-cli] Generate entity with extra derives and attributes for model struct https://github.com/SeaQL/sea-orm/pull/1124, https://github.com/SeaQL/sea-orm/pull/1321
### Enhancements
* Support Vector of enum for Postgres https://github.com/SeaQL/sea-orm/pull/1210
* Added `DatabaseConnection::close` https://github.com/SeaQL/sea-orm/pull/1236
* Refactor schema module to expose functions for database alteration https://github.com/SeaQL/sea-orm/pull/1256
### Upgrades
@ -22,11 +26,24 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### House Keeping
* Remove dependency when not needed https://github.com/SeaQL/sea-orm/pull/1213
* Removed dependency when not needed https://github.com/SeaQL/sea-orm/pull/1213
* Changed all version = "^x.y.z" into version = "x.y.z" and disabled default features and enable only the needed ones https://github.com/SeaQL/sea-orm/pull/1300
### Bug Fixes
* Fixes `DeriveColumn` (by qualifying `IdenStatic::as_str`) https://github.com/SeaQL/sea-orm/pull/1280
* Prevent returning connections to pool with a positive transaction depth https://github.com/SeaQL/sea-orm/pull/1283
## 0.10.6 - Pending
### Enhancements
* Cast enum values when constructing update many query https://github.com/SeaQL/sea-orm/pull/1178
### Bug Fixes
* [sea-orm-codegen] Skip implementing Related if the same related entity is being referenced by a conjunct relation https://github.com/SeaQL/sea-orm/pull/1298
* [sea-orm-cli] CLI depends on codegen of the same version https://github.com/SeaQL/sea-orm/pull/1299/
## 0.10.5 - 2022-12-02

View File

@ -24,41 +24,41 @@ name = "sea_orm"
path = "src/lib.rs"
[dependencies]
async-stream = { version = "^0.3", default-features = false }
async-trait = { version = "^0.1", default-features = false }
chrono = { version = "^0.4.20", default-features = false, optional = true }
time = { version = "^0.3", default-features = false, optional = true }
futures = { version = "^0.3", default-features = false, features = ["std"] }
log = { version = "^0.4", default-features = false }
tracing = { version = "^0.1", default-features = false, features = ["attributes", "log"] }
rust_decimal = { version = "^1", default-features = false, optional = true }
bigdecimal = { version = "^0.3", default-features = false, optional = true }
sea-orm-macros = { version = "^0.10.3", path = "sea-orm-macros", default-features = false, optional = true }
sea-query = { version = "^0.27.2", features = ["thread-safe"] }
sea-query-binder = { version = "^0.2.2", default-features = false, optional = true }
sea-strum = { version = "^0.23", default-features = false, features = ["derive", "sea-orm"] }
serde = { version = "^1.0", default-features = false }
serde_json = { version = "^1.0", default-features = false, optional = true }
sqlx = { version = "^0.6", default-features = false, optional = true }
uuid = { version = "^1", default-features = false, optional = true }
async-stream = { version = "0.3", default-features = false }
async-trait = { version = "0.1", default-features = false }
chrono = { version = "0.4.20", default-features = false, optional = true }
time = { version = "0.3", default-features = false, optional = true }
futures = { version = "0.3", default-features = false, features = ["std"] }
log = { version = "0.4", default-features = false }
tracing = { version = "0.1", default-features = false, features = ["attributes", "log"] }
rust_decimal = { version = "1", default-features = false, optional = true }
bigdecimal = { version = "0.3", default-features = false, optional = true }
sea-orm-macros = { version = "0.10.3", path = "sea-orm-macros", default-features = false, optional = true }
sea-query = { version = "0.27.2", features = ["thread-safe"] }
sea-query-binder = { version = "0.2.2", default-features = false, optional = true }
sea-strum = { version = "0.23", default-features = false, features = ["derive", "sea-orm"] }
serde = { version = "1.0", default-features = false }
serde_json = { version = "1.0", default-features = false, optional = true }
sqlx = { version = "0.6", default-features = false, optional = true }
uuid = { version = "1", default-features = false, optional = true }
ouroboros = { version = "0.15", default-features = false }
url = { version = "^2.2", default-features = false }
thiserror = { version = "^1", default-features = false }
url = { version = "2.2", default-features = false }
thiserror = { version = "1", default-features = false }
[dev-dependencies]
smol = { version = "^1.2" }
smol-potat = { version = "^1.1" }
async-std = { version = "^1", features = ["attributes", "tokio1"] }
futures = { version = "^0.3" }
tokio = { version = "^1.6", features = ["full"] }
smol = { version = "1.2" }
smol-potat = { version = "1.1" }
async-std = { version = "1", features = ["attributes", "tokio1"] }
futures = { version = "0.3" }
tokio = { version = "1.6", features = ["full"] }
actix-rt = { version = "2.2.0" }
maplit = { version = "^1" }
rust_decimal_macros = { version = "^1" }
maplit = { version = "1" }
rust_decimal_macros = { version = "1" }
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
sea-orm = { path = ".", features = ["mock", "debug-print", "tests-cfg", "postgres-array"] }
pretty_assertions = { version = "^0.7" }
time = { version = "^0.3", features = ["macros"] }
uuid = { version = "^1", features = ["v4"] }
pretty_assertions = { version = "0.7" }
time = { version = "0.3", features = ["macros"] }
uuid = { version = "1", features = ["v4"] }
once_cell = "1.8"
[features]

View File

@ -11,7 +11,7 @@ sleep 1
# Bump `sea-orm-cli` version
cd sea-orm-cli
sed -i 's/^version.*$/version = "'$1'"/' Cargo.toml
sed -i 's/^sea-orm-codegen [^,]*,/sea-orm-codegen = { version = "\^'$1'",/' Cargo.toml
sed -i 's/^sea-orm-codegen [^,]*,/sea-orm-codegen = { version = "\='$1'",/' Cargo.toml
git commit -am "sea-orm-cli $1"
cd ..
sleep 1
@ -23,21 +23,21 @@ git commit -am "sea-orm-macros $1"
cd ..
sleep 1
sed -i 's/^version.*$/version = "'$1'"/' Cargo.toml
sed -i 's/^sea-orm-macros [^,]*,/sea-orm-macros = { version = "\^'$1'",/' Cargo.toml
sed -i 's/^sea-orm-macros [^,]*,/sea-orm-macros = { version = "'$1'",/' Cargo.toml
git commit -am "$1" # publish sea-orm
sleep 1
# Bump `sea-orm-migration` version
cd sea-orm-migration
sed -i 's/^version.*$/version = "'$1'"/' Cargo.toml
sed -i 's/^sea-orm-cli [^,]*,/sea-orm-cli = { version = "\^'$1'",/' Cargo.toml
sed -i 's/^sea-orm [^,]*,/sea-orm = { version = "\^'$1'",/' Cargo.toml
sed -i 's/^sea-orm-cli [^,]*,/sea-orm-cli = { version = "'$1'",/' Cargo.toml
sed -i 's/^sea-orm [^,]*,/sea-orm = { version = "'$1'",/' Cargo.toml
git commit -am "sea-orm-migration $1"
cd ..
sleep 1
# Bump examples' dependency version
cd examples
find . -depth -type f -name '*.toml' -exec sed -i 's/^version = "\^.*" # sea-orm version$/version = "\^'$1'" # sea-orm version/' {} \;
find . -depth -type f -name '*.toml' -exec sed -i 's/^version = "\^.*" # sea-orm-migration version$/version = "\^'$1'" # sea-orm-migration version/' {} \;
find . -depth -type f -name '*.toml' -exec sed -i 's/^version = ".*" # sea-orm version$/version = "'$1'" # sea-orm version/' {} \;
find . -depth -type f -name '*.toml' -exec sed -i 's/^version = ".*" # sea-orm-migration version$/version = "'$1'" # sea-orm-migration version/' {} \;
git commit -am "update examples"

View File

@ -11,8 +11,8 @@ actix-http = "2"
actix-web = "3"
actix-flash = "0.2"
actix-files = "0.5"
futures = { version = "^0.3" }
futures-util = { version = "^0.3" }
futures = { version = "0.3" }
futures-util = { version = "0.3" }
tera = "1.8.0"
dotenvy = "0.15"
listenfd = "0.3.3"

View File

@ -10,7 +10,7 @@ entity = { path = "../entity" }
[dependencies.sea-orm]
path = "../../../" # remove this line in your own project
version = "^0.10.3" # sea-orm version
version = "0.10.3" # sea-orm version
features = [
"debug-print",
"runtime-async-std-native-tls",

View File

@ -13,4 +13,4 @@ serde = { version = "1", features = ["derive"] }
[dependencies.sea-orm]
path = "../../../" # remove this line in your own project
version = "^0.10.3" # sea-orm version
version = "0.10.3" # sea-orm version

View File

@ -9,11 +9,11 @@ name = "migration"
path = "src/lib.rs"
[dependencies]
async-std = { version = "^1", features = ["attributes", "tokio1"] }
async-std = { version = "1", features = ["attributes", "tokio1"] }
[dependencies.sea-orm-migration]
path = "../../../sea-orm-migration" # remove this line in your own project
version = "^0.10.3" # sea-orm-migration version
version = "0.10.3" # sea-orm-migration version
features = [
# Enable following runtime and db backend features if you want to run migration via CLI
# "runtime-async-std-native-tls",

View File

@ -10,7 +10,7 @@ entity = { path = "../entity" }
[dependencies.sea-orm]
path = "../../../" # remove this line in your own project
version = "^0.10.3" # sea-orm version
version = "0.10.3" # sea-orm version
features = [
"debug-print",
"runtime-async-std-native-tls",

View File

@ -13,4 +13,4 @@ serde = { version = "1", features = ["derive"] }
[dependencies.sea-orm]
path = "../../../" # remove this line in your own project
version = "^0.10.3" # sea-orm version
version = "0.10.3" # sea-orm version

View File

@ -9,11 +9,11 @@ name = "migration"
path = "src/lib.rs"
[dependencies]
async-std = { version = "^1", features = ["attributes", "tokio1"] }
async-std = { version = "1", features = ["attributes", "tokio1"] }
[dependencies.sea-orm-migration]
path = "../../../sea-orm-migration" # remove this line in your own project
version = "^0.10.3" # sea-orm-migration version
version = "0.10.3" # sea-orm-migration version
features = [
# Enable following runtime and db backend features if you want to run migration via CLI
# "runtime-actix-native-tls",

View File

@ -10,7 +10,7 @@ entity = { path = "../entity" }
[dependencies.sea-orm]
path = "../../../" # remove this line in your own project
version = "^0.10.3" # sea-orm version
version = "0.10.3" # sea-orm version
features = [
"debug-print",
"runtime-async-std-native-tls",

View File

@ -13,4 +13,4 @@ serde = { version = "1", features = ["derive"] }
[dependencies.sea-orm]
path = "../../../" # remove this line in your own project
version = "^0.10.3" # sea-orm version
version = "0.10.3" # sea-orm version

View File

@ -9,11 +9,11 @@ name = "migration"
path = "src/lib.rs"
[dependencies]
async-std = { version = "^1", features = ["attributes", "tokio1"] }
async-std = { version = "1", features = ["attributes", "tokio1"] }
[dependencies.sea-orm-migration]
path = "../../../sea-orm-migration" # remove this line in your own project
version = "^0.10.3" # sea-orm-migration version
version = "0.10.3" # sea-orm-migration version
features = [
# Enable following runtime and db backend features if you want to run migration via CLI
# "runtime-tokio-native-tls",

View File

@ -8,9 +8,9 @@ edition = "2021"
publish = false
[dependencies]
async-std = { version = "^1.9", features = [ "attributes", "tokio1" ] }
async-std = { version = "1.9", features = [ "attributes", "tokio1" ] }
sea-orm = { path = "../../", features = [ "sqlx-all", "runtime-async-std-native-tls" ] }
serde_json = { version = "^1" }
futures = { version = "^0.3" }
async-stream = { version = "^0.3" }
futures-util = { version = "^0.3" }
serde_json = { version = "1" }
futures = { version = "0.3" }
async-stream = { version = "0.3" }
futures-util = { version = "0.3" }

View File

@ -8,8 +8,8 @@ publish = false
[dependencies]
graphql-example-core = { path = "../core" }
tokio = { version = "1.0", features = ["full"] }
axum = "^0.5.1"
axum = "0.5.1"
dotenvy = "0.15.0"
async-graphql-axum = "^4.0.6"
async-graphql-axum = "4.0.6"
entity = { path = "../entity" }
migration = { path = "../migration" }

View File

@ -10,7 +10,7 @@ entity = { path = "../entity" }
[dependencies.sea-orm]
path = "../../../" # remove this line in your own project
version = "^0.10.3" # sea-orm version
version = "0.10.3" # sea-orm version
features = [
"debug-print",
"runtime-async-std-native-tls",

View File

@ -12,8 +12,8 @@ path = "src/lib.rs"
serde = { version = "1", features = ["derive"] }
[dependencies.async-graphql]
version = "^4.0.6"
version = "4.0.6"
[dependencies.sea-orm]
path = "../../../" # remove this line in your own project
version = "^0.10.3" # sea-orm version
version = "0.10.3" # sea-orm version

View File

@ -10,11 +10,11 @@ path = "src/lib.rs"
[dependencies]
dotenvy = "0.15.0"
async-std = { version = "^1", features = ["attributes", "tokio1"] }
async-std = { version = "1", features = ["attributes", "tokio1"] }
[dependencies.sea-orm-migration]
path = "../../../sea-orm-migration" # remove this line in your own project
version = "^0.10.3" # sea-orm-migration version
version = "0.10.3" # sea-orm-migration version
features = [
# Enable following runtime and db backend features if you want to run migration via CLI
# "runtime-tokio-native-tls",

View File

@ -6,7 +6,7 @@ publish = false
[dependencies]
jsonrpsee-example-core = { path = "../core" }
jsonrpsee = { version = "^0.8.0", features = ["full"] }
jsonrpsee = { version = "0.8.0", features = ["full"] }
jsonrpsee-core = "0.9.0"
tokio = { version = "1.8.0", features = ["full"] }
serde = { version = "1", features = ["derive"] }

View File

@ -10,7 +10,7 @@ entity = { path = "../entity" }
[dependencies.sea-orm]
path = "../../../" # remove this line in your own project
version = "^0.10.3" # sea-orm version
version = "0.10.3" # sea-orm version
features = [
"debug-print",
"runtime-tokio-native-tls",

View File

@ -13,4 +13,4 @@ serde = { version = "1", features = ["derive"] }
[dependencies.sea-orm]
path = "../../../" # remove this line in your own project
version = "^0.10.3" # sea-orm version
version = "0.10.3" # sea-orm version

View File

@ -9,11 +9,11 @@ name = "migration"
path = "src/lib.rs"
[dependencies]
async-std = { version = "^1", features = ["attributes", "tokio1"] }
async-std = { version = "1", features = ["attributes", "tokio1"] }
[dependencies.sea-orm-migration]
path = "../../../sea-orm-migration" # remove this line in your own project
version = "^0.10.3" # sea-orm-migration version
version = "0.10.3" # sea-orm-migration version
features = [
# Enable following runtime and db backend features if you want to run migration via CLI
# "runtime-tokio-native-tls",

View File

@ -10,7 +10,7 @@ entity = { path = "../entity" }
[dependencies.sea-orm]
path = "../../../" # remove this line in your own project
version = "^0.10.3" # sea-orm version
version = "0.10.3" # sea-orm version
features = [
"debug-print",
"runtime-async-std-native-tls",

View File

@ -13,4 +13,4 @@ serde = { version = "1", features = ["derive"] }
[dependencies.sea-orm]
path = "../../../" # remove this line in your own project
version = "^0.10.3" # sea-orm version
version = "0.10.3" # sea-orm version

View File

@ -9,11 +9,11 @@ name = "migration"
path = "src/lib.rs"
[dependencies]
async-std = { version = "^1", features = ["attributes", "tokio1"] }
async-std = { version = "1", features = ["attributes", "tokio1"] }
[dependencies.sea-orm-migration]
path = "../../../sea-orm-migration" # remove this line in your own project
version = "^0.10.3" # sea-orm-migration version
version = "0.10.3" # sea-orm-migration version
features = [
# Enable following runtime and db backend features if you want to run migration via CLI
# "runtime-tokio-native-tls",

View File

@ -6,18 +6,18 @@ edition = "2021"
publish = false
[dependencies]
async-stream = { version = "^0.3" }
async-stream = { version = "0.3" }
async-trait = { version = "0.1" }
rocket-example-core = { path = "../core" }
futures = { version = "^0.3" }
futures-util = { version = "^0.3" }
futures = { version = "0.3" }
futures-util = { version = "0.3" }
rocket = { version = "0.5.0-rc.1", features = [
"json",
] }
rocket_dyn_templates = { version = "0.1.0-rc.1", features = [
"tera",
] }
serde_json = { version = "^1" }
serde_json = { version = "1" }
entity = { path = "../entity" }
migration = { path = "../migration" }
tokio = "1.20.0"

View File

@ -10,7 +10,7 @@ entity = { path = "../entity" }
[dependencies.sea-orm]
path = "../../../" # remove this line in your own project
version = "^0.10.3" # sea-orm version
version = "0.10.3" # sea-orm version
features = [
"runtime-tokio-native-tls",
"sqlx-postgres",

View File

@ -15,4 +15,4 @@ rocket = { version = "0.5.0-rc.1", features = [
[dependencies.sea-orm]
path = "../../../" # remove this line in your own project
version = "^0.10.3" # sea-orm version
version = "0.10.3" # sea-orm version

View File

@ -10,11 +10,11 @@ path = "src/lib.rs"
[dependencies]
rocket = { version = "0.5.0-rc.1" }
async-std = { version = "^1", features = ["attributes", "tokio1"] }
async-std = { version = "1", features = ["attributes", "tokio1"] }
[dependencies.sea-orm-migration]
path = "../../../sea-orm-migration" # remove this line in your own project
version = "^0.10.3" # sea-orm-migration version
version = "0.10.3" # sea-orm-migration version
features = [
# Enable following runtime and db backend features if you want to run migration via CLI
# "runtime-tokio-native-tls",

View File

@ -6,18 +6,18 @@ edition = "2021"
publish = false
[dependencies]
async-stream = { version = "^0.3" }
async-stream = { version = "0.3" }
async-trait = { version = "0.1" }
rocket-example-core = { path = "../core" }
futures = { version = "^0.3" }
futures-util = { version = "^0.3" }
futures = { version = "0.3" }
futures-util = { version = "0.3" }
rocket = { version = "0.5.0-rc.1", features = [
"json",
] }
rocket_dyn_templates = { version = "0.1.0-rc.1", features = [
"tera",
] }
serde_json = { version = "^1" }
serde_json = { version = "1" }
entity = { path = "../entity" }
migration = { path = "../migration" }
tokio = "1.20.0"

View File

@ -10,7 +10,7 @@ entity = { path = "../entity" }
[dependencies.sea-orm]
path = "../../../" # remove this line in your own project
version = "^0.10.3" # sea-orm version
version = "0.10.3" # sea-orm version
features = [
"runtime-tokio-native-tls",
"sqlx-postgres",

View File

@ -15,7 +15,7 @@ rocket = { version = "0.5.0-rc.1", features = [
[dependencies.sea-orm]
path = "../../../" # remove this line in your own project
version = "^0.10.3" # sea-orm version
version = "0.10.3" # sea-orm version
[dependencies.rocket_okapi]
version = "0.8.0-rc.2"

View File

@ -10,11 +10,11 @@ path = "src/lib.rs"
[dependencies]
rocket = { version = "0.5.0-rc.1" }
async-std = { version = "^1", features = ["attributes", "tokio1"] }
async-std = { version = "1", features = ["attributes", "tokio1"] }
[dependencies.sea-orm-migration]
path = "../../../sea-orm-migration" # remove this line in your own project
version = "^0.10.3" # sea-orm-migration version
version = "0.10.3" # sea-orm-migration version
features = [
# Enable following runtime and db backend features if you want to run migration via CLI
# "runtime-tokio-native-tls",

View File

@ -10,7 +10,7 @@ entity = { path = "../entity" }
[dependencies.sea-orm]
path = "../../../" # remove this line in your own project
version = "^0.10.3" # sea-orm version
version = "0.10.3" # sea-orm version
features = [
"debug-print",
"runtime-tokio-native-tls",

View File

@ -13,4 +13,4 @@ serde = { version = "1", features = ["derive"] }
[dependencies.sea-orm]
path = "../../../" # remove this line in your own project
version = "^0.10.3" # sea-orm version
version = "0.10.3" # sea-orm version

View File

@ -9,11 +9,11 @@ name = "migration"
path = "src/lib.rs"
[dependencies]
async-std = { version = "^1", features = ["attributes", "tokio1"] }
async-std = { version = "1", features = ["attributes", "tokio1"] }
[dependencies.sea-orm-migration]
path = "../../../sea-orm-migration" # remove this line in your own project
version = "^0.10.3" # sea-orm-migration version
version = "0.10.3" # sea-orm-migration version
features = [
# Enable following runtime and db backend features if you want to run migration via CLI
# "runtime-tokio-native-tls",

View File

@ -10,7 +10,7 @@ entity = { path = "../entity" }
[dependencies.sea-orm]
path = "../../../" # remove this line in your own project
version = "^0.10.3" # sea-orm version
version = "0.10.3" # sea-orm version
features = [
"debug-print",
"runtime-tokio-rustls",

View File

@ -13,4 +13,4 @@ serde = { version = "1", features = ["derive"] }
[dependencies.sea-orm]
path = "../../../" # remove this line in your own project
version = "^0.10.3" # sea-orm version
version = "0.10.3" # sea-orm version

View File

@ -9,11 +9,11 @@ name = "migration"
path = "src/lib.rs"
[dependencies]
async-std = { version = "^1", features = ["attributes", "tokio1"] }
async-std = { version = "1", features = ["attributes", "tokio1"] }
[dependencies.sea-orm-migration]
path = "../../../sea-orm-migration" # remove this line in your own project
version = "^0.10.3" # sea-orm-migration version
version = "0.10.3" # sea-orm-migration version
features = [
# Enable following runtime and db backend features if you want to run migration via CLI
# "runtime-tokio-rustls",

View File

@ -8,8 +8,8 @@ edition = "2021"
publish = false
[dependencies]
serde = "^1"
tokio = { version = "^1", features = ["rt", "rt-multi-thread", "macros"] }
serde = "1"
tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] }
[dependencies.sea-orm]
path = "../../"

View File

@ -8,8 +8,8 @@ edition = "2021"
publish = false
[dependencies]
serde = "^1"
tokio = { version = "^1", features = ["rt", "rt-multi-thread", "macros"] }
serde = "1"
tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] }
[dependencies.sea-orm]
path = "../../"

View File

@ -9,4 +9,4 @@ publish = false
[dependencies]
sea-orm = { path = "../../", features = [ "sqlx-all", "runtime-async-std-native-tls", "debug-print" ] }
async-std = { version = "^1", features = ["attributes", "tokio1"] }
async-std = { version = "1", features = ["attributes", "tokio1"] }

View File

@ -8,8 +8,8 @@ edition = "2021"
publish = false
[dependencies]
async-std = { version = "^1", features = ["attributes", "tokio1"] }
serde = { version = "^1", features = ["derive"] }
async-std = { version = "1", features = ["attributes", "tokio1"] }
serde = { version = "1", features = ["derive"] }
sea-orm = { path = "../../", features = [
"sqlx-mysql",
"runtime-async-std-native-tls",

View File

@ -9,8 +9,8 @@ edition = "2021"
publish = false
[dependencies]
serde = "^1"
tokio = { version = "^1", features = ["rt", "rt-multi-thread", "macros"] }
serde = "1"
tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] }
[dependencies.sea-orm]
path = "../../"

View File

@ -31,17 +31,17 @@ path = "src/bin/sea.rs"
required-features = ["cli", "codegen"]
[dependencies]
clap = { version = "^3.2", features = ["env", "derive"], optional = true }
dotenvy = { version = "^0.15", optional = true }
async-std = { version = "^1.9", features = ["attributes", "tokio1"], optional = true }
sea-orm-codegen = { version = "^0.10.3", path = "../sea-orm-codegen", optional = true }
sea-schema = { version = "^0.10.2" }
sqlx = { version = "^0.6", default-features = false, features = ["mysql", "postgres"], optional = true }
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
tracing = { version = "0.1" }
url = "^2.2"
chrono = { version = "^0.4.20", default-features = false, features = ["clock"] }
regex = "1"
clap = { version = "3.2", default-features = false, features = ["std", "env", "derive"], optional = true }
dotenvy = { version = "0.15", default-features = false, optional = true }
async-std = { version = "1.9", default-features = false, features = ["attributes", "tokio1"], optional = true }
sea-orm-codegen = { version = "=0.10.3", path = "../sea-orm-codegen", default-features = false, optional = true }
sea-schema = { version = "0.10.2" }
sqlx = { version = "0.6", default-features = false, features = ["mysql", "postgres"], optional = true }
tracing-subscriber = { version = "0.3", default-features = false, features = ["env-filter", "fmt"] }
tracing = { version = "0.1", default-features = false }
url = { version = "2.2", default-features = false }
chrono = { version = "0.4.20", default-features = false, features = ["clock"] }
regex = { version = "1", default-features = false }
[dev-dependencies]
smol = "1.2.5"

View File

@ -200,6 +200,21 @@ pub enum GenerateSubcommands {
)]
with_serde: String,
#[clap(
action,
long,
help = "Generate a serde field attribute, '#[serde(skip_deserializing)]', for the primary key fields to skip them during deserialization, this flag will be affective only when '--with-serde' is 'both' or 'deserialize'"
)]
serde_skip_deserializing_primary_key: bool,
#[clap(
action,
long,
default_value = "false",
help = "Opt-in to add skip attributes to hidden columns (i.e. when 'with-serde' enabled and column name starts with an underscore)"
)]
serde_skip_hidden_column: bool,
#[clap(
action,
long,
@ -228,6 +243,24 @@ pub enum GenerateSubcommands {
help = "Generate index file as `lib.rs` instead of `mod.rs`."
)]
lib: bool,
#[clap(
value_parser,
long,
use_value_delimiter = true,
takes_value = true,
help = "Add extra derive macros to generated model structs (comma separated), ex. `--derives 'ts_rs::Ts'`"
)]
model_extra_derives: Vec<String>,
#[clap(
value_parser,
long,
use_value_delimiter = true,
takes_value = true,
help = r#"Add extra attributes to generated model struct, no need for `#[]` (comma separated), ex. `--attributes 'serde(rename_all = "camelCase")','ts(export)'`"#
)]
model_extra_attributes: Vec<String>,
},
}

View File

@ -24,9 +24,13 @@ pub async fn run_generate_command(
database_schema,
database_url,
with_serde,
serde_skip_deserializing_primary_key,
serde_skip_hidden_column,
with_copy_enums,
date_time_crate,
lib,
model_extra_derives,
model_extra_attributes,
} => {
if verbose {
let _ = tracing_subscriber::fmt()
@ -159,11 +163,15 @@ pub async fn run_generate_command(
let writer_context = EntityWriterContext::new(
expanded_format,
WithSerde::from_str(&with_serde).unwrap(),
WithSerde::from_str(&with_serde).expect("Invalid serde derive option"),
with_copy_enums,
date_time_crate.into(),
schema_name,
lib,
serde_skip_deserializing_primary_key,
serde_skip_hidden_column,
model_extra_derives,
model_extra_attributes,
);
let output = EntityTransformer::transform(table_stmts)?.generate(&writer_context);

View File

@ -101,7 +101,7 @@ pub fn run_migrate_init(migration_dir: &str) -> Result<(), Box<dyn Error>> {
write_file!("src/main.rs");
write_file!("Cargo.toml", "_Cargo.toml", |content: String| {
let ver = format!(
"^{}.{}.0",
"{}.{}.0",
env!("CARGO_PKG_VERSION_MAJOR"),
env!("CARGO_PKG_VERSION_MINOR")
);

View File

@ -9,7 +9,7 @@ name = "migration"
path = "src/lib.rs"
[dependencies]
async-std = { version = "^1", features = ["attributes", "tokio1"] }
async-std = { version = "1", features = ["attributes", "tokio1"] }
[dependencies.sea-orm-migration]
version = "<sea-orm-migration-version>"

View File

@ -17,17 +17,12 @@ name = "sea_orm_codegen"
path = "src/lib.rs"
[dependencies]
sea-query = { version = "^0.27.1", features = ["thread-safe"] }
syn = { version = "^1", default-features = false, features = [
"derive",
"parsing",
"proc-macro",
"printing",
] }
quote = "^1"
heck = "^0.3"
proc-macro2 = "^1"
tracing = { version = "0.1", features = ["log"] }
sea-query = { version = "0.27.1", default-features = false, features = ["thread-safe"] }
syn = { version = "1", default-features = false }
quote = { version = "1", default-features = false }
heck = { version = "0.3", default-features = false }
proc-macro2 = { version = "1", default-features = false }
tracing = { version = "0.1", default-features = false, features = ["log"] }
[dev-dependencies]
pretty_assertions = { version = "^0.7" }
pretty_assertions = { version = "0.7" }

View File

@ -166,6 +166,24 @@ impl Entity {
// if exist, return nothing
.map_or(quote! {, Eq}, |_| quote! {})
}
pub fn get_column_serde_attributes(
&self,
serde_skip_deserializing_primary_key: bool,
serde_skip_hidden_column: bool,
) -> Vec<TokenStream> {
self.columns
.iter()
.map(|col| {
let is_primary_key = self.primary_keys.iter().any(|pk| pk.name == col.name);
col.get_serde_attribute(
is_primary_key,
serde_skip_deserializing_primary_key,
serde_skip_hidden_column,
)
})
.collect()
}
}
#[cfg(test)]
@ -204,6 +222,7 @@ mod tests {
on_update: Some(ForeignKeyAction::Cascade),
self_referencing: false,
num_suffix: 0,
impl_related: true,
},
Relation {
ref_table: "filling".to_owned(),
@ -214,6 +233,7 @@ mod tests {
on_update: Some(ForeignKeyAction::Cascade),
self_referencing: false,
num_suffix: 0,
impl_related: true,
},
],
conjunct_relations: vec![],

View File

@ -211,6 +211,25 @@ impl Column {
}
info
}
pub fn get_serde_attribute(
&self,
is_primary_key: bool,
serde_skip_deserializing_primary_key: bool,
serde_skip_hidden_column: bool,
) -> TokenStream {
if self.name.starts_with('_') && serde_skip_hidden_column {
quote! {
#[serde(skip)]
}
} else if serde_skip_deserializing_primary_key && is_primary_key {
quote! {
#[serde(skip_deserializing)]
}
} else {
quote! {}
}
}
}
impl From<ColumnDef> for Column {

View File

@ -23,6 +23,7 @@ pub struct Relation {
pub(crate) on_delete: Option<ForeignKeyAction>,
pub(crate) self_referencing: bool,
pub(crate) num_suffix: usize,
pub(crate) impl_related: bool,
}
impl Relation {
@ -178,6 +179,7 @@ impl From<&TableForeignKey> for Relation {
on_update,
self_referencing: false,
num_suffix: 0,
impl_related: true,
}
}
}
@ -199,6 +201,7 @@ mod tests {
on_update: None,
self_referencing: false,
num_suffix: 0,
impl_related: true,
},
Relation {
ref_table: "filling".to_owned(),
@ -209,6 +212,7 @@ mod tests {
on_update: Some(ForeignKeyAction::Cascade),
self_referencing: false,
num_suffix: 0,
impl_related: true,
},
Relation {
ref_table: "filling".to_owned(),
@ -219,6 +223,7 @@ mod tests {
on_update: None,
self_referencing: false,
num_suffix: 0,
impl_related: true,
},
]
}

View File

@ -197,13 +197,23 @@ impl EntityTransformer {
}
for (tbl_name, mut conjunct_relations) in conjunct_relations.into_iter() {
if let Some(entity) = entities.get_mut(&tbl_name) {
for relation in entity.relations.iter_mut() {
// Skip `impl Related ... { fn to() ... }` implementation block,
// if the same related entity is being referenced by a conjunct relation
if conjunct_relations
.iter()
.any(|conjunct_relation| conjunct_relation.to == relation.ref_table)
{
relation.impl_related = false;
}
}
entity.conjunct_relations.append(&mut conjunct_relations);
}
}
Ok(EntityWriter {
entities: entities
.into_iter()
.map(|(_, mut v)| {
.into_values()
.map(|mut v| {
v.relations.sort_by(|a, b| a.ref_table.cmp(&b.ref_table));
v
})

View File

@ -43,6 +43,10 @@ pub struct EntityWriterContext {
pub(crate) date_time_crate: DateTimeCrate,
pub(crate) schema_name: Option<String>,
pub(crate) lib: bool,
pub(crate) serde_skip_hidden_column: bool,
pub(crate) serde_skip_deserializing_primary_key: bool,
pub(crate) model_extra_derives: TokenStream,
pub(crate) model_extra_attributes: TokenStream,
}
impl WithSerde {
@ -67,15 +71,44 @@ impl WithSerde {
}
}
};
if !extra_derive.is_empty() {
extra_derive = quote! { , #extra_derive }
}
extra_derive
}
}
/// Converts model_extra_derives argument to token stream
fn bonus_derive<T>(model_extra_derives: Vec<T>) -> TokenStream
where
T: Into<String>,
{
model_extra_derives
.into_iter()
.map(Into::<String>::into)
.fold(TokenStream::default(), |acc, derive| {
let tokens: TokenStream = derive.parse().unwrap();
quote! { #acc, #tokens }
})
}
/// convert attributes argument to token stream
fn bonus_attributes<T>(attributes: Vec<T>) -> TokenStream
where
T: Into<String>,
{
attributes.into_iter().map(Into::<String>::into).fold(
TokenStream::default(),
|acc, attribute| {
let tokens: TokenStream = attribute.parse().unwrap();
quote! {
#acc
#[#tokens]
}
},
)
}
impl FromStr for WithSerde {
type Err = crate::Error;
@ -96,6 +129,7 @@ impl FromStr for WithSerde {
}
impl EntityWriterContext {
#[allow(clippy::too_many_arguments)]
pub fn new(
expanded_format: bool,
with_serde: WithSerde,
@ -103,6 +137,10 @@ impl EntityWriterContext {
date_time_crate: DateTimeCrate,
schema_name: Option<String>,
lib: bool,
serde_skip_deserializing_primary_key: bool,
serde_skip_hidden_column: bool,
model_extra_derives: Vec<String>,
model_extra_attributes: Vec<String>,
) -> Self {
Self {
expanded_format,
@ -111,6 +149,10 @@ impl EntityWriterContext {
date_time_crate,
schema_name,
lib,
serde_skip_deserializing_primary_key,
serde_skip_hidden_column,
model_extra_derives: bonus_derive(model_extra_derives),
model_extra_attributes: bonus_attributes(model_extra_attributes),
}
}
}
@ -139,6 +181,15 @@ impl EntityWriter {
.iter()
.map(|column| column.get_info(&context.date_time_crate))
.collect::<Vec<String>>();
// Serde must be enabled to use this
let serde_skip_deserializing_primary_key = context
.serde_skip_deserializing_primary_key
&& matches!(context.with_serde, WithSerde::Both | WithSerde::Deserialize);
let serde_skip_hidden_column = context.serde_skip_hidden_column
&& matches!(
context.with_serde,
WithSerde::Both | WithSerde::Serialize | WithSerde::Deserialize
);
info!("Generating {}", entity_file);
for info in column_info.iter() {
@ -153,6 +204,10 @@ impl EntityWriter {
&context.with_serde,
&context.date_time_crate,
&context.schema_name,
serde_skip_deserializing_primary_key,
serde_skip_hidden_column,
&context.model_extra_derives,
&context.model_extra_attributes,
)
} else {
Self::gen_compact_code_blocks(
@ -160,6 +215,10 @@ impl EntityWriter {
&context.with_serde,
&context.date_time_crate,
&context.schema_name,
serde_skip_deserializing_primary_key,
serde_skip_hidden_column,
&context.model_extra_derives,
&context.model_extra_attributes,
)
};
Self::write(&mut lines, code_blocks);
@ -225,8 +284,8 @@ impl EntityWriter {
lines.push("".to_owned());
let code_blocks = self
.enums
.iter()
.map(|(_, active_enum)| active_enum.impl_active_enum(with_serde, with_copy_enums))
.values()
.map(|active_enum| active_enum.impl_active_enum(with_serde, with_copy_enums))
.collect();
Self::write(&mut lines, code_blocks);
OutputFile {
@ -254,11 +313,16 @@ impl EntityWriter {
lines.push("".to_owned());
}
#[allow(clippy::too_many_arguments)]
pub fn gen_expanded_code_blocks(
entity: &Entity,
with_serde: &WithSerde,
date_time_crate: &DateTimeCrate,
schema_name: &Option<String>,
serde_skip_deserializing_primary_key: bool,
serde_skip_hidden_column: bool,
model_extra_derives: &TokenStream,
model_extra_attributes: &TokenStream,
) -> Vec<TokenStream> {
let mut imports = Self::gen_import(with_serde);
imports.extend(Self::gen_import_active_enum(entity));
@ -266,7 +330,15 @@ impl EntityWriter {
imports,
Self::gen_entity_struct(),
Self::gen_impl_entity_name(entity, schema_name),
Self::gen_model_struct(entity, with_serde, date_time_crate),
Self::gen_model_struct(
entity,
with_serde,
date_time_crate,
serde_skip_deserializing_primary_key,
serde_skip_hidden_column,
model_extra_derives,
model_extra_attributes,
),
Self::gen_column_enum(entity),
Self::gen_primary_key_enum(entity),
Self::gen_impl_primary_key(entity, date_time_crate),
@ -280,17 +352,31 @@ impl EntityWriter {
code_blocks
}
#[allow(clippy::too_many_arguments)]
pub fn gen_compact_code_blocks(
entity: &Entity,
with_serde: &WithSerde,
date_time_crate: &DateTimeCrate,
schema_name: &Option<String>,
serde_skip_deserializing_primary_key: bool,
serde_skip_hidden_column: bool,
model_extra_derives: &TokenStream,
model_extra_attributes: &TokenStream,
) -> Vec<TokenStream> {
let mut imports = Self::gen_import(with_serde);
imports.extend(Self::gen_import_active_enum(entity));
let mut code_blocks = vec![
imports,
Self::gen_compact_model_struct(entity, with_serde, date_time_crate, schema_name),
Self::gen_compact_model_struct(
entity,
with_serde,
date_time_crate,
schema_name,
serde_skip_deserializing_primary_key,
serde_skip_hidden_column,
model_extra_derives,
model_extra_attributes,
),
Self::gen_compact_relation_enum(entity),
];
code_blocks.extend(Self::gen_impl_related(entity));
@ -312,14 +398,12 @@ impl EntityWriter {
use serde::Serialize;
}
}
WithSerde::Deserialize => {
quote! {
#prelude_import
use serde::Deserialize;
}
}
WithSerde::Both => {
quote! {
#prelude_import
@ -378,16 +462,28 @@ impl EntityWriter {
entity: &Entity,
with_serde: &WithSerde,
date_time_crate: &DateTimeCrate,
serde_skip_deserializing_primary_key: bool,
serde_skip_hidden_column: bool,
model_extra_derives: &TokenStream,
model_extra_attributes: &TokenStream,
) -> TokenStream {
let column_names_snake_case = entity.get_column_names_snake_case();
let column_rs_types = entity.get_column_rs_types(date_time_crate);
let if_eq_needed = entity.get_eq_needed();
let serde_attributes = entity.get_column_serde_attributes(
serde_skip_deserializing_primary_key,
serde_skip_hidden_column,
);
let extra_derive = with_serde.extra_derive();
quote! {
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel #if_eq_needed #extra_derive)]
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel #if_eq_needed #extra_derive #model_extra_derives)]
#model_extra_attributes
pub struct Model {
#(pub #column_names_snake_case: #column_rs_types,)*
#(
#serde_attributes
pub #column_names_snake_case: #column_rs_types,
)*
}
}
}
@ -490,7 +586,7 @@ impl EntityWriter {
entity
.relations
.iter()
.filter(|rel| !rel.self_referencing && rel.num_suffix == 0)
.filter(|rel| !rel.self_referencing && rel.num_suffix == 0 && rel.impl_related)
.map(|rel| {
let enum_name = rel.get_enum_name();
let module_name = rel.get_module_name();
@ -561,11 +657,16 @@ impl EntityWriter {
}
}
#[allow(clippy::too_many_arguments)]
pub fn gen_compact_model_struct(
entity: &Entity,
with_serde: &WithSerde,
date_time_crate: &DateTimeCrate,
schema_name: &Option<String>,
serde_skip_deserializing_primary_key: bool,
serde_skip_hidden_column: bool,
model_extra_derives: &TokenStream,
model_extra_attributes: &TokenStream,
) -> TokenStream {
let table_name = entity.table_name.as_str();
let column_names_snake_case = entity.get_column_names_snake_case();
@ -581,11 +682,12 @@ impl EntityWriter {
.iter()
.map(|col| {
let mut attrs: Punctuated<_, Comma> = Punctuated::new();
let is_primary_key = primary_keys.contains(&col.name);
if !col.is_snake_case_name() {
let column_name = &col.name;
attrs.push(quote! { column_name = #column_name });
}
if primary_keys.contains(&col.name) {
if is_primary_key {
attrs.push(quote! { primary_key });
if !col.auto_increment {
attrs.push(quote! { auto_increment = false });
@ -600,20 +702,26 @@ impl EntityWriter {
if col.unique {
attrs.push(quote! { unique });
}
let mut ts = quote! {};
if !attrs.is_empty() {
let mut ts = TokenStream::new();
for (i, attr) in attrs.into_iter().enumerate() {
if i > 0 {
ts = quote! { #ts, };
}
ts = quote! { #ts #attr };
}
quote! {
#[sea_orm(#ts)]
}
} else {
TokenStream::new()
ts = quote! { #[sea_orm(#ts)] };
}
let serde_attribute = col.get_serde_attribute(
is_primary_key,
serde_skip_deserializing_primary_key,
serde_skip_hidden_column,
);
ts = quote! {
#ts
#serde_attribute
};
ts
})
.collect();
let schema_name = match Self::gen_schema_name(schema_name) {
@ -625,11 +733,12 @@ impl EntityWriter {
let extra_derive = with_serde.extra_derive();
quote! {
#[derive(Clone, Debug, PartialEq, DeriveEntityModel #if_eq_needed #extra_derive)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel #if_eq_needed #extra_derive #model_extra_derives)]
#[sea_orm(
#schema_name
table_name = #table_name
)]
#model_extra_attributes
pub struct Model {
#(
#attrs
@ -670,6 +779,7 @@ impl EntityWriter {
#[cfg(test)]
mod tests {
use crate::{
entity::writer::{bonus_attributes, bonus_derive},
Column, ConjunctRelation, DateTimeCrate, Entity, EntityWriter, PrimaryKey, Relation,
RelationType, WithSerde,
};
@ -707,6 +817,7 @@ mod tests {
on_update: None,
self_referencing: false,
num_suffix: 0,
impl_related: true,
}],
conjunct_relations: vec![ConjunctRelation {
via: "cake_filling".to_owned(),
@ -744,6 +855,7 @@ mod tests {
on_update: Some(ForeignKeyAction::Cascade),
self_referencing: false,
num_suffix: 0,
impl_related: true,
},
Relation {
ref_table: "filling".to_owned(),
@ -754,6 +866,7 @@ mod tests {
on_update: Some(ForeignKeyAction::Cascade),
self_referencing: false,
num_suffix: 0,
impl_related: true,
},
],
conjunct_relations: vec![],
@ -828,6 +941,7 @@ mod tests {
on_update: None,
self_referencing: false,
num_suffix: 0,
impl_related: true,
},
Relation {
ref_table: "vendor".to_owned(),
@ -838,6 +952,7 @@ mod tests {
on_update: None,
self_referencing: false,
num_suffix: 0,
impl_related: true,
},
],
conjunct_relations: vec![],
@ -879,6 +994,7 @@ mod tests {
on_update: None,
self_referencing: false,
num_suffix: 0,
impl_related: true,
}],
conjunct_relations: vec![],
primary_keys: vec![PrimaryKey {
@ -990,6 +1106,7 @@ mod tests {
on_update: None,
self_referencing: true,
num_suffix: 1,
impl_related: true,
},
Relation {
ref_table: "rust_keyword".to_owned(),
@ -1000,6 +1117,7 @@ mod tests {
on_update: None,
self_referencing: true,
num_suffix: 2,
impl_related: true,
},
Relation {
ref_table: "fruit".to_owned(),
@ -1010,6 +1128,7 @@ mod tests {
on_update: None,
self_referencing: false,
num_suffix: 1,
impl_related: true,
},
Relation {
ref_table: "fruit".to_owned(),
@ -1020,6 +1139,7 @@ mod tests {
on_update: None,
self_referencing: false,
num_suffix: 2,
impl_related: true,
},
Relation {
ref_table: "cake".to_owned(),
@ -1030,6 +1150,7 @@ mod tests {
on_update: None,
self_referencing: false,
num_suffix: 0,
impl_related: true,
},
],
conjunct_relations: vec![],
@ -1071,6 +1192,7 @@ mod tests {
on_update: None,
self_referencing: false,
num_suffix: 0,
impl_related: true,
}],
conjunct_relations: vec![ConjunctRelation {
via: "cake_filling".to_owned(),
@ -1114,6 +1236,7 @@ mod tests {
on_update: None,
self_referencing: false,
num_suffix: 0,
impl_related: true,
}],
conjunct_relations: vec![ConjunctRelation {
via: "cake_filling".to_owned(),
@ -1247,7 +1370,11 @@ mod tests {
entity,
&crate::WithSerde::None,
&crate::DateTimeCrate::Chrono,
&None
&None,
false,
false,
&TokenStream::new(),
&TokenStream::new(),
)
.into_iter()
.skip(1)
@ -1263,7 +1390,11 @@ mod tests {
entity,
&crate::WithSerde::None,
&crate::DateTimeCrate::Chrono,
&Some("public".to_owned())
&Some("public".to_owned()),
false,
false,
&TokenStream::new(),
&TokenStream::new(),
)
.into_iter()
.skip(1)
@ -1279,7 +1410,11 @@ mod tests {
entity,
&crate::WithSerde::None,
&crate::DateTimeCrate::Chrono,
&Some("schema_name".to_owned())
&Some("schema_name".to_owned()),
false,
false,
&TokenStream::new(),
&TokenStream::new(),
)
.into_iter()
.skip(1)
@ -1331,7 +1466,11 @@ mod tests {
entity,
&crate::WithSerde::None,
&crate::DateTimeCrate::Chrono,
&None
&None,
false,
false,
&TokenStream::new(),
&TokenStream::new(),
)
.into_iter()
.skip(1)
@ -1347,7 +1486,11 @@ mod tests {
entity,
&crate::WithSerde::None,
&crate::DateTimeCrate::Chrono,
&Some("public".to_owned())
&Some("public".to_owned()),
false,
false,
&TokenStream::new(),
&TokenStream::new(),
)
.into_iter()
.skip(1)
@ -1363,7 +1506,11 @@ mod tests {
entity,
&crate::WithSerde::None,
&crate::DateTimeCrate::Chrono,
&Some("schema_name".to_owned())
&Some("schema_name".to_owned()),
false,
false,
&TokenStream::new(),
&TokenStream::new(),
)
.into_iter()
.skip(1)
@ -1385,76 +1532,241 @@ mod tests {
assert_eq!(cake_entity.get_table_name_snake_case(), "cake");
// Compact code blocks
assert_serde_variant_results(
&cake_entity,
&(
include_str!("../../tests/compact_with_serde/cake_none.rs").into(),
WithSerde::None,
None,
),
Box::new(EntityWriter::gen_compact_code_blocks),
)?;
assert_serde_variant_results(
&cake_entity,
&(
include_str!("../../tests/compact_with_serde/cake_serialize.rs").into(),
WithSerde::Serialize,
None,
),
Box::new(EntityWriter::gen_compact_code_blocks),
)?;
assert_serde_variant_results(
&cake_entity,
&(
include_str!("../../tests/compact_with_serde/cake_deserialize.rs").into(),
WithSerde::Deserialize,
None,
),
Box::new(EntityWriter::gen_compact_code_blocks),
)?;
assert_serde_variant_results(
&cake_entity,
&(
include_str!("../../tests/compact_with_serde/cake_both.rs").into(),
WithSerde::Both,
None,
),
Box::new(EntityWriter::gen_compact_code_blocks),
)?;
assert_eq!(
comparable_file_string(include_str!("../../tests/compact_with_serde/cake_none.rs"))?,
generated_to_string(EntityWriter::gen_compact_code_blocks(
&cake_entity,
&WithSerde::None,
&DateTimeCrate::Chrono,
&None,
false,
false,
&TokenStream::new(),
&TokenStream::new(),
))
);
assert_eq!(
comparable_file_string(include_str!(
"../../tests/compact_with_serde/cake_serialize.rs"
))?,
generated_to_string(EntityWriter::gen_compact_code_blocks(
&cake_entity,
&WithSerde::Serialize,
&DateTimeCrate::Chrono,
&None,
false,
false,
&TokenStream::new(),
&TokenStream::new(),
))
);
assert_eq!(
comparable_file_string(include_str!(
"../../tests/compact_with_serde/cake_deserialize.rs"
))?,
generated_to_string(EntityWriter::gen_compact_code_blocks(
&cake_entity,
&WithSerde::Deserialize,
&DateTimeCrate::Chrono,
&None,
true,
false,
&TokenStream::new(),
&TokenStream::new(),
))
);
assert_eq!(
comparable_file_string(include_str!("../../tests/compact_with_serde/cake_both.rs"))?,
generated_to_string(EntityWriter::gen_compact_code_blocks(
&cake_entity,
&WithSerde::Both,
&DateTimeCrate::Chrono,
&None,
true,
false,
&TokenStream::new(),
&TokenStream::new(),
))
);
// Expanded code blocks
assert_eq!(
comparable_file_string(include_str!("../../tests/expanded_with_serde/cake_none.rs"))?,
generated_to_string(EntityWriter::gen_expanded_code_blocks(
&cake_entity,
&WithSerde::None,
&DateTimeCrate::Chrono,
&None,
false,
false,
&TokenStream::new(),
&TokenStream::new(),
))
);
assert_eq!(
comparable_file_string(include_str!(
"../../tests/expanded_with_serde/cake_serialize.rs"
))?,
generated_to_string(EntityWriter::gen_expanded_code_blocks(
&cake_entity,
&WithSerde::Serialize,
&DateTimeCrate::Chrono,
&None,
false,
false,
&TokenStream::new(),
&TokenStream::new(),
))
);
assert_eq!(
comparable_file_string(include_str!(
"../../tests/expanded_with_serde/cake_deserialize.rs"
))?,
generated_to_string(EntityWriter::gen_expanded_code_blocks(
&cake_entity,
&WithSerde::Deserialize,
&DateTimeCrate::Chrono,
&None,
true,
false,
&TokenStream::new(),
&TokenStream::new(),
))
);
assert_eq!(
comparable_file_string(include_str!("../../tests/expanded_with_serde/cake_both.rs"))?,
generated_to_string(EntityWriter::gen_expanded_code_blocks(
&cake_entity,
&WithSerde::Both,
&DateTimeCrate::Chrono,
&None,
true,
false,
&TokenStream::new(),
&TokenStream::new(),
))
);
Ok(())
}
#[test]
fn test_gen_with_derives() -> io::Result<()> {
let mut cake_entity = setup().get_mut(0).unwrap().clone();
assert_eq!(cake_entity.get_table_name_snake_case(), "cake");
// Compact code blocks
assert_eq!(
comparable_file_string(include_str!(
"../../tests/compact_with_derives/cake_none.rs"
))?,
generated_to_string(EntityWriter::gen_compact_code_blocks(
&cake_entity,
&WithSerde::None,
&DateTimeCrate::Chrono,
&None,
false,
false,
&TokenStream::new(),
&TokenStream::new(),
))
);
assert_eq!(
comparable_file_string(include_str!("../../tests/compact_with_derives/cake_one.rs"))?,
generated_to_string(EntityWriter::gen_compact_code_blocks(
&cake_entity,
&WithSerde::None,
&DateTimeCrate::Chrono,
&None,
false,
false,
&bonus_derive(vec!["ts_rs::TS"]),
&TokenStream::new(),
))
);
assert_eq!(
comparable_file_string(include_str!(
"../../tests/compact_with_derives/cake_multiple.rs"
))?,
generated_to_string(EntityWriter::gen_compact_code_blocks(
&cake_entity,
&WithSerde::None,
&DateTimeCrate::Chrono,
&None,
false,
false,
&bonus_derive(vec!["ts_rs::TS", "utoipa::ToSchema"]),
&TokenStream::new(),
))
);
// Expanded code blocks
assert_eq!(
comparable_file_string(include_str!(
"../../tests/expanded_with_derives/cake_none.rs"
))?,
generated_to_string(EntityWriter::gen_expanded_code_blocks(
&cake_entity,
&WithSerde::None,
&DateTimeCrate::Chrono,
&None,
false,
false,
&TokenStream::new(),
&TokenStream::new(),
))
);
assert_eq!(
comparable_file_string(include_str!(
"../../tests/expanded_with_derives/cake_one.rs"
))?,
generated_to_string(EntityWriter::gen_expanded_code_blocks(
&cake_entity,
&WithSerde::None,
&DateTimeCrate::Chrono,
&None,
false,
false,
&bonus_derive(vec!["ts_rs::TS"]),
&TokenStream::new(),
))
);
assert_eq!(
comparable_file_string(include_str!(
"../../tests/expanded_with_derives/cake_multiple.rs"
))?,
generated_to_string(EntityWriter::gen_expanded_code_blocks(
&cake_entity,
&WithSerde::None,
&DateTimeCrate::Chrono,
&None,
false,
false,
&bonus_derive(vec!["ts_rs::TS", "utoipa::ToSchema"]),
&TokenStream::new(),
))
);
// Make the `name` column of `cake` entity as hidden column
cake_entity.columns[1].name = "_name".into();
assert_serde_variant_results(
&cake_entity,
&(
include_str!("../../tests/expanded_with_serde/cake_none.rs").into(),
WithSerde::None,
None,
),
Box::new(EntityWriter::gen_expanded_code_blocks),
)?;
assert_serde_variant_results(
&cake_entity,
&(
include_str!("../../tests/expanded_with_serde/cake_serialize.rs").into(),
include_str!("../../tests/compact_with_serde/cake_serialize_with_hidden_column.rs"),
WithSerde::Serialize,
None,
),
Box::new(EntityWriter::gen_expanded_code_blocks),
Box::new(EntityWriter::gen_compact_code_blocks),
)?;
assert_serde_variant_results(
&cake_entity,
&(
include_str!("../../tests/expanded_with_serde/cake_deserialize.rs").into(),
WithSerde::Deserialize,
None,
),
Box::new(EntityWriter::gen_expanded_code_blocks),
)?;
assert_serde_variant_results(
&cake_entity,
&(
include_str!("../../tests/expanded_with_serde/cake_both.rs").into(),
WithSerde::Both,
include_str!(
"../../tests/expanded_with_serde/cake_serialize_with_hidden_column.rs"
),
WithSerde::Serialize,
None,
),
Box::new(EntityWriter::gen_expanded_code_blocks),
@ -1466,13 +1778,174 @@ mod tests {
#[allow(clippy::type_complexity)]
fn assert_serde_variant_results(
cake_entity: &Entity,
entity_serde_variant: &(String, WithSerde, Option<String>),
entity_serde_variant: &(&str, WithSerde, Option<String>),
generator: Box<
dyn Fn(&Entity, &WithSerde, &DateTimeCrate, &Option<String>) -> Vec<TokenStream>,
dyn Fn(
&Entity,
&WithSerde,
&DateTimeCrate,
&Option<String>,
bool,
bool,
&TokenStream,
&TokenStream,
) -> Vec<TokenStream>,
>,
) -> io::Result<()> {
let mut reader = BufReader::new(entity_serde_variant.0.as_bytes());
let mut lines: Vec<String> = Vec::new();
let serde_skip_deserializing_primary_key = matches!(
entity_serde_variant.1,
WithSerde::Both | WithSerde::Deserialize
);
let serde_skip_hidden_column = matches!(entity_serde_variant.1, WithSerde::Serialize);
reader.read_until(b'\n', &mut Vec::new())?;
let mut line = String::new();
while reader.read_line(&mut line)? > 0 {
lines.push(line.to_owned());
line.clear();
}
let content = lines.join("");
let expected: TokenStream = content.parse().unwrap();
println!("{:?}", entity_serde_variant.1);
let generated = generator(
cake_entity,
&entity_serde_variant.1,
&DateTimeCrate::Chrono,
&entity_serde_variant.2,
serde_skip_deserializing_primary_key,
serde_skip_hidden_column,
&TokenStream::new(),
&TokenStream::new(),
)
.into_iter()
.fold(TokenStream::new(), |mut acc, tok| {
acc.extend(tok);
acc
});
assert_eq!(expected.to_string(), generated.to_string());
Ok(())
}
#[test]
fn test_gen_with_attributes() -> io::Result<()> {
let cake_entity = setup().get(0).unwrap().clone();
assert_eq!(cake_entity.get_table_name_snake_case(), "cake");
// Compact code blocks
assert_eq!(
comparable_file_string(include_str!(
"../../tests/compact_with_attributes/cake_none.rs"
))?,
generated_to_string(EntityWriter::gen_compact_code_blocks(
&cake_entity,
&WithSerde::None,
&DateTimeCrate::Chrono,
&None,
false,
false,
&TokenStream::new(),
&TokenStream::new(),
))
);
assert_eq!(
comparable_file_string(include_str!(
"../../tests/compact_with_attributes/cake_one.rs"
))?,
generated_to_string(EntityWriter::gen_compact_code_blocks(
&cake_entity,
&WithSerde::None,
&DateTimeCrate::Chrono,
&None,
false,
false,
&TokenStream::new(),
&bonus_attributes(vec![r#"serde(rename_all = "camelCase")"#]),
))
);
assert_eq!(
comparable_file_string(include_str!(
"../../tests/compact_with_attributes/cake_multiple.rs"
))?,
generated_to_string(EntityWriter::gen_compact_code_blocks(
&cake_entity,
&WithSerde::None,
&DateTimeCrate::Chrono,
&None,
false,
false,
&TokenStream::new(),
&bonus_attributes(vec![r#"serde(rename_all = "camelCase")"#, "ts(export)"]),
))
);
// Expanded code blocks
assert_eq!(
comparable_file_string(include_str!(
"../../tests/expanded_with_attributes/cake_none.rs"
))?,
generated_to_string(EntityWriter::gen_expanded_code_blocks(
&cake_entity,
&WithSerde::None,
&DateTimeCrate::Chrono,
&None,
false,
false,
&TokenStream::new(),
&TokenStream::new(),
))
);
assert_eq!(
comparable_file_string(include_str!(
"../../tests/expanded_with_attributes/cake_one.rs"
))?,
generated_to_string(EntityWriter::gen_expanded_code_blocks(
&cake_entity,
&WithSerde::None,
&DateTimeCrate::Chrono,
&None,
false,
false,
&TokenStream::new(),
&bonus_attributes(vec![r#"serde(rename_all = "camelCase")"#]),
))
);
assert_eq!(
comparable_file_string(include_str!(
"../../tests/expanded_with_attributes/cake_multiple.rs"
))?,
generated_to_string(EntityWriter::gen_expanded_code_blocks(
&cake_entity,
&WithSerde::None,
&DateTimeCrate::Chrono,
&None,
false,
false,
&TokenStream::new(),
&bonus_attributes(vec![r#"serde(rename_all = "camelCase")"#, "ts(export)"]),
))
);
Ok(())
}
fn generated_to_string(generated: Vec<TokenStream>) -> String {
generated
.into_iter()
.fold(TokenStream::new(), |mut acc, tok| {
acc.extend(tok);
acc
})
.to_string()
}
fn comparable_file_string(file: &str) -> io::Result<String> {
let mut reader = BufReader::new(file.as_bytes());
let mut lines: Vec<String> = Vec::new();
reader.read_until(b'\n', &mut Vec::new())?;
@ -1483,19 +1956,7 @@ mod tests {
}
let content = lines.join("");
let expected: TokenStream = content.parse().unwrap();
let generated = generator(
cake_entity,
&entity_serde_variant.1,
&DateTimeCrate::Chrono,
&entity_serde_variant.2,
)
.into_iter()
.fold(TokenStream::new(), |mut acc, tok| {
acc.extend(tok);
acc
});
assert_eq!(expected.to_string(), generated.to_string());
Ok(())
Ok(expected.to_string())
}
}

View File

@ -0,0 +1,37 @@
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
use sea_orm::entity::prelude:: * ;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "cake")]
#[serde(rename_all = "camelCase")]
#[ts(export)]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
#[sea_orm(column_type = "Text", nullable)]
pub name: Option<String> ,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(has_many = "super::fruit::Entity")]
Fruit,
}
impl Related<super::fruit::Entity> for Entity {
fn to() -> RelationDef {
Relation::Fruit.def()
}
}
impl Related<super::filling::Entity> for Entity {
fn to() -> RelationDef {
super::cake_filling::Relation::Filling.def()
}
fn via() -> Option<RelationDef> {
Some(super::cake_filling::Relation::Cake.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@ -0,0 +1,35 @@
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
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,
#[sea_orm(column_type = "Text", nullable)]
pub name: Option<String> ,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(has_many = "super::fruit::Entity")]
Fruit,
}
impl Related<super::fruit::Entity> for Entity {
fn to() -> RelationDef {
Relation::Fruit.def()
}
}
impl Related<super::filling::Entity> for Entity {
fn to() -> RelationDef {
super::cake_filling::Relation::Filling.def()
}
fn via() -> Option<RelationDef> {
Some(super::cake_filling::Relation::Cake.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@ -0,0 +1,36 @@
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
use sea_orm::entity::prelude:: * ;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "cake")]
#[serde(rename_all = "camelCase")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
#[sea_orm(column_type = "Text", nullable)]
pub name: Option<String> ,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(has_many = "super::fruit::Entity")]
Fruit,
}
impl Related<super::fruit::Entity> for Entity {
fn to() -> RelationDef {
Relation::Fruit.def()
}
}
impl Related<super::filling::Entity> for Entity {
fn to() -> RelationDef {
super::cake_filling::Relation::Filling.def()
}
fn via() -> Option<RelationDef> {
Some(super::cake_filling::Relation::Cake.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@ -0,0 +1,35 @@
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
use sea_orm::entity::prelude:: * ;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, ts_rs::TS, utoipa::ToSchema)]
#[sea_orm(table_name = "cake")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
#[sea_orm(column_type = "Text", nullable)]
pub name: Option<String> ,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(has_many = "super::fruit::Entity")]
Fruit,
}
impl Related<super::fruit::Entity> for Entity {
fn to() -> RelationDef {
Relation::Fruit.def()
}
}
impl Related<super::filling::Entity> for Entity {
fn to() -> RelationDef {
super::cake_filling::Relation::Filling.def()
}
fn via() -> Option<RelationDef> {
Some(super::cake_filling::Relation::Cake.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@ -0,0 +1,35 @@
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
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,
#[sea_orm(column_type = "Text", nullable)]
pub name: Option<String> ,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(has_many = "super::fruit::Entity")]
Fruit,
}
impl Related<super::fruit::Entity> for Entity {
fn to() -> RelationDef {
Relation::Fruit.def()
}
}
impl Related<super::filling::Entity> for Entity {
fn to() -> RelationDef {
super::cake_filling::Relation::Filling.def()
}
fn via() -> Option<RelationDef> {
Some(super::cake_filling::Relation::Cake.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@ -0,0 +1,35 @@
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
use sea_orm::entity::prelude:: * ;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, ts_rs::TS)]
#[sea_orm(table_name = "cake")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
#[sea_orm(column_type = "Text", nullable)]
pub name: Option<String> ,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(has_many = "super::fruit::Entity")]
Fruit,
}
impl Related<super::fruit::Entity> for Entity {
fn to() -> RelationDef {
Relation::Fruit.def()
}
}
impl Related<super::filling::Entity> for Entity {
fn to() -> RelationDef {
super::cake_filling::Relation::Filling.def()
}
fn via() -> Option<RelationDef> {
Some(super::cake_filling::Relation::Cake.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@ -7,6 +7,7 @@ use serde::{Deserialize, Serialize};
#[sea_orm(table_name = "cake")]
pub struct Model {
#[sea_orm(primary_key)]
#[serde(skip_deserializing)]
pub id: i32,
#[sea_orm(column_type = "Text", nullable)]
pub name: Option<String> ,

View File

@ -7,6 +7,7 @@ use serde::Deserialize;
#[sea_orm(table_name = "cake")]
pub struct Model {
#[sea_orm(primary_key)]
#[serde(skip_deserializing)]
pub id: i32,
#[sea_orm(column_type = "Text", nullable)]
pub name: Option<String> ,

View File

@ -0,0 +1,37 @@
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
use sea_orm::entity::prelude:: * ;
use serde::Serialize;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize)]
#[sea_orm(table_name = "cake")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
#[sea_orm(column_name = "_name", column_type = "Text", nullable)]
#[serde(skip)]
pub name: Option<String> ,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(has_many = "super::fruit::Entity")]
Fruit,
}
impl Related<super::fruit::Entity> for Entity {
fn to() -> RelationDef {
Relation::Fruit.def()
}
}
impl Related<super::filling::Entity> for Entity {
fn to() -> RelationDef {
super::cake_filling::Relation::Filling.def()
}
fn via() -> Option<RelationDef> {
Some(super::cake_filling::Relation::Cake.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@ -0,0 +1,79 @@
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
use sea_orm::entity::prelude:: * ;
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
pub struct Entity;
impl EntityName for Entity {
fn table_name(&self) -> &str {
"cake"
}
}
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Eq)]
#[serde(rename_all = "camelCase")]
#[ts(export)]
pub struct Model {
pub id: i32,
pub name: Option<String> ,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
pub enum Column {
Id,
Name,
}
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
pub enum PrimaryKey {
Id,
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}
}
#[derive(Copy, Clone, Debug, EnumIter)]
pub enum Relation {
Fruit,
}
impl ColumnTrait for Column {
type EntityName = Entity;
fn def(&self) -> ColumnDef {
match self {
Self::Id => ColumnType::Integer.def(),
Self::Name => ColumnType::Text.def().null(),
}
}
}
impl RelationTrait for Relation {
fn def(&self) -> RelationDef {
match self {
Self::Fruit => Entity::has_many(super::fruit::Entity).into(),
}
}
}
impl Related<super::fruit::Entity> for Entity {
fn to() -> RelationDef {
Relation::Fruit.def()
}
}
impl Related<super::filling::Entity> for Entity {
fn to() -> RelationDef {
super::cake_filling::Relation::Filling.def()
}
fn via() -> Option<RelationDef> {
Some(super::cake_filling::Relation::Cake.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@ -0,0 +1,77 @@
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
use sea_orm::entity::prelude:: * ;
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
pub struct Entity;
impl EntityName for Entity {
fn table_name(&self) -> &str {
"cake"
}
}
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Eq)]
pub struct Model {
pub id: i32,
pub name: Option<String> ,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
pub enum Column {
Id,
Name,
}
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
pub enum PrimaryKey {
Id,
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}
}
#[derive(Copy, Clone, Debug, EnumIter)]
pub enum Relation {
Fruit,
}
impl ColumnTrait for Column {
type EntityName = Entity;
fn def(&self) -> ColumnDef {
match self {
Self::Id => ColumnType::Integer.def(),
Self::Name => ColumnType::Text.def().null(),
}
}
}
impl RelationTrait for Relation {
fn def(&self) -> RelationDef {
match self {
Self::Fruit => Entity::has_many(super::fruit::Entity).into(),
}
}
}
impl Related<super::fruit::Entity> for Entity {
fn to() -> RelationDef {
Relation::Fruit.def()
}
}
impl Related<super::filling::Entity> for Entity {
fn to() -> RelationDef {
super::cake_filling::Relation::Filling.def()
}
fn via() -> Option<RelationDef> {
Some(super::cake_filling::Relation::Cake.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@ -0,0 +1,78 @@
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
use sea_orm::entity::prelude:: * ;
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
pub struct Entity;
impl EntityName for Entity {
fn table_name(&self) -> &str {
"cake"
}
}
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Eq)]
#[serde(rename_all = "camelCase")]
pub struct Model {
pub id: i32,
pub name: Option<String> ,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
pub enum Column {
Id,
Name,
}
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
pub enum PrimaryKey {
Id,
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}
}
#[derive(Copy, Clone, Debug, EnumIter)]
pub enum Relation {
Fruit,
}
impl ColumnTrait for Column {
type EntityName = Entity;
fn def(&self) -> ColumnDef {
match self {
Self::Id => ColumnType::Integer.def(),
Self::Name => ColumnType::Text.def().null(),
}
}
}
impl RelationTrait for Relation {
fn def(&self) -> RelationDef {
match self {
Self::Fruit => Entity::has_many(super::fruit::Entity).into(),
}
}
}
impl Related<super::fruit::Entity> for Entity {
fn to() -> RelationDef {
Relation::Fruit.def()
}
}
impl Related<super::filling::Entity> for Entity {
fn to() -> RelationDef {
super::cake_filling::Relation::Filling.def()
}
fn via() -> Option<RelationDef> {
Some(super::cake_filling::Relation::Cake.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@ -0,0 +1,77 @@
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
use sea_orm::entity::prelude:: * ;
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
pub struct Entity;
impl EntityName for Entity {
fn table_name(&self) -> &str {
"cake"
}
}
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Eq, ts_rs::TS, utoipa::ToSchema)]
pub struct Model {
pub id: i32,
pub name: Option<String> ,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
pub enum Column {
Id,
Name,
}
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
pub enum PrimaryKey {
Id,
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}
}
#[derive(Copy, Clone, Debug, EnumIter)]
pub enum Relation {
Fruit,
}
impl ColumnTrait for Column {
type EntityName = Entity;
fn def(&self) -> ColumnDef {
match self {
Self::Id => ColumnType::Integer.def(),
Self::Name => ColumnType::Text.def().null(),
}
}
}
impl RelationTrait for Relation {
fn def(&self) -> RelationDef {
match self {
Self::Fruit => Entity::has_many(super::fruit::Entity).into(),
}
}
}
impl Related<super::fruit::Entity> for Entity {
fn to() -> RelationDef {
Relation::Fruit.def()
}
}
impl Related<super::filling::Entity> for Entity {
fn to() -> RelationDef {
super::cake_filling::Relation::Filling.def()
}
fn via() -> Option<RelationDef> {
Some(super::cake_filling::Relation::Cake.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@ -0,0 +1,77 @@
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
use sea_orm::entity::prelude:: * ;
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
pub struct Entity;
impl EntityName for Entity {
fn table_name(&self) -> &str {
"cake"
}
}
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Eq)]
pub struct Model {
pub id: i32,
pub name: Option<String> ,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
pub enum Column {
Id,
Name,
}
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
pub enum PrimaryKey {
Id,
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}
}
#[derive(Copy, Clone, Debug, EnumIter)]
pub enum Relation {
Fruit,
}
impl ColumnTrait for Column {
type EntityName = Entity;
fn def(&self) -> ColumnDef {
match self {
Self::Id => ColumnType::Integer.def(),
Self::Name => ColumnType::Text.def().null(),
}
}
}
impl RelationTrait for Relation {
fn def(&self) -> RelationDef {
match self {
Self::Fruit => Entity::has_many(super::fruit::Entity).into(),
}
}
}
impl Related<super::fruit::Entity> for Entity {
fn to() -> RelationDef {
Relation::Fruit.def()
}
}
impl Related<super::filling::Entity> for Entity {
fn to() -> RelationDef {
super::cake_filling::Relation::Filling.def()
}
fn via() -> Option<RelationDef> {
Some(super::cake_filling::Relation::Cake.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@ -0,0 +1,77 @@
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
use sea_orm::entity::prelude:: * ;
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
pub struct Entity;
impl EntityName for Entity {
fn table_name(&self) -> &str {
"cake"
}
}
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Eq, ts_rs::TS)]
pub struct Model {
pub id: i32,
pub name: Option<String> ,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
pub enum Column {
Id,
Name,
}
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
pub enum PrimaryKey {
Id,
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}
}
#[derive(Copy, Clone, Debug, EnumIter)]
pub enum Relation {
Fruit,
}
impl ColumnTrait for Column {
type EntityName = Entity;
fn def(&self) -> ColumnDef {
match self {
Self::Id => ColumnType::Integer.def(),
Self::Name => ColumnType::Text.def().null(),
}
}
}
impl RelationTrait for Relation {
fn def(&self) -> RelationDef {
match self {
Self::Fruit => Entity::has_many(super::fruit::Entity).into(),
}
}
}
impl Related<super::fruit::Entity> for Entity {
fn to() -> RelationDef {
Relation::Fruit.def()
}
}
impl Related<super::filling::Entity> for Entity {
fn to() -> RelationDef {
super::cake_filling::Relation::Filling.def()
}
fn via() -> Option<RelationDef> {
Some(super::cake_filling::Relation::Cake.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@ -14,6 +14,7 @@ impl EntityName for Entity {
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Eq, Serialize, Deserialize)]
pub struct Model {
#[serde(skip_deserializing)]
pub id: i32,
pub name: Option<String> ,
}

View File

@ -14,6 +14,7 @@ impl EntityName for Entity {
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Eq, Deserialize)]
pub struct Model {
#[serde(skip_deserializing)]
pub id: i32,
pub name: Option<String> ,
}

View File

@ -0,0 +1,80 @@
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
use sea_orm::entity::prelude:: * ;
use serde::Serialize;
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
pub struct Entity;
impl EntityName for Entity {
fn table_name(&self) -> &str {
"cake"
}
}
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Eq, Serialize)]
pub struct Model {
pub id: i32,
#[serde(skip)]
pub name: Option<String> ,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
pub enum Column {
Id,
#[sea_orm(column_name = "_name")]
Name,
}
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
pub enum PrimaryKey {
Id,
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}
}
#[derive(Copy, Clone, Debug, EnumIter)]
pub enum Relation {
Fruit,
}
impl ColumnTrait for Column {
type EntityName = Entity;
fn def(&self) -> ColumnDef {
match self {
Self::Id => ColumnType::Integer.def(),
Self::Name => ColumnType::Text.def().null(),
}
}
}
impl RelationTrait for Relation {
fn def(&self) -> RelationDef {
match self {
Self::Fruit => Entity::has_many(super::fruit::Entity).into(),
}
}
}
impl Related<super::fruit::Entity> for Entity {
fn to() -> RelationDef {
Relation::Fruit.def()
}
}
impl Related<super::filling::Entity> for Entity {
fn to() -> RelationDef {
super::cake_filling::Relation::Filling.def()
}
fn via() -> Option<RelationDef> {
Some(super::cake_filling::Relation::Cake.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@ -18,15 +18,15 @@ path = "src/lib.rs"
proc-macro = true
[dependencies]
bae = "^0.1"
syn = { version = "^1", default-features = false, features = [ "full", "derive", "clone-impls", "parsing", "proc-macro", "printing", "extra-traits" ] }
quote = "^1"
heck = "^0.3"
proc-macro2 = "^1"
bae = { version = "0.1", default-features = false }
syn = { version = "1", default-features = false }
quote = { version = "1", default-features = false }
heck = { version = "0.3", default-features = false }
proc-macro2 = { version = "1", default-features = false }
[dev-dependencies]
sea-orm = { path = "../", features = ["macros"] }
serde = { version = "^1.0", features = ["derive"] }
serde = { version = "1.0", features = ["derive"] }
[features]
postgres-array = []

View File

@ -20,17 +20,17 @@ name = "sea_orm_migration"
path = "src/lib.rs"
[dependencies]
async-trait = { version = "^0.1" }
clap = { version = "^3.2", features = ["env", "derive"], optional = true }
dotenvy = { version = "^0.15", optional = true }
sea-orm = { version = "^0.10.3", path = "../", default-features = false, features = ["macros"] }
sea-orm-cli = { version = "^0.10.3", path = "../sea-orm-cli", default-features = false, optional = true }
sea-schema = { version = "^0.10.2" }
tracing = { version = "0.1", features = ["log"] }
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
async-trait = { version = "0.1", default-features = false }
clap = { version = "3.2", default-features = false, features = ["std", "env", "derive"], optional = true }
dotenvy = { version = "0.15", default-features = false, optional = true }
sea-orm = { version = "0.10.3", path = "../", default-features = false, features = ["macros"] }
sea-orm-cli = { version = "0.10.3", path = "../sea-orm-cli", default-features = false, optional = true }
sea-schema = { version = "0.10.2" }
tracing = { version = "0.1", default-features = false, features = ["log"] }
tracing-subscriber = { version = "0.3", default-features = false, features = ["env-filter", "fmt"] }
[dev-dependencies]
async-std = { version = "^1", features = ["attributes", "tokio1"] }
async-std = { version = "1", features = ["attributes", "tokio1"] }
[features]
default = ["cli"]

View File

@ -174,9 +174,8 @@ impl DatabaseTransaction {
/// Commit a transaction atomically
#[instrument(level = "trace")]
#[allow(unreachable_code)]
#[allow(unreachable_code, unused_mut)]
pub async fn commit(mut self) -> Result<(), DbErr> {
self.open = false;
match *self.conn.lock().await {
#[cfg(feature = "sqlx-mysql")]
InnerConnection::MySql(ref mut c) => {
@ -201,14 +200,14 @@ impl DatabaseTransaction {
c.commit();
}
}
self.open = false;
Ok(())
}
/// rolls back a transaction in case error are encountered during the operation
#[instrument(level = "trace")]
#[allow(unreachable_code)]
#[allow(unreachable_code, unused_mut)]
pub async fn rollback(mut self) -> Result<(), DbErr> {
self.open = false;
match *self.conn.lock().await {
#[cfg(feature = "sqlx-mysql")]
InnerConnection::MySql(ref mut c) => {
@ -233,6 +232,7 @@ impl DatabaseTransaction {
c.rollback();
}
}
self.open = false;
Ok(())
}

View File

@ -1,6 +1,9 @@
use crate::{EntityTrait, Identity, IdentityOf, Iterable, QuerySelect, Select};
use crate::{unpack_table_ref, EntityTrait, Identity, IdentityOf, Iterable, QuerySelect, Select};
use core::marker::PhantomData;
use sea_query::{Alias, Condition, DynIden, JoinType, SeaRc, TableRef};
use sea_query::{
Alias, Condition, DynIden, ForeignKeyCreateStatement, JoinType, SeaRc, TableForeignKey,
TableRef,
};
use std::fmt::Debug;
/// Defines the type of relationship
@ -309,6 +312,98 @@ where
}
}
macro_rules! set_foreign_key_stmt {
( $relation: ident, $foreign_key: ident ) => {
let from_cols: Vec<String> = match $relation.from_col {
Identity::Unary(o1) => vec![o1],
Identity::Binary(o1, o2) => vec![o1, o2],
Identity::Ternary(o1, o2, o3) => vec![o1, o2, o3],
}
.into_iter()
.map(|col| {
let col_name = col.to_string();
$foreign_key.from_col(col);
col_name
})
.collect();
match $relation.to_col {
Identity::Unary(o1) => {
$foreign_key.to_col(o1);
}
Identity::Binary(o1, o2) => {
$foreign_key.to_col(o1);
$foreign_key.to_col(o2);
}
Identity::Ternary(o1, o2, o3) => {
$foreign_key.to_col(o1);
$foreign_key.to_col(o2);
$foreign_key.to_col(o3);
}
}
if let Some(action) = $relation.on_delete {
$foreign_key.on_delete(action);
}
if let Some(action) = $relation.on_update {
$foreign_key.on_update(action);
}
let name = if let Some(name) = $relation.fk_name {
name
} else {
let from_tbl = unpack_table_ref(&$relation.from_tbl);
format!("fk-{}-{}", from_tbl.to_string(), from_cols.join("-"))
};
$foreign_key.name(&name);
};
}
impl From<RelationDef> for ForeignKeyCreateStatement {
fn from(relation: RelationDef) -> Self {
let mut foreign_key_stmt = Self::new();
set_foreign_key_stmt!(relation, foreign_key_stmt);
foreign_key_stmt
.from_tbl(unpack_table_ref(&relation.from_tbl))
.to_tbl(unpack_table_ref(&relation.to_tbl))
.take()
}
}
/// Creates a column definition for example to update a table.
/// ```
/// use sea_query::{Alias, IntoIden, MysqlQueryBuilder, TableAlterStatement, TableRef};
/// use sea_orm::{EnumIter, Iden, Identity, PrimaryKeyTrait, RelationDef, RelationTrait, RelationType};
///
/// let relation = RelationDef {
/// rel_type: RelationType::HasOne,
/// from_tbl: TableRef::Table(Alias::new("foo").into_iden()),
/// to_tbl: TableRef::Table(Alias::new("bar").into_iden()),
/// from_col: Identity::Unary(Alias::new("bar_id").into_iden()),
/// to_col: Identity::Unary(Alias::new("bar_id").into_iden()),
/// is_owner: false,
/// on_delete: None,
/// on_update: None,
/// on_condition: None,
/// fk_name: Some("foo-bar".to_string()),
/// };
///
/// let mut alter_table = TableAlterStatement::new()
/// .table(TableRef::Table(Alias::new("foo").into_iden()))
/// .add_foreign_key(&mut relation.into()).take();
/// assert_eq!(
/// alter_table.to_string(MysqlQueryBuilder::default()),
/// "ALTER TABLE `foo` ADD CONSTRAINT `foo-bar` FOREIGN KEY (`bar_id`) REFERENCES `bar` (`bar_id`)"
/// );
/// ```
impl From<RelationDef> for TableForeignKey {
fn from(relation: RelationDef) -> Self {
let mut foreign_key = Self::new();
set_foreign_key_stmt!(relation, foreign_key);
foreign_key
.from_tbl(unpack_table_ref(&relation.from_tbl))
.to_tbl(unpack_table_ref(&relation.to_tbl))
.take()
}
}
#[cfg(test)]
mod tests {
use crate::{

View File

@ -45,8 +45,8 @@ where
let query = self
.query
.clone()
.limit(self.page_size as u64)
.offset((self.page_size * page) as u64)
.limit(self.page_size)
.offset(self.page_size * page)
.to_owned();
let builder = self.db.get_database_backend();
let stmt = builder.build(&query);

View File

@ -189,7 +189,8 @@ where
for col in E::Column::iter() {
let av = model.get(col);
if av.is_set() {
self.query.value(col, av.unwrap());
let expr = cast_text_as_enum(Expr::val(av.into_value().unwrap()), &col);
self.query.value(col, expr);
}
}
self
@ -207,7 +208,7 @@ where
#[cfg(test)]
mod tests {
use crate::tests_cfg::{cake, fruit};
use crate::tests_cfg::{cake, fruit, lunch_set, sea_orm_active_enums::Tea};
use crate::{entity::*, query::*, DbBackend};
use sea_query::{Expr, Value};
@ -294,4 +295,33 @@ mod tests {
r#"UPDATE "fruit" SET "id" = 3 WHERE "fruit"."id" = 2"#,
);
}
#[test]
fn update_7() {
assert_eq!(
Update::many(lunch_set::Entity)
.set(lunch_set::ActiveModel {
tea: Set(Tea::EverydayTea),
..Default::default()
})
.filter(lunch_set::Column::Tea.eq(Tea::BreakfastTea))
.build(DbBackend::Postgres)
.to_string(),
r#"UPDATE "lunch_set" SET "tea" = CAST('EverydayTea' AS tea) WHERE "lunch_set"."tea" = CAST('BreakfastTea' AS tea)"#,
);
}
#[test]
fn update_8() {
assert_eq!(
Update::one(lunch_set::ActiveModel {
id: Unchanged(1),
tea: Set(Tea::EverydayTea),
..Default::default()
})
.build(DbBackend::Postgres)
.to_string(),
r#"UPDATE "lunch_set" SET "tea" = CAST('EverydayTea' AS tea) WHERE "lunch_set"."id" = 1"#,
);
}
}

View File

@ -1,10 +1,10 @@
use crate::{
unpack_table_ref, ActiveEnum, ColumnTrait, ColumnType, DbBackend, EntityTrait, Identity,
Iterable, PrimaryKeyToColumn, PrimaryKeyTrait, RelationTrait, Schema,
ActiveEnum, ColumnTrait, ColumnType, DbBackend, EntityTrait, Iterable, PrimaryKeyToColumn,
PrimaryKeyTrait, RelationTrait, Schema,
};
use sea_query::{
extension::postgres::{Type, TypeCreateStatement},
ColumnDef, ForeignKeyCreateStatement, Iden, Index, IndexCreateStatement, TableCreateStatement,
ColumnDef, Iden, Index, IndexCreateStatement, TableCreateStatement,
};
impl Schema {
@ -40,6 +40,51 @@ impl Schema {
{
create_index_from_entity(entity, self.backend)
}
/// Creates a column definition for example to update a table.
/// ```
/// use crate::sea_orm::IdenStatic;
/// use sea_orm::{
/// ActiveModelBehavior, ColumnDef, ColumnTrait, ColumnType, DbBackend, EntityName,
/// EntityTrait, EnumIter, PrimaryKeyTrait, RelationDef, RelationTrait, Schema,
/// };
/// use sea_orm_macros::{DeriveEntityModel, DerivePrimaryKey};
/// use sea_query::{MysqlQueryBuilder, TableAlterStatement};
///
/// #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
/// #[sea_orm(table_name = "posts")]
/// pub struct Model {
/// #[sea_orm(primary_key)]
/// pub id: u32,
/// pub title: String,
/// }
///
/// #[derive(Copy, Clone, Debug, EnumIter)]
/// pub enum Relation {}
/// impl RelationTrait for Relation {
/// fn def(&self) -> RelationDef {
/// panic!("No RelationDef")
/// }
/// }
/// impl ActiveModelBehavior for ActiveModel {}
///
/// let schema = Schema::new(DbBackend::MySql);
///
/// let mut alter_table = TableAlterStatement::new()
/// .table(Entity)
/// .add_column(&mut schema.get_column_def::<Entity>(Column::Title))
/// .take();
/// assert_eq!(
/// alter_table.to_string(MysqlQueryBuilder::default()),
/// "ALTER TABLE `posts` ADD COLUMN `title` varchar(255) NOT NULL"
/// );
/// ```
pub fn get_column_def<E>(&self, column: E::Column) -> ColumnDef
where
E: EntityTrait,
{
column_def_from_entity_column::<E>(column, self.backend)
}
}
pub(crate) fn create_enum_from_active_enum<A>(backend: DbBackend) -> TypeCreateStatement
@ -117,39 +162,7 @@ where
let mut stmt = TableCreateStatement::new();
for column in E::Column::iter() {
let orm_column_def = column.def();
let types = match orm_column_def.col_type {
ColumnType::Enum { name, variants } => match backend {
DbBackend::MySql => {
let variants: Vec<String> = variants.iter().map(|v| v.to_string()).collect();
ColumnType::Custom(format!("ENUM('{}')", variants.join("', '")))
}
DbBackend::Postgres => ColumnType::Custom(name.to_string()),
DbBackend::Sqlite => ColumnType::Text,
}
.into(),
_ => orm_column_def.col_type.into(),
};
let mut column_def = ColumnDef::new_with_type(column, types);
if !orm_column_def.null {
column_def.not_null();
}
if orm_column_def.unique {
column_def.unique_key();
}
if let Some(value) = orm_column_def.default_value {
column_def.default(value);
}
for primary_key in E::PrimaryKey::iter() {
if column.to_string() == primary_key.into_column().to_string() {
if E::PrimaryKey::auto_increment() {
column_def.auto_increment();
}
if E::PrimaryKey::iter().count() == 1 {
column_def.primary_key();
}
}
}
let mut column_def = column_def_from_entity_column::<E>(column, backend);
stmt.col(&mut column_def);
}
@ -166,57 +179,52 @@ where
if relation.is_owner {
continue;
}
let mut foreign_key_stmt = ForeignKeyCreateStatement::new();
let from_tbl = unpack_table_ref(&relation.from_tbl);
let to_tbl = unpack_table_ref(&relation.to_tbl);
let from_cols: Vec<String> = match relation.from_col {
Identity::Unary(o1) => vec![o1],
Identity::Binary(o1, o2) => vec![o1, o2],
Identity::Ternary(o1, o2, o3) => vec![o1, o2, o3],
}
.into_iter()
.map(|col| {
let col_name = col.to_string();
foreign_key_stmt.from_col(col);
col_name
})
.collect();
match relation.to_col {
Identity::Unary(o1) => {
foreign_key_stmt.to_col(o1);
}
Identity::Binary(o1, o2) => {
foreign_key_stmt.to_col(o1);
foreign_key_stmt.to_col(o2);
}
Identity::Ternary(o1, o2, o3) => {
foreign_key_stmt.to_col(o1);
foreign_key_stmt.to_col(o2);
foreign_key_stmt.to_col(o3);
}
}
if let Some(action) = relation.on_delete {
foreign_key_stmt.on_delete(action);
}
if let Some(action) = relation.on_update {
foreign_key_stmt.on_update(action);
}
let name = if let Some(name) = relation.fk_name {
name
} else {
format!("fk-{}-{}", from_tbl.to_string(), from_cols.join("-"))
};
stmt.foreign_key(
foreign_key_stmt
.name(&name)
.from_tbl(from_tbl)
.to_tbl(to_tbl),
);
stmt.foreign_key(&mut relation.into());
}
stmt.table(entity.table_ref()).take()
}
fn column_def_from_entity_column<E>(column: E::Column, backend: DbBackend) -> ColumnDef
where
E: EntityTrait,
{
let orm_column_def = column.def();
let types = match orm_column_def.col_type {
ColumnType::Enum { name, variants } => match backend {
DbBackend::MySql => {
let variants: Vec<String> = variants.iter().map(|v| v.to_string()).collect();
ColumnType::Custom(format!("ENUM('{}')", variants.join("', '")))
}
DbBackend::Postgres => ColumnType::Custom(name.to_string()),
DbBackend::Sqlite => ColumnType::Text,
}
.into(),
_ => orm_column_def.col_type.into(),
};
let mut column_def = ColumnDef::new_with_type(column, types);
if !orm_column_def.null {
column_def.not_null();
}
if orm_column_def.unique {
column_def.unique_key();
}
if let Some(value) = orm_column_def.default_value {
column_def.default(value);
}
for primary_key in E::PrimaryKey::iter() {
if column.to_string() == primary_key.into_column().to_string() {
if E::PrimaryKey::auto_increment() {
column_def.auto_increment();
}
if E::PrimaryKey::iter().count() == 1 {
column_def.primary_key();
}
}
}
column_def
}
#[cfg(test)]
mod tests {
use crate::{sea_query::*, tests_cfg::*, DbBackend, EntityName, Schema};

View File

@ -0,0 +1,70 @@
use sea_orm::entity::prelude::*;
use sea_orm::{
sea_query::{ArrayType, ColumnType, SeaRc, ValueType},
TryGetError, TryGetable,
};
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "event_trigger")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub events: Events,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Event(pub String);
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Events(pub Vec<Event>);
impl From<Events> for Value {
fn from(events: Events) -> Self {
let Events(events) = events;
Value::Array(
ArrayType::String,
Some(Box::new(
events
.into_iter()
.map(|Event(s)| Value::String(Some(Box::new(s))))
.collect(),
)),
)
}
}
impl TryGetable for Events {
fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result<Self, TryGetError> {
let vec: Vec<String> = res.try_get(pre, col).map_err(TryGetError::DbErr)?;
Ok(Events(vec.into_iter().map(Event).collect()))
}
}
impl ValueType for Events {
fn try_from(v: Value) -> Result<Self, sea_query::ValueTypeErr> {
let value: Option<Vec<String>> =
v.expect("This Value::Array should consist of Value::String");
let vec = match value {
Some(v) => v.into_iter().map(Event).collect(),
None => vec![],
};
Ok(Events(vec))
}
fn type_name() -> String {
stringify!(Events).to_owned()
}
fn array_type() -> ArrayType {
ArrayType::String
}
fn column_type() -> ColumnType {
ColumnType::Array(SeaRc::new(Box::new(ColumnType::String(None))))
}
}

View File

@ -4,6 +4,7 @@ pub mod applog;
pub mod byte_primary_key;
pub mod collection;
pub mod custom_active_model;
pub mod event_trigger;
pub mod insert_default;
pub mod json_struct;
pub mod json_vec;
@ -21,6 +22,7 @@ pub use active_enum_child::Entity as ActiveEnumChild;
pub use applog::Entity as Applog;
pub use byte_primary_key::Entity as BytePrimaryKey;
pub use collection::Entity as Collection;
pub use event_trigger::Entity as EventTrigger;
pub use insert_default::Entity as InsertDefault;
pub use json_struct::Entity as JsonStruct;
pub use json_vec::Entity as JsonVec;

View File

@ -45,6 +45,7 @@ pub async fn create_tables(db: &DatabaseConnection) -> Result<(), DbErr> {
if DbBackend::Postgres == db_backend {
create_collection_table(db).await?;
create_event_trigger_table(db).await?;
}
Ok(())
@ -411,3 +412,23 @@ pub async fn create_pi_table(db: &DbConn) -> Result<ExecResult, DbErr> {
create_table(db, &stmt, Pi).await
}
pub async fn create_event_trigger_table(db: &DbConn) -> Result<ExecResult, DbErr> {
let stmt = sea_query::Table::create()
.table(event_trigger::Entity)
.col(
ColumnDef::new(event_trigger::Column::Id)
.integer()
.not_null()
.auto_increment()
.primary_key(),
)
.col(
ColumnDef::new(event_trigger::Column::Events)
.array(sea_query::ColumnType::String(None))
.not_null(),
)
.to_owned();
create_table(db, &stmt, EventTrigger).await
}

View File

@ -0,0 +1,48 @@
pub mod common;
pub use common::{
features::{
event_trigger::{Event, Events},
*,
},
setup::*,
TestContext,
};
use pretty_assertions::assert_eq;
use sea_orm::{entity::prelude::*, entity::*, DatabaseConnection};
#[sea_orm_macros::test]
#[cfg(all(feature = "sqlx-postgres", feature = "postgres-array"))]
async fn main() -> Result<(), DbErr> {
let ctx = TestContext::new("event_trigger_tests").await;
create_tables(&ctx.db).await?;
insert_event_trigger(&ctx.db).await?;
ctx.delete().await;
Ok(())
}
pub async fn insert_event_trigger(db: &DatabaseConnection) -> Result<(), DbErr> {
let event_trigger = event_trigger::Model {
id: 1,
events: Events(
["A", "B", "C"]
.into_iter()
.map(|s| Event(s.to_owned()))
.collect(),
),
};
let result = event_trigger.clone().into_active_model().insert(db).await?;
assert_eq!(result, event_trigger);
let model = event_trigger::Entity::find()
.filter(event_trigger::Column::Id.eq(event_trigger.id))
.one(db)
.await?;
assert_eq!(model, Some(event_trigger));
Ok(())
}

View File

@ -27,8 +27,8 @@ pub async fn crud_in_parallel(db: &DatabaseConnection) -> Result<(), DbErr> {
key: "markup".to_owned(),
value: "1.18".to_owned(),
bytes: vec![1, 2, 3],
date: Some(Date::from_ymd(2021, 9, 27)),
time: Some(Time::from_hms(11, 32, 55)),
date: Some(Date::from_ymd_opt(2021, 9, 27).unwrap()),
time: Some(Time::from_hms_opt(11, 32, 55).unwrap()),
},
metadata::Model {
uuid: Uuid::new_v4(),
@ -36,8 +36,8 @@ pub async fn crud_in_parallel(db: &DatabaseConnection) -> Result<(), DbErr> {
key: "exchange_rate".to_owned(),
value: "0.78".to_owned(),
bytes: vec![1, 2, 3],
date: Some(Date::from_ymd(2021, 9, 27)),
time: Some(Time::from_hms(11, 32, 55)),
date: Some(Date::from_ymd_opt(2021, 9, 27).unwrap()),
time: Some(Time::from_hms_opt(11, 32, 55).unwrap()),
},
metadata::Model {
uuid: Uuid::new_v4(),

View File

@ -23,7 +23,7 @@ pub async fn create_metadata(db: &DatabaseConnection) -> Result<(), DbErr> {
let model = self_join::Model {
uuid: Uuid::new_v4(),
uuid_ref: None,
time: Some(Time::from_hms(1, 00, 00)),
time: Some(Time::from_hms_opt(1, 00, 00).unwrap()),
};
model.clone().into_active_model().insert(db).await?;
@ -31,7 +31,7 @@ pub async fn create_metadata(db: &DatabaseConnection) -> Result<(), DbErr> {
let linked_model = self_join::Model {
uuid: Uuid::new_v4(),
uuid_ref: Some(model.clone().uuid),
time: Some(Time::from_hms(2, 00, 00)),
time: Some(Time::from_hms_opt(2, 00, 00).unwrap()),
};
linked_model.clone().into_active_model().insert(db).await?;
@ -39,7 +39,7 @@ pub async fn create_metadata(db: &DatabaseConnection) -> Result<(), DbErr> {
let not_linked_model = self_join::Model {
uuid: Uuid::new_v4(),
uuid_ref: None,
time: Some(Time::from_hms(3, 00, 00)),
time: Some(Time::from_hms_opt(3, 00, 00).unwrap()),
};
not_linked_model

View File

@ -28,8 +28,8 @@ pub async fn insert_metadata(db: &DatabaseConnection) -> Result<(), DbErr> {
key: "markup".to_owned(),
value: "1.18".to_owned(),
bytes: vec![1, 2, 3],
date: Some(Date::from_ymd(2021, 9, 27)),
time: Some(Time::from_hms(11, 32, 55)),
date: Some(Date::from_ymd_opt(2021, 9, 27).unwrap()),
time: Some(Time::from_hms_opt(11, 32, 55).unwrap()),
};
let result = metadata.clone().into_active_model().insert(db).await?;
@ -65,8 +65,8 @@ pub async fn create_and_update_metadata(db: &DatabaseConnection) -> Result<(), D
key: "markup".to_owned(),
value: "1.18".to_owned(),
bytes: vec![1, 2, 3],
date: Some(Date::from_ymd(2021, 9, 27)),
time: Some(Time::from_hms(11, 32, 55)),
date: Some(Date::from_ymd_opt(2021, 9, 27).unwrap()),
time: Some(Time::from_hms_opt(11, 32, 55).unwrap()),
};
let res = Metadata::insert(metadata.clone().into_active_model())