1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use clap::{App, AppSettings, Arg};
use dotenv::dotenv;
use std::{fmt::Display, process::exit};
use tracing_subscriber::{prelude::*, EnvFilter};

use sea_orm::{Database, DbConn};
use sea_orm_cli::migration::get_subcommands;

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_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);
}

pub fn build_cli() -> App<'static, 'static> {
    let mut app = App::new("sea-orm-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
}

fn handle_error<E>(error: E)
where
    E: Display,
{
    eprintln!("{}", error);
    exit(1);
}