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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use crate::{ops::forc_postgres_createdb, pg::PostgresVersion, utils::db_dir_or_default};
use anyhow::Result;
use clap::Parser;
use fuel_indexer_lib::defaults;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

/// Create a new database.
#[derive(Debug, Parser, Clone, Serialize, Deserialize)]
pub struct Command {
    /// Name of database.
    #[clap(help = "Name of database.")]
    pub name: String,

    /// Database user.
    #[clap(short, long, default_value = defaults::POSTGRES_USER, help = "Database user.")]
    pub user: String,

    /// Database password.
    #[clap(long, default_value = defaults::POSTGRES_PASSWORD, help = "Database password.")]
    pub password: String,

    /// Port to use.
    #[clap(long, default_value = defaults::POSTGRES_PORT, help = "Port to use.")]
    pub port: String,

    /// Where to store the PostgreSQL database.
    #[clap(long, help = "Where to store the PostgreSQL database.")]
    pub database_dir: Option<PathBuf>,

    /// Authentication method.
    #[clap(long, default_value = "plain", value_parser(["plain", "md5", "scram-sha-256"]), help = "Authentication method.")]
    pub auth_method: String,

    /// Do not clean up files and directories on database drop.
    #[clap(long, help = "Do not clean up files and directories on database drop.")]
    pub persistent: bool,

    /// Duration to wait before terminating process execution for pg_ctl start/stop and initdb.
    #[clap(
        long,
        help = "Duration to wait before terminating process execution for pg_ctl start/stop and initdb."
    )]
    pub timeout: Option<u64>,

    /// The directory containing migration scripts.
    #[clap(long, help = "The directory containing migration scripts.")]
    pub migration_dir: Option<PathBuf>,

    /// PostgreSQL version to use.
    #[clap(
        long,
        arg_enum,
        default_value = "v14",
        help = "PostgreSQL version to use."
    )]
    pub postgres_version: PostgresVersion,

    /// Start the PostgreSQL instance after creation.
    #[clap(long, help = "Start the PostgreSQL instance after creation.")]
    pub start: bool,

    /// Fuel indexer configuration file.
    #[clap(short, long, help = "Fuel indexer configuration file.")]
    pub config: Option<PathBuf>,

    /// Verbose output.
    #[clap(short, long, help = "Verbose output.")]
    pub verbose: bool,
}

impl Default for Command {
    fn default() -> Self {
        Command {
            name: defaults::POSTGRES_DATABASE.to_string(),
            password: defaults::POSTGRES_PASSWORD.to_string(),
            user: defaults::POSTGRES_USER.to_string(),
            port: defaults::POSTGRES_PORT.to_string(),
            database_dir: None,
            auth_method: "plain".to_string(),
            persistent: true,
            start: false,
            config: None,
            timeout: None,
            migration_dir: None,
            postgres_version: PostgresVersion::V14,
            verbose: false,
        }
    }
}

pub async fn exec(command: Command) -> Result<()> {
    let Command {
        name,
        user,
        password,
        port,
        database_dir,
        auth_method,
        persistent,
        timeout,
        migration_dir,
        postgres_version,
        start,
        config,
        verbose,
    } = command;

    let database_dir = db_dir_or_default(database_dir.as_ref(), &name);

    forc_postgres_createdb::init(Command {
        name,
        user,
        password,
        port,
        database_dir: Some(database_dir),
        auth_method,
        persistent,
        timeout,
        migration_dir,
        postgres_version,
        start,
        config,
        verbose,
    })
    .await?;

    Ok(())
}