diff --git a/Cargo.toml b/Cargo.toml index c3ea1ce8..6dc978d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,7 @@ once_cell = "1.8" [dev-dependencies] smol = { version = "^1.2" } smol-potat = { version = "^1.1" } -async-std = { version = "^1.9", features = ["attributes", "tokio1"] } +async-std = { version = "^1", features = ["attributes", "tokio1"] } tokio = { version = "^1.6", features = ["full"] } actix-rt = { version = "2.2.0" } maplit = { version = "^1" } diff --git a/examples/actix3_example/entity/Cargo.toml b/examples/actix3_example/entity/Cargo.toml index b0daaeda..67879a0a 100644 --- a/examples/actix3_example/entity/Cargo.toml +++ b/examples/actix3_example/entity/Cargo.toml @@ -12,7 +12,7 @@ path = "src/lib.rs" serde = { version = "1", features = ["derive"] } [dependencies.sea-orm] -# path = "../../../" # remove this line in your own project +path = "../../../" # remove this line in your own project version = "^0.7.0" features = [ "macros", diff --git a/examples/actix3_example/migration/Cargo.toml b/examples/actix3_example/migration/Cargo.toml index 89174a73..4ffcdd4e 100644 --- a/examples/actix3_example/migration/Cargo.toml +++ b/examples/actix3_example/migration/Cargo.toml @@ -9,5 +9,8 @@ name = "migration" path = "src/lib.rs" [dependencies] -sea-schema = { version = "^0.7.0", default-features = false, features = [ "migration", "debug-print" ] } entity = { path = "../entity" } + +[dependencies.sea-orm-migration] +path = "../../../sea-orm-migration" # remove this line in your own project +version = "^0.7.0" diff --git a/examples/actix3_example/migration/src/lib.rs b/examples/actix3_example/migration/src/lib.rs index 3679d81f..af8d9b2a 100644 --- a/examples/actix3_example/migration/src/lib.rs +++ b/examples/actix3_example/migration/src/lib.rs @@ -1,4 +1,4 @@ -pub use sea_schema::migration::prelude::*; +pub use sea_orm_migration::prelude::*; mod m20220120_000001_create_post_table; diff --git a/examples/actix3_example/migration/src/m20220120_000001_create_post_table.rs b/examples/actix3_example/migration/src/m20220120_000001_create_post_table.rs index 0fe872c4..097c2267 100644 --- a/examples/actix3_example/migration/src/m20220120_000001_create_post_table.rs +++ b/examples/actix3_example/migration/src/m20220120_000001_create_post_table.rs @@ -1,5 +1,5 @@ use entity::post::*; -use sea_schema::migration::prelude::*; +use sea_orm_migration::prelude::*; pub struct Migration; diff --git a/examples/actix3_example/migration/src/main.rs b/examples/actix3_example/migration/src/main.rs index 7e5e996d..c6b6e48d 100644 --- a/examples/actix3_example/migration/src/main.rs +++ b/examples/actix3_example/migration/src/main.rs @@ -1,7 +1,6 @@ -use migration::Migrator; -use sea_schema::migration::*; +use sea_orm_migration::prelude::*; #[async_std::main] async fn main() { - cli::run_cli(Migrator).await; + cli::run_cli(migration::Migrator).await; } diff --git a/examples/actix_example/entity/Cargo.toml b/examples/actix_example/entity/Cargo.toml index 9db2a583..c0d21f5c 100644 --- a/examples/actix_example/entity/Cargo.toml +++ b/examples/actix_example/entity/Cargo.toml @@ -12,7 +12,7 @@ path = "src/lib.rs" serde = { version = "1", features = ["derive"] } [dependencies.sea-orm] -# path = "../../../" # remove this line in your own project +path = "../../../" # remove this line in your own project version = "^0.7.0" features = [ "macros", diff --git a/examples/actix_example/migration/Cargo.toml b/examples/actix_example/migration/Cargo.toml index 89174a73..4ffcdd4e 100644 --- a/examples/actix_example/migration/Cargo.toml +++ b/examples/actix_example/migration/Cargo.toml @@ -9,5 +9,8 @@ name = "migration" path = "src/lib.rs" [dependencies] -sea-schema = { version = "^0.7.0", default-features = false, features = [ "migration", "debug-print" ] } entity = { path = "../entity" } + +[dependencies.sea-orm-migration] +path = "../../../sea-orm-migration" # remove this line in your own project +version = "^0.7.0" diff --git a/examples/actix_example/migration/src/lib.rs b/examples/actix_example/migration/src/lib.rs index 3679d81f..af8d9b2a 100644 --- a/examples/actix_example/migration/src/lib.rs +++ b/examples/actix_example/migration/src/lib.rs @@ -1,4 +1,4 @@ -pub use sea_schema::migration::prelude::*; +pub use sea_orm_migration::prelude::*; mod m20220120_000001_create_post_table; diff --git a/examples/actix_example/migration/src/m20220120_000001_create_post_table.rs b/examples/actix_example/migration/src/m20220120_000001_create_post_table.rs index 0fe872c4..097c2267 100644 --- a/examples/actix_example/migration/src/m20220120_000001_create_post_table.rs +++ b/examples/actix_example/migration/src/m20220120_000001_create_post_table.rs @@ -1,5 +1,5 @@ use entity::post::*; -use sea_schema::migration::prelude::*; +use sea_orm_migration::prelude::*; pub struct Migration; diff --git a/examples/actix_example/migration/src/main.rs b/examples/actix_example/migration/src/main.rs index 7e5e996d..c6b6e48d 100644 --- a/examples/actix_example/migration/src/main.rs +++ b/examples/actix_example/migration/src/main.rs @@ -1,7 +1,6 @@ -use migration::Migrator; -use sea_schema::migration::*; +use sea_orm_migration::prelude::*; #[async_std::main] async fn main() { - cli::run_cli(Migrator).await; + cli::run_cli(migration::Migrator).await; } diff --git a/examples/actix_example/src/main.rs b/examples/actix_example/src/main.rs index 5855bbed..dd100fef 100644 --- a/examples/actix_example/src/main.rs +++ b/examples/actix_example/src/main.rs @@ -1,6 +1,6 @@ use actix_files::Files as Fs; use actix_web::{ - error, get, middleware, post, web, App, Error, HttpRequest, HttpResponse, HttpServer, Result + error, get, middleware, post, web, App, Error, HttpRequest, HttpResponse, HttpServer, Result, }; use entity::post; diff --git a/examples/axum_example/entity/Cargo.toml b/examples/axum_example/entity/Cargo.toml index 407a6942..961eb33c 100644 --- a/examples/axum_example/entity/Cargo.toml +++ b/examples/axum_example/entity/Cargo.toml @@ -12,7 +12,7 @@ path = "src/lib.rs" serde = { version = "1", features = ["derive"] } [dependencies.sea-orm] -# path = "../../../" # remove this line in your own project +path = "../../../" # remove this line in your own project version = "^0.7.0" features = [ "macros", diff --git a/examples/axum_example/migration/Cargo.toml b/examples/axum_example/migration/Cargo.toml index 89174a73..4ffcdd4e 100644 --- a/examples/axum_example/migration/Cargo.toml +++ b/examples/axum_example/migration/Cargo.toml @@ -9,5 +9,8 @@ name = "migration" path = "src/lib.rs" [dependencies] -sea-schema = { version = "^0.7.0", default-features = false, features = [ "migration", "debug-print" ] } entity = { path = "../entity" } + +[dependencies.sea-orm-migration] +path = "../../../sea-orm-migration" # remove this line in your own project +version = "^0.7.0" diff --git a/examples/axum_example/migration/src/lib.rs b/examples/axum_example/migration/src/lib.rs index 3679d81f..af8d9b2a 100644 --- a/examples/axum_example/migration/src/lib.rs +++ b/examples/axum_example/migration/src/lib.rs @@ -1,4 +1,4 @@ -pub use sea_schema::migration::prelude::*; +pub use sea_orm_migration::prelude::*; mod m20220120_000001_create_post_table; diff --git a/examples/axum_example/migration/src/m20220120_000001_create_post_table.rs b/examples/axum_example/migration/src/m20220120_000001_create_post_table.rs index 0fe872c4..097c2267 100644 --- a/examples/axum_example/migration/src/m20220120_000001_create_post_table.rs +++ b/examples/axum_example/migration/src/m20220120_000001_create_post_table.rs @@ -1,5 +1,5 @@ use entity::post::*; -use sea_schema::migration::prelude::*; +use sea_orm_migration::prelude::*; pub struct Migration; diff --git a/examples/axum_example/migration/src/main.rs b/examples/axum_example/migration/src/main.rs index 7e5e996d..c6b6e48d 100644 --- a/examples/axum_example/migration/src/main.rs +++ b/examples/axum_example/migration/src/main.rs @@ -1,7 +1,6 @@ -use migration::Migrator; -use sea_schema::migration::*; +use sea_orm_migration::prelude::*; #[async_std::main] async fn main() { - cli::run_cli(Migrator).await; + cli::run_cli(migration::Migrator).await; } diff --git a/examples/graphql_example/entity/Cargo.toml b/examples/graphql_example/entity/Cargo.toml index c7e1da0a..5623ad04 100644 --- a/examples/graphql_example/entity/Cargo.toml +++ b/examples/graphql_example/entity/Cargo.toml @@ -15,6 +15,7 @@ serde = { version = "1", features = ["derive"] } version = "^3.0.38" [dependencies.sea-orm] +path = "../../../" # remove this line in your own project version = "^0.7.0" features = [ "macros", diff --git a/examples/graphql_example/migration/Cargo.toml b/examples/graphql_example/migration/Cargo.toml index af696384..9c5242f8 100644 --- a/examples/graphql_example/migration/Cargo.toml +++ b/examples/graphql_example/migration/Cargo.toml @@ -9,6 +9,9 @@ name = "migration" path = "src/lib.rs" [dependencies] -sea-schema = { version = "^0.7.0", default-features = false, features = [ "migration", "debug-print" ] } dotenv = "0.15.0" -entity = { path = "../entity" } \ No newline at end of file +entity = { path = "../entity" } + +[dependencies.sea-orm-migration] +path = "../../../sea-orm-migration" # remove this line in your own project +version = "^0.7.0" diff --git a/examples/graphql_example/migration/src/lib.rs b/examples/graphql_example/migration/src/lib.rs index 339d693b..2c605afb 100644 --- a/examples/graphql_example/migration/src/lib.rs +++ b/examples/graphql_example/migration/src/lib.rs @@ -1,4 +1,4 @@ -pub use sea_schema::migration::*; +pub use sea_orm_migration::prelude::*; mod m20220101_000001_create_table; diff --git a/examples/graphql_example/migration/src/m20220101_000001_create_table.rs b/examples/graphql_example/migration/src/m20220101_000001_create_table.rs index 0c754f6c..42278d2c 100644 --- a/examples/graphql_example/migration/src/m20220101_000001_create_table.rs +++ b/examples/graphql_example/migration/src/m20220101_000001_create_table.rs @@ -1,11 +1,8 @@ +use sea_orm_migration::prelude::*; use entity::{ note, sea_orm::{DbBackend, EntityTrait, Schema}, }; -use sea_schema::migration::{ - sea_query::*, - *, -}; pub struct Migration; diff --git a/examples/graphql_example/migration/src/main.rs b/examples/graphql_example/migration/src/main.rs index 5a5548f8..3e249b20 100644 --- a/examples/graphql_example/migration/src/main.rs +++ b/examples/graphql_example/migration/src/main.rs @@ -1,5 +1,4 @@ -use migration::Migrator; -use sea_schema::migration::*; +use sea_orm_migration::prelude::*; use std::path::PathBuf; #[cfg(debug_assertions)] @@ -22,5 +21,5 @@ async fn main() { } }; - cli::run_cli(Migrator).await; + cli::run_cli(migration::Migrator).await; } diff --git a/examples/jsonrpsee_example/entity/Cargo.toml b/examples/jsonrpsee_example/entity/Cargo.toml index e0ff8062..d24020b8 100644 --- a/examples/jsonrpsee_example/entity/Cargo.toml +++ b/examples/jsonrpsee_example/entity/Cargo.toml @@ -12,7 +12,7 @@ path = "src/lib.rs" serde = { version = "1", features = ["derive"] } [dependencies.sea-orm] -# path = "../../../" # remove this line in your own project +path = "../../../" # remove this line in your own project version = "^0.7.0" features = [ "macros", diff --git a/examples/jsonrpsee_example/migration/Cargo.toml b/examples/jsonrpsee_example/migration/Cargo.toml index 89174a73..4ffcdd4e 100644 --- a/examples/jsonrpsee_example/migration/Cargo.toml +++ b/examples/jsonrpsee_example/migration/Cargo.toml @@ -9,5 +9,8 @@ name = "migration" path = "src/lib.rs" [dependencies] -sea-schema = { version = "^0.7.0", default-features = false, features = [ "migration", "debug-print" ] } entity = { path = "../entity" } + +[dependencies.sea-orm-migration] +path = "../../../sea-orm-migration" # remove this line in your own project +version = "^0.7.0" diff --git a/examples/jsonrpsee_example/migration/src/lib.rs b/examples/jsonrpsee_example/migration/src/lib.rs index 3679d81f..af8d9b2a 100644 --- a/examples/jsonrpsee_example/migration/src/lib.rs +++ b/examples/jsonrpsee_example/migration/src/lib.rs @@ -1,4 +1,4 @@ -pub use sea_schema::migration::prelude::*; +pub use sea_orm_migration::prelude::*; mod m20220120_000001_create_post_table; diff --git a/examples/jsonrpsee_example/migration/src/m20220120_000001_create_post_table.rs b/examples/jsonrpsee_example/migration/src/m20220120_000001_create_post_table.rs index 0fe872c4..097c2267 100644 --- a/examples/jsonrpsee_example/migration/src/m20220120_000001_create_post_table.rs +++ b/examples/jsonrpsee_example/migration/src/m20220120_000001_create_post_table.rs @@ -1,5 +1,5 @@ use entity::post::*; -use sea_schema::migration::prelude::*; +use sea_orm_migration::prelude::*; pub struct Migration; diff --git a/examples/jsonrpsee_example/migration/src/main.rs b/examples/jsonrpsee_example/migration/src/main.rs index 7e5e996d..c6b6e48d 100644 --- a/examples/jsonrpsee_example/migration/src/main.rs +++ b/examples/jsonrpsee_example/migration/src/main.rs @@ -1,7 +1,6 @@ -use migration::Migrator; -use sea_schema::migration::*; +use sea_orm_migration::prelude::*; #[async_std::main] async fn main() { - cli::run_cli(Migrator).await; + cli::run_cli(migration::Migrator).await; } diff --git a/examples/poem_example/entity/Cargo.toml b/examples/poem_example/entity/Cargo.toml index e0ff8062..d24020b8 100644 --- a/examples/poem_example/entity/Cargo.toml +++ b/examples/poem_example/entity/Cargo.toml @@ -12,7 +12,7 @@ path = "src/lib.rs" serde = { version = "1", features = ["derive"] } [dependencies.sea-orm] -# path = "../../../" # remove this line in your own project +path = "../../../" # remove this line in your own project version = "^0.7.0" features = [ "macros", diff --git a/examples/poem_example/migration/Cargo.toml b/examples/poem_example/migration/Cargo.toml index 89174a73..4ffcdd4e 100644 --- a/examples/poem_example/migration/Cargo.toml +++ b/examples/poem_example/migration/Cargo.toml @@ -9,5 +9,8 @@ name = "migration" path = "src/lib.rs" [dependencies] -sea-schema = { version = "^0.7.0", default-features = false, features = [ "migration", "debug-print" ] } entity = { path = "../entity" } + +[dependencies.sea-orm-migration] +path = "../../../sea-orm-migration" # remove this line in your own project +version = "^0.7.0" diff --git a/examples/poem_example/migration/src/lib.rs b/examples/poem_example/migration/src/lib.rs index 3679d81f..af8d9b2a 100644 --- a/examples/poem_example/migration/src/lib.rs +++ b/examples/poem_example/migration/src/lib.rs @@ -1,4 +1,4 @@ -pub use sea_schema::migration::prelude::*; +pub use sea_orm_migration::prelude::*; mod m20220120_000001_create_post_table; diff --git a/examples/poem_example/migration/src/m20220120_000001_create_post_table.rs b/examples/poem_example/migration/src/m20220120_000001_create_post_table.rs index 0fe872c4..097c2267 100644 --- a/examples/poem_example/migration/src/m20220120_000001_create_post_table.rs +++ b/examples/poem_example/migration/src/m20220120_000001_create_post_table.rs @@ -1,5 +1,5 @@ use entity::post::*; -use sea_schema::migration::prelude::*; +use sea_orm_migration::prelude::*; pub struct Migration; diff --git a/examples/poem_example/migration/src/main.rs b/examples/poem_example/migration/src/main.rs index 7e5e996d..c6b6e48d 100644 --- a/examples/poem_example/migration/src/main.rs +++ b/examples/poem_example/migration/src/main.rs @@ -1,7 +1,6 @@ -use migration::Migrator; -use sea_schema::migration::*; +use sea_orm_migration::prelude::*; #[async_std::main] async fn main() { - cli::run_cli(Migrator).await; + cli::run_cli(migration::Migrator).await; } diff --git a/examples/rocket_example/entity/Cargo.toml b/examples/rocket_example/entity/Cargo.toml index 645dbf3f..b29afd4e 100644 --- a/examples/rocket_example/entity/Cargo.toml +++ b/examples/rocket_example/entity/Cargo.toml @@ -14,7 +14,7 @@ rocket = { version = "0.5.0-rc.1", features = [ ] } [dependencies.sea-orm] -# path = "../../../" # remove this line in your own project +path = "../../../" # remove this line in your own project version = "^0.7.0" features = [ "macros", diff --git a/examples/rocket_example/migration/Cargo.toml b/examples/rocket_example/migration/Cargo.toml index a5e565b7..01f5b9b7 100644 --- a/examples/rocket_example/migration/Cargo.toml +++ b/examples/rocket_example/migration/Cargo.toml @@ -9,6 +9,9 @@ name = "migration" path = "src/lib.rs" [dependencies] -sea-schema = { version = "^0.7.0", default-features = false, features = [ "migration", "debug-print" ] } entity = { path = "../entity" } + +[dependencies.sea-orm-migration] +path = "../../../sea-orm-migration" # remove this line in your own project +version = "^0.7.0" rocket = { version = "0.5.0-rc.1" } diff --git a/examples/rocket_example/migration/src/lib.rs b/examples/rocket_example/migration/src/lib.rs index 3679d81f..af8d9b2a 100644 --- a/examples/rocket_example/migration/src/lib.rs +++ b/examples/rocket_example/migration/src/lib.rs @@ -1,4 +1,4 @@ -pub use sea_schema::migration::prelude::*; +pub use sea_orm_migration::prelude::*; mod m20220120_000001_create_post_table; diff --git a/examples/rocket_example/migration/src/m20220120_000001_create_post_table.rs b/examples/rocket_example/migration/src/m20220120_000001_create_post_table.rs index 0fe872c4..097c2267 100644 --- a/examples/rocket_example/migration/src/m20220120_000001_create_post_table.rs +++ b/examples/rocket_example/migration/src/m20220120_000001_create_post_table.rs @@ -1,5 +1,5 @@ use entity::post::*; -use sea_schema::migration::prelude::*; +use sea_orm_migration::prelude::*; pub struct Migration; diff --git a/examples/rocket_example/migration/src/main.rs b/examples/rocket_example/migration/src/main.rs index e47018eb..4626e82f 100644 --- a/examples/rocket_example/migration/src/main.rs +++ b/examples/rocket_example/migration/src/main.rs @@ -1,5 +1,4 @@ -use migration::Migrator; -use sea_schema::migration::prelude::*; +use sea_orm_migration::prelude::*; #[async_std::main] async fn main() { @@ -14,5 +13,5 @@ async fn main() { std::env::set_var(key, database_url); } - cli::run_cli(Migrator).await; + cli::run_cli(migration::Migrator).await; } diff --git a/examples/tonic_example/Cargo.toml b/examples/tonic_example/Cargo.toml index cded186c..64620a1c 100644 --- a/examples/tonic_example/Cargo.toml +++ b/examples/tonic_example/Cargo.toml @@ -14,7 +14,6 @@ tonic = "0.7" tokio = { version = "1.17", features = ["macros", "rt-multi-thread", "full"] } entity = { path = "entity" } migration = { path = "migration" } -sea-orm = { version = "0.7.1", features = [ "sqlx-postgres", "runtime-tokio-rustls", "macros" ] } prost = "0.10.0" serde = "1.0" diff --git a/examples/tonic_example/entity/Cargo.toml b/examples/tonic_example/entity/Cargo.toml index 178dcbec..7b430b07 100644 --- a/examples/tonic_example/entity/Cargo.toml +++ b/examples/tonic_example/entity/Cargo.toml @@ -12,7 +12,7 @@ path = "src/lib.rs" serde = { version = "1", features = ["derive"] } [dependencies.sea-orm] -# path = "../../../" # remove this line in your own project +path = "../../../" # remove this line in your own project version = "^0.7.0" features = [ "macros", diff --git a/examples/tonic_example/migration/Cargo.toml b/examples/tonic_example/migration/Cargo.toml index 89174a73..4ffcdd4e 100644 --- a/examples/tonic_example/migration/Cargo.toml +++ b/examples/tonic_example/migration/Cargo.toml @@ -9,5 +9,8 @@ name = "migration" path = "src/lib.rs" [dependencies] -sea-schema = { version = "^0.7.0", default-features = false, features = [ "migration", "debug-print" ] } entity = { path = "../entity" } + +[dependencies.sea-orm-migration] +path = "../../../sea-orm-migration" # remove this line in your own project +version = "^0.7.0" diff --git a/examples/tonic_example/migration/src/lib.rs b/examples/tonic_example/migration/src/lib.rs index 3679d81f..af8d9b2a 100644 --- a/examples/tonic_example/migration/src/lib.rs +++ b/examples/tonic_example/migration/src/lib.rs @@ -1,4 +1,4 @@ -pub use sea_schema::migration::prelude::*; +pub use sea_orm_migration::prelude::*; mod m20220120_000001_create_post_table; diff --git a/examples/tonic_example/migration/src/m20220120_000001_create_post_table.rs b/examples/tonic_example/migration/src/m20220120_000001_create_post_table.rs index 0fe872c4..097c2267 100644 --- a/examples/tonic_example/migration/src/m20220120_000001_create_post_table.rs +++ b/examples/tonic_example/migration/src/m20220120_000001_create_post_table.rs @@ -1,5 +1,5 @@ use entity::post::*; -use sea_schema::migration::prelude::*; +use sea_orm_migration::prelude::*; pub struct Migration; diff --git a/examples/tonic_example/migration/src/main.rs b/examples/tonic_example/migration/src/main.rs index 7e5e996d..c6b6e48d 100644 --- a/examples/tonic_example/migration/src/main.rs +++ b/examples/tonic_example/migration/src/main.rs @@ -1,7 +1,6 @@ -use migration::Migrator; -use sea_schema::migration::*; +use sea_orm_migration::prelude::*; #[async_std::main] async fn main() { - cli::run_cli(Migrator).await; + cli::run_cli(migration::Migrator).await; } diff --git a/examples/tonic_example/src/server.rs b/examples/tonic_example/src/server.rs index 6e3d2632..c51ebb10 100644 --- a/examples/tonic_example/src/server.rs +++ b/examples/tonic_example/src/server.rs @@ -8,7 +8,7 @@ use sea_orm_tonic_example::post::{ use entity::{ post::{self, Entity as PostEntity}, - sea_orm::{entity::*, query::*, DatabaseConnection}, + sea_orm::{self, entity::*, query::*, DatabaseConnection}, }; use migration::{Migrator, MigratorTrait}; diff --git a/sea-orm-cli/Cargo.toml b/sea-orm-cli/Cargo.toml index 0efea548..33cc67bf 100644 --- a/sea-orm-cli/Cargo.toml +++ b/sea-orm-cli/Cargo.toml @@ -32,7 +32,7 @@ clap = { version = "^2.33.3" } dotenv = { version = "^0.15" } async-std = { version = "^1.9", features = [ "attributes", "tokio1" ] } sea-orm-codegen = { version = "^0.7.0", path = "../sea-orm-codegen" } -sea-schema = { version = "^0.7.0", default-features = false, features = [ +sea-schema = { git = "https://github.com/SeaQL/sea-schema", branch = "dump-sea-orm-dep", default-features = false, features = [ "debug-print", "sqlx-mysql", "sqlx-sqlite", diff --git a/sea-orm-cli/src/cli.rs b/sea-orm-cli/src/cli.rs index e8e22a1f..3b1efab7 100644 --- a/sea-orm-cli/src/cli.rs +++ b/sea-orm-cli/src/cli.rs @@ -1,4 +1,5 @@ use clap::{App, AppSettings, Arg, SubCommand}; +use sea_schema::get_cli_subcommands; pub fn build_cli() -> App<'static, 'static> { let entity_subcommand = SubCommand::with_name("generate") @@ -95,7 +96,7 @@ pub fn build_cli() -> App<'static, 'static> { .arg(arg_migration_dir.clone()), ) .arg(arg_migration_dir.clone()); - for subcommand in sea_schema::migration::get_subcommands() { + for subcommand in get_cli_subcommands!() { migrate_subcommands = migrate_subcommands.subcommand(subcommand.arg(arg_migration_dir.clone())); } diff --git a/sea-orm-cli/template/migration/_Cargo.toml b/sea-orm-cli/template/migration/_Cargo.toml index 73d34bfa..4ffcdd4e 100644 --- a/sea-orm-cli/template/migration/_Cargo.toml +++ b/sea-orm-cli/template/migration/_Cargo.toml @@ -9,4 +9,8 @@ name = "migration" path = "src/lib.rs" [dependencies] -sea-schema = { version = "^0.7.0", default-features = false, features = [ "migration", "debug-print" ] } +entity = { path = "../entity" } + +[dependencies.sea-orm-migration] +path = "../../../sea-orm-migration" # remove this line in your own project +version = "^0.7.0" diff --git a/sea-orm-cli/template/migration/src/lib.rs b/sea-orm-cli/template/migration/src/lib.rs index 3cabe22c..2c605afb 100644 --- a/sea-orm-cli/template/migration/src/lib.rs +++ b/sea-orm-cli/template/migration/src/lib.rs @@ -1,4 +1,4 @@ -pub use sea_schema::migration::prelude::*; +pub use sea_orm_migration::prelude::*; mod m20220101_000001_create_table; diff --git a/sea-orm-cli/template/migration/src/m20220101_000001_create_table.rs b/sea-orm-cli/template/migration/src/m20220101_000001_create_table.rs index a5907a28..b4dc891e 100644 --- a/sea-orm-cli/template/migration/src/m20220101_000001_create_table.rs +++ b/sea-orm-cli/template/migration/src/m20220101_000001_create_table.rs @@ -1,4 +1,4 @@ -use sea_schema::migration::prelude::*; +use sea_orm_migration::prelude::*; pub struct Migration; diff --git a/sea-orm-cli/template/migration/src/main.rs b/sea-orm-cli/template/migration/src/main.rs index 89b349c9..c6b6e48d 100644 --- a/sea-orm-cli/template/migration/src/main.rs +++ b/sea-orm-cli/template/migration/src/main.rs @@ -1,7 +1,6 @@ -use migration::Migrator; -use sea_schema::migration::prelude::*; +use sea_orm_migration::prelude::*; #[async_std::main] async fn main() { - cli::run_cli(Migrator).await; + cli::run_cli(migration::Migrator).await; } diff --git a/sea-orm-codegen/Cargo.toml b/sea-orm-codegen/Cargo.toml index e1d408db..6af01e87 100644 --- a/sea-orm-codegen/Cargo.toml +++ b/sea-orm-codegen/Cargo.toml @@ -15,7 +15,7 @@ name = "sea_orm_codegen" path = "src/lib.rs" [dependencies] -sea-query = { version = "0.22.0" } +sea-query = { version = "0.24.0" } syn = { version = "^1", default-features = false, features = [ "derive", "parsing", diff --git a/sea-orm-migration/Cargo.toml b/sea-orm-migration/Cargo.toml new file mode 100644 index 00000000..c5e2e1d2 --- /dev/null +++ b/sea-orm-migration/Cargo.toml @@ -0,0 +1,28 @@ +[workspace] +# A separate workspace + +[package] +name = "sea-orm-migration" +version = "0.7.2" +authors = [ "Billy Chan " ] +edition = "2021" +description = "Migration utility for SeaORM" +license = "MIT OR Apache-2.0" +documentation = "https://docs.rs/sea-orm" +repository = "https://github.com/SeaQL/sea-orm" +categories = [ "database" ] +keywords = ["async", "orm", "mysql", "postgres", "sqlite"] + +[lib] +name = "sea_orm_migration" +path = "src/lib.rs" + +[dependencies] +sea-orm = { path = "../", default-features = false, features = ["macros"] } +sea-schema = { git = "https://github.com/SeaQL/sea-schema", branch = "dump-sea-orm-dep", features = ["migration"], default-features = false } +async-std = { version = "^1", features = ["attributes", "tokio1"] } +tracing-subscriber = { version = "0.3", features = ["env-filter"] } +tracing = { version = "0.1", features = ["log"] } +async-trait = { version = "^0.1" } +dotenv = { version = "^0.15" } +clap = { version = "^2.33" } diff --git a/sea-orm-migration/README.md b/sea-orm-migration/README.md new file mode 100644 index 00000000..87a41232 --- /dev/null +++ b/sea-orm-migration/README.md @@ -0,0 +1,77 @@ +# SeaORM CLI + +Install and Usage: + +```sh +> cargo install sea-orm-cli +> sea-orm-cli help +``` + +Or: + +```sh +> cargo install --bin sea +> sea help +``` + +Getting Help: + +```sh +cargo run -- -h +``` + +## Running Entity Generator: + +```sh +# MySQL (`--database-schema` option is ignored) +cargo run -- generate entity -u mysql://sea:sea@localhost/bakery -o out + +# SQLite (`--database-schema` option is ignored) +cargo run -- generate entity -u sqlite://bakery.db -o out + +# PostgreSQL +cargo run -- generate entity -u postgres://sea:sea@localhost/bakery -s public -o out +``` + +## Running Migration: + +- Initialize migration directory + ```sh + cargo run -- migrate init + ``` +- Apply all pending migrations + ```sh + cargo run -- migrate + ``` + ```sh + cargo run -- migrate up + ``` +- Apply first 10 pending migrations + ```sh + cargo run -- migrate up -n 10 + ``` +- Rollback last applied migrations + ```sh + cargo run -- migrate down + ``` +- Rollback last 10 applied migrations + ```sh + cargo run -- migrate down -n 10 + ``` +- Drop all tables from the database, then reapply all migrations + ```sh + cargo run -- migrate fresh + ``` +- Rollback all applied migrations, then reapply all migrations + ```sh + cargo run -- migrate refresh + ``` +- Rollback all applied migrations + ```sh + cargo run -- migrate reset + ``` +- Check the status of all migrations + ```sh + cargo run -- migrate status + ``` + diff --git a/sea-orm-migration/src/cli.rs b/sea-orm-migration/src/cli.rs new file mode 100644 index 00000000..bc211f29 --- /dev/null +++ b/sea-orm-migration/src/cli.rs @@ -0,0 +1,103 @@ +//! Run migrator CLI + +use crate::MigratorTrait; +use clap::{App, AppSettings, Arg}; +use dotenv::dotenv; +use sea_orm::{Database, DbConn}; +use sea_schema::get_cli_subcommands; +use std::{fmt::Display, process::exit}; +use tracing_subscriber::{prelude::*, EnvFilter}; + +#[allow(dead_code)] +/// Migrator CLI application +pub async fn run_cli(migrator: M) +where + M: MigratorTrait, +{ + dotenv().ok(); + let url = std::env::var("DATABASE_URL").expect("Environment variable 'DATABASE_URL' not set"); + let db = &Database::connect(&url).await.unwrap(); + let app = build_cli(); + get_matches(migrator, db, app).await; +} + +async fn get_matches(_: M, db: &DbConn, app: App<'static, 'static>) +where + M: MigratorTrait, +{ + let matches = app.get_matches(); + let mut verbose = false; + let filter = match matches.subcommand() { + (_, None) => "sea_orm::migration=info", + (_, Some(args)) => match args.is_present("VERBOSE") { + true => { + verbose = true; + "debug" + } + false => "sea_orm::migration=info", + }, + }; + let filter_layer = EnvFilter::try_new(filter).unwrap(); + if verbose { + let fmt_layer = tracing_subscriber::fmt::layer(); + tracing_subscriber::registry() + .with(filter_layer) + .with(fmt_layer) + .init() + } else { + let fmt_layer = tracing_subscriber::fmt::layer() + .with_target(false) + .with_level(false) + .without_time(); + tracing_subscriber::registry() + .with(filter_layer) + .with(fmt_layer) + .init() + }; + match matches.subcommand() { + ("fresh", _) => M::fresh(db).await, + ("refresh", _) => M::refresh(db).await, + ("reset", _) => M::reset(db).await, + ("status", _) => M::status(db).await, + ("up", None) => M::up(db, None).await, + ("down", None) => M::down(db, Some(1)).await, + ("up", Some(args)) => { + let str = args.value_of("NUM_MIGRATION").unwrap_or_default(); + let steps = str.parse().ok(); + M::up(db, steps).await + } + ("down", Some(args)) => { + let str = args.value_of("NUM_MIGRATION").unwrap(); + let steps = str.parse().ok().unwrap_or(1); + M::down(db, Some(steps)).await + } + _ => M::up(db, None).await, + } + .unwrap_or_else(handle_error); +} + +fn build_cli() -> App<'static, 'static> { + let mut app = App::new("sea-schema-migration") + .version(env!("CARGO_PKG_VERSION")) + .setting(AppSettings::VersionlessSubcommands) + .arg( + Arg::with_name("VERBOSE") + .long("verbose") + .short("v") + .help("Show debug messages") + .takes_value(false) + .global(true), + ); + for subcommand in get_cli_subcommands!() { + app = app.subcommand(subcommand); + } + app +} + +fn handle_error(error: E) +where + E: Display, +{ + eprintln!("{}", error); + exit(1); +} diff --git a/sea-orm-migration/src/connection.rs b/sea-orm-migration/src/connection.rs new file mode 100644 index 00000000..9d49b97a --- /dev/null +++ b/sea-orm-migration/src/connection.rs @@ -0,0 +1,48 @@ +//! Manage migration connection + +use crate::{into_migration_db_backend, into_migration_err, into_orm_stmt, QueryResult}; +use sea_orm::ConnectionTrait; +use sea_schema::migration::{self, MigrationErr, QueryResultTrait}; + +#[derive(Debug)] +pub(crate) struct DatabaseConnection<'c> { + pub(crate) conn: &'c sea_orm::DatabaseConnection, +} + +#[async_trait::async_trait] +impl migration::ConnectionTrait for DatabaseConnection<'_> { + fn get_database_backend(&self) -> migration::DbBackend { + into_migration_db_backend(ConnectionTrait::get_database_backend(self.conn)) + } + + async fn execute(&self, stmt: migration::Statement) -> Result<(), MigrationErr> { + ConnectionTrait::execute(self.conn, into_orm_stmt(stmt)) + .await + .map(|_| ()) + .map_err(|e| MigrationErr(e.to_string())) + } + + async fn query_one( + &self, + stmt: migration::Statement, + ) -> Result>, MigrationErr> { + ConnectionTrait::query_one(self.conn, into_orm_stmt(stmt)) + .await + .map(|res| res.map(|res| Box::new(QueryResult { res }) as Box)) + .map_err(into_migration_err) + } + + async fn query_all( + &self, + stmt: migration::Statement, + ) -> Result>, MigrationErr> { + ConnectionTrait::query_all(self.conn, into_orm_stmt(stmt)) + .await + .map(|rows| { + rows.into_iter() + .map(|res| Box::new(QueryResult { res }) as Box) + .collect() + }) + .map_err(into_migration_err) + } +} diff --git a/sea-orm-migration/src/database.rs b/sea-orm-migration/src/database.rs new file mode 100644 index 00000000..82142840 --- /dev/null +++ b/sea-orm-migration/src/database.rs @@ -0,0 +1,19 @@ +//! Convert database backend + +use sea_schema::migration; + +pub(crate) fn into_orm_db_backend(db_backend: migration::DbBackend) -> sea_orm::DbBackend { + match db_backend { + migration::DbBackend::MySql => sea_orm::DbBackend::MySql, + migration::DbBackend::Postgres => sea_orm::DbBackend::Postgres, + migration::DbBackend::Sqlite => sea_orm::DbBackend::Sqlite, + } +} + +pub(crate) fn into_migration_db_backend(db_backend: sea_orm::DbBackend) -> migration::DbBackend { + match db_backend { + sea_orm::DbBackend::MySql => migration::DbBackend::MySql, + sea_orm::DbBackend::Postgres => migration::DbBackend::Postgres, + sea_orm::DbBackend::Sqlite => migration::DbBackend::Sqlite, + } +} diff --git a/sea-orm-migration/src/error.rs b/sea-orm-migration/src/error.rs new file mode 100644 index 00000000..43bd4dd4 --- /dev/null +++ b/sea-orm-migration/src/error.rs @@ -0,0 +1,11 @@ +//! Convert migration error + +use sea_schema::migration; + +pub(crate) fn into_orm_db_err(err: migration::MigrationErr) -> sea_orm::DbErr { + sea_orm::DbErr::Migration(err.to_string()) +} + +pub(crate) fn into_migration_err(err: sea_orm::DbErr) -> migration::MigrationErr { + migration::MigrationErr(err.to_string()) +} diff --git a/sea-orm-migration/src/lib.rs b/sea-orm-migration/src/lib.rs new file mode 100644 index 00000000..cb2712f3 --- /dev/null +++ b/sea-orm-migration/src/lib.rs @@ -0,0 +1,36 @@ +pub mod cli; +pub mod connection; +pub mod database; +pub mod error; +pub mod manager; +pub mod migrator; +pub mod prelude; +pub mod query; +pub mod seaql_migrations; +pub mod statement; + +pub use manager::*; +pub use migrator::*; + +use connection::*; +use database::*; +use error::*; +use query::*; +use statement::*; +use sea_orm::DbErr; + +/// Define the name of a migration +pub trait MigrationName { + /// Get migration name + fn name(&self) -> &str; +} + +/// Define the actions of a migration +#[async_trait::async_trait] +pub trait MigrationTrait: MigrationName + Send + Sync { + /// Define actions to perform when applying the migration + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr>; + + /// Define actions to perform when rolling back the migration + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr>; +} diff --git a/sea-orm-migration/src/manager.rs b/sea-orm-migration/src/manager.rs new file mode 100644 index 00000000..4bd0c16a --- /dev/null +++ b/sea-orm-migration/src/manager.rs @@ -0,0 +1,163 @@ +//! Schema manager + +use crate::{into_orm_db_err, DatabaseConnection}; +use sea_orm::sea_query::{ + extension::postgres::{TypeAlterStatement, TypeCreateStatement, TypeDropStatement}, + ForeignKeyCreateStatement, ForeignKeyDropStatement, IndexCreateStatement, IndexDropStatement, + TableAlterStatement, TableCreateStatement, TableDropStatement, TableRenameStatement, + TableTruncateStatement, +}; +use sea_orm::{ConnectionTrait, DbBackend, DbConn, DbErr, StatementBuilder}; +use sea_schema::migration; + +/// Helper struct for writing migration scripts in migration file +#[derive(Debug)] +pub struct SchemaManager<'c> { + conn: DatabaseConnection<'c>, +} + +impl<'c> SchemaManager<'c> { + /// Initialize [`SchemaManager`] + pub fn new(conn: &'c DbConn) -> Self { + Self { + conn: DatabaseConnection { conn }, + } + } + + /// Execute any statement that implemented [`StatementBuilder`] + pub async fn exec_stmt(&self, stmt: S) -> Result<(), DbErr> + where + S: StatementBuilder, + { + let builder = self.conn.conn.get_database_backend(); + self.conn + .conn + .execute(builder.build(&stmt)) + .await + .map(|_| ()) + } + + /// Get database backend + pub fn get_database_backend(&self) -> DbBackend { + self.conn.conn.get_database_backend() + } + + /// Borrow database connection + pub fn get_connection(&self) -> &'c DbConn { + self.conn.conn + } +} + +/// Schema Creation +impl<'c> SchemaManager<'c> { + /// Create table + pub async fn create_table(&self, stmt: TableCreateStatement) -> Result<(), DbErr> { + migration::SchemaManager::create_table(stmt, &self.conn) + .await + .map_err(into_orm_db_err) + } + + /// Create index + pub async fn create_index(&self, stmt: IndexCreateStatement) -> Result<(), DbErr> { + migration::SchemaManager::create_index(stmt, &self.conn) + .await + .map_err(into_orm_db_err) + } + + /// Create foreign key + pub async fn create_foreign_key(&self, stmt: ForeignKeyCreateStatement) -> Result<(), DbErr> { + migration::SchemaManager::create_foreign_key(stmt, &self.conn) + .await + .map_err(into_orm_db_err) + } + + /// Create type + pub async fn create_type(&self, stmt: TypeCreateStatement) -> Result<(), DbErr> { + migration::SchemaManager::create_type(stmt, &self.conn) + .await + .map_err(into_orm_db_err) + } +} + +/// Schema Mutation +impl<'c> SchemaManager<'c> { + /// Alter table + pub async fn alter_table(&self, stmt: TableAlterStatement) -> Result<(), DbErr> { + migration::SchemaManager::alter_table(stmt, &self.conn) + .await + .map_err(into_orm_db_err) + } + + /// Drop table + pub async fn drop_table(&self, stmt: TableDropStatement) -> Result<(), DbErr> { + migration::SchemaManager::drop_table(stmt, &self.conn) + .await + .map_err(into_orm_db_err) + } + + /// Rename table + pub async fn rename_table(&self, stmt: TableRenameStatement) -> Result<(), DbErr> { + migration::SchemaManager::rename_table(stmt, &self.conn) + .await + .map_err(into_orm_db_err) + } + + /// Truncate table + pub async fn truncate_table(&self, stmt: TableTruncateStatement) -> Result<(), DbErr> { + migration::SchemaManager::truncate_table(stmt, &self.conn) + .await + .map_err(into_orm_db_err) + } + + /// Drop index + pub async fn drop_index(&self, stmt: IndexDropStatement) -> Result<(), DbErr> { + migration::SchemaManager::drop_index(stmt, &self.conn) + .await + .map_err(into_orm_db_err) + } + + /// Drop foreign key + pub async fn drop_foreign_key(&self, stmt: ForeignKeyDropStatement) -> Result<(), DbErr> { + migration::SchemaManager::drop_foreign_key(stmt, &self.conn) + .await + .map_err(into_orm_db_err) + } + + /// Alter type + pub async fn alter_type(&self, stmt: TypeAlterStatement) -> Result<(), DbErr> { + migration::SchemaManager::alter_type(stmt, &self.conn) + .await + .map_err(into_orm_db_err) + } + + /// Drop type + pub async fn drop_type(&self, stmt: TypeDropStatement) -> Result<(), DbErr> { + migration::SchemaManager::drop_type(stmt, &self.conn) + .await + .map_err(into_orm_db_err) + } +} + +/// Schema Inspection +impl<'c> SchemaManager<'c> { + /// Check if a table exists in the database + pub async fn has_table(&self, table: T) -> Result + where + T: AsRef, + { + migration::SchemaManager::has_table(table, &self.conn) + .await + .map_err(into_orm_db_err) + } + + /// Check if a column exists in a specific database table + pub async fn has_column(&self, table: T, column: C) -> Result + where + T: AsRef, + C: AsRef, + { + migration::SchemaManager::has_column(table, column, &self.conn) + .await + .map_err(into_orm_db_err) + } +} diff --git a/sea-orm-migration/src/migrator.rs b/sea-orm-migration/src/migrator.rs new file mode 100644 index 00000000..a846f123 --- /dev/null +++ b/sea-orm-migration/src/migrator.rs @@ -0,0 +1,338 @@ +//! Migration executor + +use crate::{seaql_migrations, MigrationTrait, SchemaManager}; +use sea_orm::sea_query::{ + Alias, Expr, ForeignKey, IntoTableRef, Query, SelectStatement, SimpleExpr, Table, +}; +use sea_orm::{ + ActiveModelTrait, ActiveValue, ColumnTrait, Condition, ConnectionTrait, DbBackend, DbConn, + DbErr, EntityTrait, QueryFilter, QueryOrder, Schema, Statement, +}; +use std::fmt::Display; +use std::time::SystemTime; +use tracing::info; + +#[derive(Debug, PartialEq)] +/// Status of migration +pub enum MigrationStatus { + /// Not yet applied + Pending, + /// Applied + Applied, +} + +/// Wrapper of [`MigrationTrait`] with migration status +#[allow(missing_debug_implementations)] +pub struct Migration { + migration: Box, + status: MigrationStatus, +} + +impl Display for MigrationStatus { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let status = match self { + MigrationStatus::Pending => "Pending", + MigrationStatus::Applied => "Applied", + }; + write!(f, "{}", status) + } +} + +/// Performing migrations on a database +#[async_trait::async_trait] +pub trait MigratorTrait: Send { + /// Vector of migrations in time sequence + fn migrations() -> Vec>; + + /// Get list of migrations wrapped in `Migration` struct + fn get_migration_files() -> Vec { + Self::migrations() + .into_iter() + .map(|migration| Migration { + migration, + status: MigrationStatus::Pending, + }) + .collect() + } + + /// Get list of applied migrations from database + async fn get_migration_models(db: &DbConn) -> Result, DbErr> { + Self::install(db).await?; + seaql_migrations::Entity::find() + .order_by_asc(seaql_migrations::Column::Version) + .all(db) + .await + } + + /// Get list of migrations with status + async fn get_migration_with_status(db: &DbConn) -> Result, DbErr> { + Self::install(db).await?; + let mut migration_files = Self::get_migration_files(); + let migration_models = Self::get_migration_models(db).await?; + for (i, migration_model) in migration_models.into_iter().enumerate() { + if let Some(migration_file) = migration_files.get_mut(i) { + if migration_file.migration.name() == migration_model.version.as_str() { + migration_file.status = MigrationStatus::Applied; + } else { + return Err(DbErr::Custom(format!("Migration mismatch: applied migration != migration file, '{0}' != '{1}'\nMigration '{0}' has been applied but its corresponding migration file is missing.", migration_file.migration.name(), migration_model.version))); + } + } else { + return Err(DbErr::Custom(format!("Migration file of version '{}' is missing, this migration has been applied but its file is missing", migration_model.version))); + } + } + Ok(migration_files) + } + + /// Get list of pending migrations + async fn get_pending_migrations(db: &DbConn) -> Result, DbErr> { + Self::install(db).await?; + Ok(Self::get_migration_with_status(db) + .await? + .into_iter() + .filter(|file| file.status == MigrationStatus::Pending) + .collect()) + } + + /// Get list of applied migrations + async fn get_applied_migrations(db: &DbConn) -> Result, DbErr> { + Self::install(db).await?; + Ok(Self::get_migration_with_status(db) + .await? + .into_iter() + .filter(|file| file.status == MigrationStatus::Applied) + .collect()) + } + + /// Create migration table `seaql_migrations` in the database + async fn install(db: &DbConn) -> Result<(), DbErr> { + let builder = db.get_database_backend(); + let schema = Schema::new(builder); + let mut stmt = schema.create_table_from_entity(seaql_migrations::Entity); + stmt.if_not_exists(); + db.execute(builder.build(&stmt)).await.map(|_| ()) + } + + /// Drop all tables from the database, then reapply all migrations + async fn fresh(db: &DbConn) -> Result<(), DbErr> { + Self::install(db).await?; + let db_backend = db.get_database_backend(); + + // Temporarily disable the foreign key check + if db_backend == DbBackend::Sqlite { + info!("Disabling foreign key check"); + db.execute(Statement::from_string( + db_backend, + "PRAGMA foreign_keys = OFF".to_owned(), + )) + .await?; + info!("Foreign key check disabled"); + } + + // Drop all foreign keys + if db_backend == DbBackend::MySql { + info!("Dropping all foreign keys"); + let mut stmt = Query::select(); + stmt.columns([Alias::new("TABLE_NAME"), Alias::new("CONSTRAINT_NAME")]) + .from(( + Alias::new("information_schema"), + Alias::new("table_constraints"), + )) + .cond_where( + Condition::all() + .add( + Expr::expr(get_current_schema(db)).equals( + Alias::new("table_constraints"), + Alias::new("table_schema"), + ), + ) + .add(Expr::expr(Expr::value("FOREIGN KEY")).equals( + Alias::new("table_constraints"), + Alias::new("constraint_type"), + )), + ); + let rows = db.query_all(db_backend.build(&stmt)).await?; + for row in rows.into_iter() { + let constraint_name: String = row.try_get("", "CONSTRAINT_NAME")?; + let table_name: String = row.try_get("", "TABLE_NAME")?; + info!( + "Dropping foreign key '{}' from table '{}'", + constraint_name, table_name + ); + let mut stmt = ForeignKey::drop(); + stmt.table(Alias::new(table_name.as_str())) + .name(constraint_name.as_str()); + db.execute(db_backend.build(&stmt)).await?; + info!("Foreign key '{}' has been dropped", constraint_name); + } + info!("All foreign keys dropped"); + } + + // Drop all tables + let stmt = query_tables(db); + let rows = db.query_all(db_backend.build(&stmt)).await?; + for row in rows.into_iter() { + let table_name: String = row.try_get("", "table_name")?; + info!("Dropping table '{}'", table_name); + let mut stmt = Table::drop(); + stmt.table(Alias::new(table_name.as_str())) + .if_exists() + .cascade(); + db.execute(db_backend.build(&stmt)).await?; + info!("Table '{}' has been dropped", table_name); + } + + // Restore the foreign key check + if db_backend == DbBackend::Sqlite { + info!("Restoring foreign key check"); + db.execute(Statement::from_string( + db_backend, + "PRAGMA foreign_keys = ON".to_owned(), + )) + .await?; + info!("Foreign key check restored"); + } + + // Reapply all migrations + Self::up(db, None).await + } + + /// Rollback all applied migrations, then reapply all migrations + async fn refresh(db: &DbConn) -> Result<(), DbErr> { + Self::down(db, None).await?; + Self::up(db, None).await + } + + /// Rollback all applied migrations + async fn reset(db: &DbConn) -> Result<(), DbErr> { + Self::down(db, None).await + } + + /// Check the status of all migrations + async fn status(db: &DbConn) -> Result<(), DbErr> { + Self::install(db).await?; + + info!("Checking migration status"); + + for Migration { migration, status } in Self::get_migration_with_status(db).await? { + info!("Migration '{}'... {}", migration.name(), status); + } + + Ok(()) + } + + /// Apply pending migrations + async fn up(db: &DbConn, mut steps: Option) -> Result<(), DbErr> { + Self::install(db).await?; + let manager = SchemaManager::new(db); + + if let Some(steps) = steps { + info!("Applying {} pending migrations", steps); + } else { + info!("Applying all pending migrations"); + } + + let migrations = Self::get_pending_migrations(db).await?.into_iter(); + if migrations.len() == 0 { + info!("No pending migrations"); + } + for Migration { migration, .. } in migrations { + if let Some(steps) = steps.as_mut() { + if steps == &0 { + break; + } + *steps -= 1; + } + info!("Applying migration '{}'", migration.name()); + migration.up(&manager).await?; + info!("Migration '{}' has been applied", migration.name()); + let now = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .expect("SystemTime before UNIX EPOCH!"); + seaql_migrations::ActiveModel { + version: ActiveValue::Set(migration.name().to_owned()), + applied_at: ActiveValue::Set(now.as_secs() as i64), + } + .insert(db) + .await?; + } + + Ok(()) + } + + /// Rollback applied migrations + async fn down(db: &DbConn, mut steps: Option) -> Result<(), DbErr> { + Self::install(db).await?; + let manager = SchemaManager::new(db); + + if let Some(steps) = steps { + info!("Rolling back {} applied migrations", steps); + } else { + info!("Rolling back all applied migrations"); + } + + let migrations = Self::get_applied_migrations(db).await?.into_iter().rev(); + if migrations.len() == 0 { + info!("No applied migrations"); + } + for Migration { migration, .. } in migrations { + if let Some(steps) = steps.as_mut() { + if steps == &0 { + break; + } + *steps -= 1; + } + info!("Rolling back migration '{}'", migration.name()); + migration.down(&manager).await?; + info!("Migration '{}' has been rollbacked", migration.name()); + seaql_migrations::Entity::delete_many() + .filter(seaql_migrations::Column::Version.eq(migration.name())) + .exec(db) + .await?; + } + + Ok(()) + } +} + +pub(crate) fn query_tables(db: &DbConn) -> SelectStatement { + let mut stmt = Query::select(); + let (expr, tbl_ref, condition) = match db.get_database_backend() { + DbBackend::MySql => ( + Expr::col(Alias::new("table_name")), + (Alias::new("information_schema"), Alias::new("tables")).into_table_ref(), + Condition::all().add( + Expr::expr(get_current_schema(db)) + .equals(Alias::new("tables"), Alias::new("table_schema")), + ), + ), + DbBackend::Postgres => ( + Expr::col(Alias::new("table_name")), + (Alias::new("information_schema"), Alias::new("tables")).into_table_ref(), + Condition::all() + .add( + Expr::expr(get_current_schema(db)) + .equals(Alias::new("tables"), Alias::new("table_schema")), + ) + .add(Expr::col(Alias::new("table_type")).eq("BASE TABLE")), + ), + DbBackend::Sqlite => ( + Expr::col(Alias::new("name")), + Alias::new("sqlite_master").into_table_ref(), + Condition::all() + .add(Expr::col(Alias::new("type")).eq("table")) + .add(Expr::col(Alias::new("name")).ne("sqlite_sequence")), + ), + }; + stmt.expr_as(expr, Alias::new("table_name")) + .from(tbl_ref) + .cond_where(condition); + stmt +} + +pub(crate) fn get_current_schema(db: &DbConn) -> SimpleExpr { + match db.get_database_backend() { + DbBackend::MySql => Expr::cust("DATABASE()"), + DbBackend::Postgres => Expr::cust("CURRENT_SCHEMA()"), + DbBackend::Sqlite => unimplemented!(), + } +} diff --git a/sea-orm-migration/src/prelude.rs b/sea-orm-migration/src/prelude.rs new file mode 100644 index 00000000..c116a49c --- /dev/null +++ b/sea-orm-migration/src/prelude.rs @@ -0,0 +1,8 @@ +//! Import migration utility + +pub use crate::*; +pub use async_std; +pub use async_trait; +pub use sea_orm::sea_query; +pub use sea_orm::sea_query::*; +pub use sea_orm::DbErr; diff --git a/sea-orm-migration/src/query.rs b/sea-orm-migration/src/query.rs new file mode 100644 index 00000000..0b23d0d5 --- /dev/null +++ b/sea-orm-migration/src/query.rs @@ -0,0 +1,20 @@ +//! Get query result from db + +use crate::into_migration_err; +use sea_schema::migration::{self, MigrationErr}; + +pub(crate) struct QueryResult { + pub(crate) res: sea_orm::QueryResult, +} + +impl migration::QueryResultTrait for QueryResult { + fn try_get_string(&self, col: &str) -> Result { + self.res + .try_get::("", col) + .map_err(into_migration_err) + } + + fn try_get_i64(&self, col: &str) -> Result { + self.res.try_get::("", col).map_err(into_migration_err) + } +} diff --git a/sea-orm-migration/src/seaql_migrations.rs b/sea-orm-migration/src/seaql_migrations.rs new file mode 100644 index 00000000..b387b57c --- /dev/null +++ b/sea-orm-migration/src/seaql_migrations.rs @@ -0,0 +1,18 @@ +#![allow(missing_docs)] + +//! Migration entity + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "seaql_migrations")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub version: String, + pub applied_at: i64, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/sea-orm-migration/src/statement.rs b/sea-orm-migration/src/statement.rs new file mode 100644 index 00000000..c897aee8 --- /dev/null +++ b/sea-orm-migration/src/statement.rs @@ -0,0 +1,12 @@ +//! Convert SQL statement + +use crate::into_orm_db_backend; +use sea_schema::migration; + +pub(crate) fn into_orm_stmt(stmt: migration::Statement) -> sea_orm::Statement { + sea_orm::Statement { + sql: stmt.sql, + values: stmt.values, + db_backend: into_orm_db_backend(stmt.db_backend), + } +} diff --git a/src/error.rs b/src/error.rs index 273b9c9d..3e6753c6 100644 --- a/src/error.rs +++ b/src/error.rs @@ -15,6 +15,8 @@ pub enum DbErr { Type(String), /// Error occurred while parsing json value as target type Json(String), + /// A migration error + Migration(String), } impl std::error::Error for DbErr {} @@ -29,6 +31,7 @@ impl std::fmt::Display for DbErr { Self::Custom(s) => write!(f, "Custom Error: {}", s), Self::Type(s) => write!(f, "Type Error: {}", s), Self::Json(s) => write!(f, "Json Error: {}", s), + Self::Migration(s) => write!(f, "Migration Error: {}", s), } } }