Skip to main content

db_mover/
args.rs

1use crate::databases::mysql::{MysqlDB, MysqlTypeOptions};
2use crate::databases::postgres::PostgresDB;
3use crate::databases::sqlite::SqliteDB;
4use crate::databases::traits::{DBReader, DBWriter};
5use crate::uri::URI;
6use anyhow::Context;
7use clap::Parser;
8use tracing::Level;
9
10#[derive(Parser, Clone)]
11#[command(version, about, long_about = None)]
12#[command(next_line_help = true)]
13pub struct Args {
14    /// Input URI of database
15    #[arg(long, short)]
16    pub input: URI,
17
18    /// Output URI of database
19    #[arg(long, short)]
20    pub output: URI,
21
22    /// List of tables. By default all tables from the input database
23    #[arg(long, short)]
24    pub table: Vec<String>,
25
26    /// Size of queue between reader and writers
27    #[arg(long, default_value_t = 100_000)]
28    pub queue_size: usize,
29
30    /// Number of writer workers (if supported by database)
31    #[arg(long, default_value_t = 1)]
32    pub writer_workers: usize,
33
34    /// Size of batches used by writer
35    #[arg(long, default_value_t = 10_000)]
36    pub batch_write_size: usize,
37
38    /// Number of retries to write a batch. Exponential retry is used, with start value 500ms and
39    /// factor of 2.
40    #[arg(long, default_value_t = 5)]
41    pub batch_write_retries: usize,
42
43    /// Disable output
44    #[clap(long, action)]
45    pub quiet: bool,
46
47    /// Log level
48    #[arg(long, default_value_t = Level::INFO)]
49    pub log_level: Level,
50
51    /// Disable the COUNT query used for progress tracking.
52    /// Progress will be shown but without prognoses.
53    /// Only for input table.
54    #[clap(long, action)]
55    pub no_count: bool,
56
57    /// Check compatibility without moving a data
58    #[clap(long, action)]
59    pub dry_run: bool,
60
61    /// Disable assumption that binary(16) is UUID for MySQL
62    #[clap(long, action)]
63    pub no_mysql_binary_16_as_uuid: bool,
64}
65
66impl Args {
67    pub fn new(input: URI, output: URI) -> Self {
68        return Args {
69            input,
70            output,
71            table: Vec::new(),
72            queue_size: 100_000,
73            writer_workers: 1,
74            batch_write_size: 10_000,
75            batch_write_retries: 1,
76            quiet: true,
77            log_level: Level::INFO,
78            no_count: false,
79            dry_run: false,
80            no_mysql_binary_16_as_uuid: false,
81        };
82    }
83
84    fn build_sqlite(&self, uri: &str) -> anyhow::Result<Box<SqliteDB>> {
85        return Ok(Box::new(
86            SqliteDB::new(uri).context("Unable to connect to the sqlite")?,
87        ));
88    }
89
90    fn build_postgres(&self, uri: &str) -> anyhow::Result<Box<PostgresDB>> {
91        return Ok(Box::new(
92            PostgresDB::new(uri).context("Unable to connect to the postgres")?,
93        ));
94    }
95
96    fn build_mysql(&self, uri: &str) -> anyhow::Result<Box<MysqlDB>> {
97        let options = MysqlTypeOptions {
98            binary_16_as_uuid: !self.no_mysql_binary_16_as_uuid,
99            ..Default::default()
100        };
101        let db = MysqlDB::new(uri, options).context("Unable to connect to the mysql")?;
102        return Ok(Box::new(db));
103    }
104
105    pub fn create_reader(&self) -> anyhow::Result<Box<dyn DBReader>> {
106        let reader: Box<dyn DBReader> = match &self.input {
107            URI::Sqlite(uri) => self.build_sqlite(uri)?,
108            URI::Postgres(uri) => self.build_postgres(uri)?,
109            URI::Mysql(uri) => self.build_mysql(uri)?,
110        };
111        return Ok(reader);
112    }
113
114    pub fn create_writer(&self) -> anyhow::Result<Box<dyn DBWriter>> {
115        let writer: Box<dyn DBWriter> = match &self.output {
116            URI::Sqlite(uri) => self.build_sqlite(uri)?,
117            URI::Postgres(uri) => self.build_postgres(uri)?,
118            URI::Mysql(uri) => self.build_mysql(uri)?,
119        };
120        return Ok(writer);
121    }
122}