~vpzom/lotide

ref: 44be4e1a63974411e7b31274b23b3fbd0458a9f6 lotide/src/migrate.rs -rw-r--r-- 3.0 KiB
44be4e1a — Colin Reeder Update INSTALL.md to use embedded migrations 8 months ago
                                                                                
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
pub const MIGRATIONS: &[StaticMigration] = include!(concat!(env!("OUT_DIR"), "/migrations.rs"));

pub struct StaticMigration {
    tag: &'static str,
    up: &'static str,
    down: &'static str,
}

pub fn run(mut args: std::env::Args) {
    let action = args.next();
    let action = action.as_deref().unwrap_or("up");

    let database_url = std::env::var("DATABASE_URL").expect("Missing DATABASE_URL");
    let db_cfg: tokio_postgres::Config =
        database_url.parse().expect("Failed to parse DATABASE_URL");

    let mut settings = migrant_lib::Settings::configure_postgres();
    settings
        .database_name(db_cfg.get_dbname().expect("Missing dbname"))
        .database_user(db_cfg.get_user().expect("Missing user"))
        .database_password(
            std::str::from_utf8(db_cfg.get_password().expect("Missing password")).unwrap(),
        );

    let hosts = db_cfg.get_hosts();
    if !hosts.is_empty() {
        let host = hosts
            .iter()
            .filter_map(|host| match host {
                tokio_postgres::config::Host::Tcp(hostname) => Some(hostname),
                _ => None,
            })
            .next();

        match host {
            None => panic!("Unsupported host type"),
            Some(hostname) => {
                settings.database_host(hostname);
            }
        }
    }

    let ports = db_cfg.get_ports();
    if !ports.is_empty() {
        if ports.len() == 1 {
            settings.database_port(ports[0]);
        } else {
            panic!("Multiple ports are not supported");
        }
    }

    let settings = settings.build().unwrap();

    let mut config = migrant_lib::Config::with_settings(&settings);
    config.use_cli_compatible_tags(true);

    if action == "setup" {
        config.setup().expect("Failed to setup database");
    } else {
        let migrations: Vec<_> = MIGRATIONS
            .iter()
            .map(|item| {
                migrant_lib::EmbeddedMigration::with_tag(item.tag)
                    .up(item.up)
                    .down(item.down)
                    .boxed()
            })
            .collect();
        config
            .use_migrations(&migrations)
            .expect("Failed to initialize migrations");

        let config = config.reload().expect("Failed to check status");

        match action {
            "up" => {
                println!("Applying migrations...");
                migrant_lib::Migrator::with_config(&config)
                    .all(true)
                    .swallow_completion(true)
                    .apply()
                    .expect("Failed to apply migrations");
            }
            "down" => {
                println!("Unapplying migration...");
                migrant_lib::Migrator::with_config(&config)
                    .direction(migrant_lib::Direction::Down)
                    .all(false)
                    .swallow_completion(true)
                    .apply()
                    .expect("Failed to undo migration");
            }
            _ => panic!("Unknown migrate action"),
        }
    }
}