Merge pull request #666 from SeaQL/sea-schema/dump-sea-orm-dep

Dump SeaORM Dependency from SeaSchema's Migrator
This commit is contained in:
Chris Tsang 2022-05-09 19:48:43 +08:00 committed by GitHub
commit 25f3db731b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
69 changed files with 1172 additions and 109 deletions

View File

@ -383,6 +383,14 @@ jobs:
--test '*'
--features default,sqlx-sqlite,runtime-${{ matrix.runtime }}-${{ matrix.tls }}
- uses: actions-rs/cargo@v1
with:
command: test
args: >
--manifest-path sea-orm-migration/Cargo.toml
--test '*'
--features sqlx-sqlite,runtime-${{ matrix.runtime }}-${{ matrix.tls }}
mysql:
name: MySQL
needs:
@ -444,6 +452,14 @@ jobs:
--test '*'
--features default,sqlx-mysql,runtime-${{ matrix.runtime }}-${{ matrix.tls }}
- uses: actions-rs/cargo@v1
with:
command: test
args: >
--manifest-path sea-orm-migration/Cargo.toml
--test '*'
--features sqlx-mysql,runtime-${{ matrix.runtime }}-${{ matrix.tls }}
mariadb:
name: MariaDB
needs:
@ -562,3 +578,11 @@ jobs:
args: >
--test '*'
--features default,sqlx-postgres,runtime-${{ matrix.runtime }}-${{ matrix.tls }}
- uses: actions-rs/cargo@v1
with:
command: test
args: >
--manifest-path sea-orm-migration/Cargo.toml
--test '*'
--features sqlx-postgres,runtime-${{ matrix.runtime }}-${{ matrix.tls }}

View File

@ -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" }

View File

@ -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",

View File

@ -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"

View File

@ -1,4 +1,4 @@
pub use sea_schema::migration::prelude::*;
pub use sea_orm_migration::prelude::*;
mod m20220120_000001_create_post_table;

View File

@ -1,5 +1,5 @@
use entity::post::*;
use sea_schema::migration::prelude::*;
use sea_orm_migration::prelude::*;
pub struct Migration;

View File

@ -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;
}

View File

@ -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",

View File

@ -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"

View File

@ -1,4 +1,4 @@
pub use sea_schema::migration::prelude::*;
pub use sea_orm_migration::prelude::*;
mod m20220120_000001_create_post_table;

View File

@ -1,5 +1,5 @@
use entity::post::*;
use sea_schema::migration::prelude::*;
use sea_orm_migration::prelude::*;
pub struct Migration;

View File

@ -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;
}

View File

@ -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;

View File

@ -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",

View File

@ -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"

View File

@ -1,4 +1,4 @@
pub use sea_schema::migration::prelude::*;
pub use sea_orm_migration::prelude::*;
mod m20220120_000001_create_post_table;

View File

@ -1,5 +1,5 @@
use entity::post::*;
use sea_schema::migration::prelude::*;
use sea_orm_migration::prelude::*;
pub struct Migration;

View File

@ -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;
}

View File

@ -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",

View File

@ -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" }
entity = { path = "../entity" }
[dependencies.sea-orm-migration]
path = "../../../sea-orm-migration" # remove this line in your own project
version = "^0.7.0"

View File

@ -1,4 +1,4 @@
pub use sea_schema::migration::*;
pub use sea_orm_migration::prelude::*;
mod m20220101_000001_create_table;

View File

@ -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;

View File

@ -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;
}

View File

@ -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",

View File

@ -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"

View File

@ -1,4 +1,4 @@
pub use sea_schema::migration::prelude::*;
pub use sea_orm_migration::prelude::*;
mod m20220120_000001_create_post_table;

View File

@ -1,5 +1,5 @@
use entity::post::*;
use sea_schema::migration::prelude::*;
use sea_orm_migration::prelude::*;
pub struct Migration;

View File

@ -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;
}

View File

@ -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",

View File

@ -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"

View File

@ -1,4 +1,4 @@
pub use sea_schema::migration::prelude::*;
pub use sea_orm_migration::prelude::*;
mod m20220120_000001_create_post_table;

View File

@ -1,5 +1,5 @@
use entity::post::*;
use sea_schema::migration::prelude::*;
use sea_orm_migration::prelude::*;
pub struct Migration;

View File

@ -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;
}

View File

@ -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",

View File

@ -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" }

View File

@ -1,4 +1,4 @@
pub use sea_schema::migration::prelude::*;
pub use sea_orm_migration::prelude::*;
mod m20220120_000001_create_post_table;

View File

@ -1,5 +1,5 @@
use entity::post::*;
use sea_schema::migration::prelude::*;
use sea_orm_migration::prelude::*;
pub struct Migration;

View File

@ -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;
}

View File

@ -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"

View File

@ -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",

View File

@ -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"

View File

@ -1,4 +1,4 @@
pub use sea_schema::migration::prelude::*;
pub use sea_orm_migration::prelude::*;
mod m20220120_000001_create_post_table;

View File

@ -1,5 +1,5 @@
use entity::post::*;
use sea_schema::migration::prelude::*;
use sea_orm_migration::prelude::*;
pub struct Migration;

View File

@ -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;
}

View File

@ -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};

View File

@ -14,7 +14,6 @@ categories = [ "database" ]
keywords = ["async", "orm", "mysql", "postgres", "sqlite"]
default-run = "sea-orm-cli"
[lib]
name = "sea_orm_cli"
path = "src/lib.rs"
@ -22,26 +21,20 @@ path = "src/lib.rs"
[[bin]]
name = "sea-orm-cli"
path = "src/bin/main.rs"
required-features = ["codegen"]
[[bin]]
name = "sea"
path = "src/bin/sea.rs"
required-features = ["codegen"]
[dependencies]
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 = [
"debug-print",
"sqlx-mysql",
"sqlx-sqlite",
"sqlx-postgres",
"discovery",
"writer",
"migration",
] }
sqlx = { version = "^0.5", default-features = false, features = [ "mysql", "postgres" ] }
sea-orm-codegen = { version = "^0.7.0", path = "../sea-orm-codegen", optional = true }
sea-schema = { git = "https://github.com/SeaQL/sea-schema", branch = "master" }
sqlx = { version = "^0.5", default-features = false, features = [ "mysql", "postgres" ], optional = true }
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
tracing = { version = "0.1" }
url = "^2.2"
@ -50,28 +43,11 @@ url = "^2.2"
smol = "1.2.5"
[features]
default = [ "runtime-async-std-native-tls" ]
runtime-actix-native-tls = [
"sqlx/runtime-actix-native-tls",
"sea-schema/runtime-actix-native-tls",
]
runtime-async-std-native-tls = [
"sqlx/runtime-async-std-native-tls",
"sea-schema/runtime-async-std-native-tls",
]
runtime-tokio-native-tls = [
"sqlx/runtime-tokio-native-tls",
"sea-schema/runtime-tokio-native-tls",
]
runtime-actix-rustls = [
"sqlx/runtime-actix-rustls",
"sea-schema/runtime-actix-rustls",
]
runtime-async-std-rustls = [
"sqlx/runtime-async-std-rustls",
"sea-schema/runtime-async-std-rustls",
]
runtime-tokio-rustls = [
"sqlx/runtime-tokio-rustls",
"sea-schema/runtime-tokio-rustls",
]
default = [ "codegen", "runtime-async-std-native-tls" ]
codegen = [ "sea-schema/sqlx-all", "sea-orm-codegen" ]
runtime-actix-native-tls = [ "sqlx/runtime-actix-native-tls", "sea-schema/runtime-actix-native-tls" ]
runtime-async-std-native-tls = [ "sqlx/runtime-async-std-native-tls", "sea-schema/runtime-async-std-native-tls" ]
runtime-tokio-native-tls = [ "sqlx/runtime-tokio-native-tls", "sea-schema/runtime-tokio-native-tls" ]
runtime-actix-rustls = [ "sqlx/runtime-actix-rustls", "sea-schema/runtime-actix-rustls" ]
runtime-async-std-rustls = [ "sqlx/runtime-async-std-rustls", "sea-schema/runtime-async-std-rustls" ]
runtime-tokio-rustls = [ "sqlx/runtime-tokio-rustls", "sea-schema/runtime-tokio-rustls" ]

View File

@ -1,3 +1,4 @@
use crate::migration::get_subcommands;
use clap::{App, AppSettings, Arg, SubCommand};
pub fn build_cli() -> App<'static, 'static> {
@ -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_subcommands() {
migrate_subcommands =
migrate_subcommands.subcommand(subcommand.arg(arg_migration_dir.clone()));
}

View File

@ -117,7 +117,7 @@ pub async fn run_generate_command(matches: &ArgMatches<'_>) -> Result<(), Box<dy
.collect()
}
"sqlite" => {
use sea_schema::sqlite::SchemaDiscovery;
use sea_schema::sqlite::discovery::SchemaDiscovery;
use sqlx::Sqlite;
let connection = connect::<Sqlite>(max_connections, url.as_str()).await?;

View File

@ -1,5 +1,8 @@
pub mod cli;
#[cfg(feature = "codegen")]
pub mod commands;
pub mod migration;
pub use cli::*;
#[cfg(feature = "codegen")]
pub use commands::*;

View File

@ -0,0 +1,49 @@
use clap::{App, AppSettings, Arg, SubCommand};
pub 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_subcommands() {
app = app.subcommand(subcommand);
}
app
}
pub fn get_subcommands() -> Vec<App<'static, 'static>> {
vec![
SubCommand::with_name("fresh")
.about("Drop all tables from the database, then reapply all migrations"),
SubCommand::with_name("refresh")
.about("Rollback all applied migrations, then reapply all migrations"),
SubCommand::with_name("reset").about("Rollback all applied migrations"),
SubCommand::with_name("status").about("Check the status of all migrations"),
SubCommand::with_name("up")
.about("Apply pending migrations")
.arg(
Arg::with_name("NUM_MIGRATION")
.long("num")
.short("n")
.help("Number of pending migrations to be applied")
.takes_value(true),
),
SubCommand::with_name("down")
.about("Rollback applied migrations")
.arg(
Arg::with_name("NUM_MIGRATION")
.long("num")
.short("n")
.help("Number of pending migrations to be rolled back")
.takes_value(true)
.default_value("1"),
),
]
}

View File

@ -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"

View File

@ -1,4 +1,4 @@
pub use sea_schema::migration::prelude::*;
pub use sea_orm_migration::prelude::*;
mod m20220101_000001_create_table;

View File

@ -1,4 +1,4 @@
use sea_schema::migration::prelude::*;
use sea_orm_migration::prelude::*;
pub struct Migration;

View File

@ -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;
}

View File

@ -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",

View File

@ -0,0 +1,40 @@
[workspace]
# A separate workspace
[package]
name = "sea-orm-migration"
version = "0.7.2"
authors = [ "Billy Chan <ccw.billy.123@gmail.com>" ]
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]
async-std = { version = "^1", features = ["attributes", "tokio1"] }
async-trait = { version = "^0.1" }
clap = { version = "^2.33" }
dotenv = { version = "^0.15" }
sea-orm = { path = "../", default-features = false, features = ["macros"] }
sea-orm-cli = { path = "../sea-orm-cli", default-features = false }
sea-schema = { git = "https://github.com/SeaQL/sea-schema", branch = "master" }
tracing = { version = "0.1", features = ["log"] }
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
[features]
sqlx-mysql = ["sea-orm/sqlx-mysql"]
sqlx-postgres = ["sea-orm/sqlx-postgres"]
sqlx-sqlite = ["sea-orm/sqlx-sqlite"]
runtime-actix-native-tls = [ "sea-orm/runtime-actix-native-tls" ]
runtime-async-std-native-tls = [ "sea-orm/runtime-async-std-native-tls" ]
runtime-tokio-native-tls = [ "sea-orm/runtime-tokio-native-tls" ]
runtime-actix-rustls = [ "sea-orm/runtime-actix-rustls" ]
runtime-async-std-rustls = [ "sea-orm/runtime-async-std-rustls" ]
runtime-tokio-rustls = [ "sea-orm/runtime-tokio-rustls" ]

View File

@ -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
```

View File

@ -0,0 +1,83 @@
use clap::App;
use dotenv::dotenv;
use std::{fmt::Display, process::exit};
use tracing_subscriber::{prelude::*, EnvFilter};
use sea_orm::{Database, DbConn};
use sea_orm_cli::build_cli;
use super::MigratorTrait;
pub async fn run_cli<M>(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;
}
pub async fn get_matches<M>(_: 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_schema::migration=info",
(_, Some(args)) => match args.is_present("VERBOSE") {
true => {
verbose = true;
"debug"
}
false => "sea_schema::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 handle_error<E>(error: E)
where
E: Display,
{
eprintln!("{}", error);
exit(1);
}

View File

@ -0,0 +1,28 @@
pub mod cli;
pub mod manager;
pub mod migrator;
pub mod prelude;
pub mod seaql_migrations;
pub use manager::*;
pub use migrator::*;
pub use async_std;
pub use async_trait;
pub use sea_orm;
pub use sea_orm::sea_query;
pub use sea_orm::DbErr;
pub trait MigrationName {
fn name(&self) -> &str;
}
/// The migration definition
#[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>;
}

View File

@ -0,0 +1,133 @@
use sea_orm::sea_query::{
extension::postgres::{TypeAlterStatement, TypeCreateStatement, TypeDropStatement},
Alias, Expr, ForeignKeyCreateStatement, ForeignKeyDropStatement, IndexCreateStatement,
IndexDropStatement, Query, TableAlterStatement, TableCreateStatement, TableDropStatement,
TableRenameStatement, TableTruncateStatement,
};
use sea_orm::{Condition, ConnectionTrait, DbBackend, DbConn, DbErr, Statement, StatementBuilder};
use sea_schema::{mysql::MySql, postgres::Postgres, probe::SchemaProbe, sqlite::Sqlite};
/// Helper struct for writing migration scripts in migration file
pub struct SchemaManager<'c> {
conn: &'c DbConn,
}
impl<'c> SchemaManager<'c> {
pub fn new(conn: &'c DbConn) -> Self {
Self { conn }
}
pub async fn exec_stmt<S>(&self, stmt: S) -> Result<(), DbErr>
where
S: StatementBuilder,
{
let builder = self.conn.get_database_backend();
self.conn.execute(builder.build(&stmt)).await.map(|_| ())
}
pub fn get_database_backend(&self) -> DbBackend {
self.conn.get_database_backend()
}
pub fn get_connection(&self) -> &'c DbConn {
self.conn
}
}
/// Schema Creation
impl<'c> SchemaManager<'c> {
pub async fn create_table(&self, stmt: TableCreateStatement) -> Result<(), DbErr> {
self.exec_stmt(stmt).await
}
pub async fn create_index(&self, stmt: IndexCreateStatement) -> Result<(), DbErr> {
self.exec_stmt(stmt).await
}
pub async fn create_foreign_key(&self, stmt: ForeignKeyCreateStatement) -> Result<(), DbErr> {
self.exec_stmt(stmt).await
}
pub async fn create_type(&self, stmt: TypeCreateStatement) -> Result<(), DbErr> {
self.exec_stmt(stmt).await
}
}
/// Schema Mutation
impl<'c> SchemaManager<'c> {
pub async fn alter_table(&self, stmt: TableAlterStatement) -> Result<(), DbErr> {
self.exec_stmt(stmt).await
}
pub async fn drop_table(&self, stmt: TableDropStatement) -> Result<(), DbErr> {
self.exec_stmt(stmt).await
}
pub async fn rename_table(&self, stmt: TableRenameStatement) -> Result<(), DbErr> {
self.exec_stmt(stmt).await
}
pub async fn truncate_table(&self, stmt: TableTruncateStatement) -> Result<(), DbErr> {
self.exec_stmt(stmt).await
}
pub async fn drop_index(&self, stmt: IndexDropStatement) -> Result<(), DbErr> {
self.exec_stmt(stmt).await
}
pub async fn drop_foreign_key(&self, stmt: ForeignKeyDropStatement) -> Result<(), DbErr> {
self.exec_stmt(stmt).await
}
pub async fn alter_type(&self, stmt: TypeAlterStatement) -> Result<(), DbErr> {
self.exec_stmt(stmt).await
}
pub async fn drop_type(&self, stmt: TypeDropStatement) -> Result<(), DbErr> {
self.exec_stmt(stmt).await
}
}
/// Schema Inspection
impl<'c> SchemaManager<'c> {
pub async fn has_table<T>(&self, table: T) -> Result<bool, DbErr>
where
T: AsRef<str>,
{
let stmt = match self.conn.get_database_backend() {
DbBackend::MySql => MySql::has_table(table),
DbBackend::Postgres => Postgres::has_table(table),
DbBackend::Sqlite => Sqlite::has_table(table),
};
let builder = self.conn.get_database_backend();
let res = self
.conn
.query_one(builder.build(&stmt))
.await?
.ok_or_else(|| DbErr::Custom("Failed to check table exists".to_owned()))?;
Ok(res.try_get("", "has_table")?)
}
pub async fn has_column<T, C>(&self, table: T, column: C) -> Result<bool, DbErr>
where
T: AsRef<str>,
C: AsRef<str>,
{
let stmt = match self.conn.get_database_backend() {
DbBackend::MySql => MySql::has_column(table, column),
DbBackend::Postgres => Postgres::has_column(table, column),
DbBackend::Sqlite => Sqlite::has_column(table, column),
};
let builder = self.conn.get_database_backend();
let res = self
.conn
.query_one(builder.build(&stmt))
.await?
.ok_or_else(|| DbErr::Custom("Failed to check column exists".to_owned()))?;
Ok(res.try_get("", "has_column")?)
}
}

View File

@ -0,0 +1,308 @@
use std::fmt::Display;
use std::time::SystemTime;
use tracing::info;
use sea_orm::sea_query::{Alias, Expr, ForeignKey, Query, SelectStatement, SimpleExpr, Table};
use sea_orm::{
ActiveModelTrait, ActiveValue, ColumnTrait, Condition, ConnectionTrait, DbBackend, DbConn,
DbErr, EntityTrait, QueryFilter, QueryOrder, Schema, Statement,
};
use sea_schema::{mysql::MySql, postgres::Postgres, probe::SchemaProbe, sqlite::Sqlite};
use super::{seaql_migrations, MigrationTrait, SchemaManager};
#[derive(Debug, PartialEq)]
/// Status of migration
pub enum MigrationStatus {
/// Not yet applied
Pending,
/// Applied
Applied,
}
pub struct Migration {
migration: Box<dyn MigrationTrait>,
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<Box<dyn MigrationTrait>>;
/// Get list of migrations wrapped in `Migration` struct
fn get_migration_files() -> Vec<Migration> {
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<Vec<seaql_migrations::Model>, 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<Vec<Migration>, 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<Vec<Migration>, 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<Vec<Migration>, 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<u32>) -> 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<u32>) -> 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 {
match db.get_database_backend() {
DbBackend::MySql => MySql::query_tables(),
DbBackend::Postgres => Postgres::query_tables(),
DbBackend::Sqlite => Sqlite::query_tables(),
}
}
pub(crate) fn get_current_schema(db: &DbConn) -> SimpleExpr {
match db.get_database_backend() {
DbBackend::MySql => MySql::get_current_schema(),
DbBackend::Postgres => Postgres::get_current_schema(),
DbBackend::Sqlite => unimplemented!(),
}
}

View File

@ -0,0 +1,11 @@
pub use sea_orm_cli::migration as cli;
pub use super::manager::SchemaManager;
pub use super::migrator::MigratorTrait;
pub use super::{MigrationName, MigrationTrait};
pub use async_std;
pub use async_trait;
pub use sea_orm;
pub use sea_orm::sea_query;
pub use sea_orm::sea_query::*;
pub use sea_orm::DbErr;

View File

@ -0,0 +1,14 @@
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 {}

View File

@ -0,0 +1,121 @@
mod migrator;
use migrator::Migrator;
use sea_orm::{ConnectionTrait, Database, DbBackend, DbErr, Statement};
use sea_orm_migration::prelude::*;
#[async_std::test]
async fn main() -> Result<(), DbErr> {
let url = std::env::var("DATABASE_URL").expect("Environment variable 'DATABASE_URL' not set");
let db_name = "sea_orm_migration";
let db = Database::connect(&url).await?;
let db = &match db.get_database_backend() {
DbBackend::MySql => {
db.execute(Statement::from_string(
db.get_database_backend(),
format!("CREATE DATABASE IF NOT EXISTS `{}`;", db_name),
))
.await?;
let url = format!("{}/{}", url, db_name);
Database::connect(&url).await?
}
DbBackend::Postgres => {
db.execute(Statement::from_string(
db.get_database_backend(),
format!("DROP DATABASE IF EXISTS \"{}\";", db_name),
))
.await?;
db.execute(Statement::from_string(
db.get_database_backend(),
format!("CREATE DATABASE \"{}\";", db_name),
))
.await?;
let url = format!("{}/{}", url, db_name);
Database::connect(&url).await?
}
DbBackend::Sqlite => db,
};
let manager = SchemaManager::new(db);
println!("\nMigrator::status");
Migrator::status(db).await?;
println!("\nMigrator::install");
Migrator::install(db).await?;
assert!(manager.has_table("seaql_migrations").await?);
println!("\nMigrator::reset");
Migrator::reset(db).await?;
assert!(!manager.has_table("cake").await?);
assert!(!manager.has_table("fruit").await?);
println!("\nMigrator::up");
Migrator::up(db, Some(0)).await?;
assert!(!manager.has_table("cake").await?);
assert!(!manager.has_table("fruit").await?);
println!("\nMigrator::up");
Migrator::up(db, Some(1)).await?;
assert!(manager.has_table("cake").await?);
assert!(!manager.has_table("fruit").await?);
println!("\nMigrator::down");
Migrator::down(db, Some(0)).await?;
assert!(manager.has_table("cake").await?);
assert!(!manager.has_table("fruit").await?);
println!("\nMigrator::down");
Migrator::down(db, Some(1)).await?;
assert!(!manager.has_table("cake").await?);
assert!(!manager.has_table("fruit").await?);
println!("\nMigrator::up");
Migrator::up(db, None).await?;
println!("\nMigrator::status");
Migrator::status(db).await?;
assert!(manager.has_table("cake").await?);
assert!(manager.has_table("fruit").await?);
assert!(manager.has_column("cake", "name").await?);
assert!(manager.has_column("fruit", "cake_id").await?);
println!("\nMigrator::down");
Migrator::down(db, None).await?;
assert!(manager.has_table("seaql_migrations").await?);
assert!(!manager.has_table("cake").await?);
assert!(!manager.has_table("fruit").await?);
println!("\nMigrator::fresh");
Migrator::fresh(db).await?;
assert!(manager.has_table("cake").await?);
assert!(manager.has_table("fruit").await?);
println!("\nMigrator::refresh");
Migrator::refresh(db).await?;
assert!(manager.has_table("cake").await?);
assert!(manager.has_table("fruit").await?);
println!("\nMigrator::reset");
Migrator::reset(db).await?;
assert!(!manager.has_table("cake").await?);
assert!(!manager.has_table("fruit").await?);
println!("\nMigrator::status");
Migrator::status(db).await?;
Ok(())
}

View File

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

View File

@ -0,0 +1,63 @@
use super::m20220118_000001_create_cake_table::Cake;
use sea_orm::DbBackend;
use sea_orm_migration::prelude::*;
pub struct Migration;
impl MigrationName for Migration {
fn name(&self) -> &str {
"m20220118_000002_create_fruit_table"
}
}
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(Fruit::Table)
.col(
ColumnDef::new(Fruit::Id)
.integer()
.not_null()
.auto_increment()
.primary_key(),
)
.col(ColumnDef::new(Fruit::Name).string().not_null())
.col(ColumnDef::new(Fruit::CakeId).integer().not_null())
.foreign_key(
ForeignKey::create()
.name("fk-fruit-cake_id")
.from(Fruit::Table, Fruit::CakeId)
.to(Cake::Table, Cake::Id),
)
.to_owned(),
)
.await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
if manager.get_database_backend() != DbBackend::Sqlite {
manager
.drop_foreign_key(
ForeignKey::drop()
.table(Fruit::Table)
.name("fk-fruit-cake_id")
.to_owned(),
)
.await?;
}
manager
.drop_table(Table::drop().table(Fruit::Table).to_owned())
.await
}
}
#[derive(Iden)]
pub enum Fruit {
Table,
Id,
Name,
CakeId,
}

View File

@ -0,0 +1,52 @@
use sea_orm::{entity::prelude::*, Set};
use sea_orm_migration::prelude::*;
pub struct Migration;
impl MigrationName for Migration {
fn name(&self) -> &str {
"m20220118_000003_seed_cake_table"
}
}
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
let db = manager.get_connection();
cake::ActiveModel {
name: Set("Cheesecake".to_owned()),
..Default::default()
}
.insert(db)
.await
.map(|_| ())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
let db = manager.get_connection();
cake::Entity::delete_many()
.filter(cake::Column::Name.eq("Cheesecake"))
.exec(db)
.await
.map(|_| ())
}
}
mod cake {
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "cake")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub name: String,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
}

View File

@ -0,0 +1,18 @@
use sea_orm_migration::prelude::*;
mod m20220118_000001_create_cake_table;
mod m20220118_000002_create_fruit_table;
mod m20220118_000003_seed_cake_table;
pub struct Migrator;
#[async_trait::async_trait]
impl MigratorTrait for Migrator {
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
vec![
Box::new(m20220118_000001_create_cake_table::Migration),
Box::new(m20220118_000002_create_fruit_table::Migration),
Box::new(m20220118_000003_seed_cake_table::Migration),
]
}
}

View File

@ -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),
}
}
}