• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

getdozer / dozer / 4020902227

pending completion
4020902227

Pull #743

github

GitHub
Merge 57279c6b6 into a12da35a5
Pull Request #743: Chore clippy fix

165 of 165 new or added lines in 60 files covered. (100.0%)

23638 of 35485 relevant lines covered (66.61%)

38417.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/dozer-orchestrator/src/cli/init.rs
1
use crate::errors::{CliError, OrchestrationError};
2
use dozer_types::{
3
    ingestion_types::{EthConfig, EthFilter, SnowflakeConfig},
4
    log::info,
5
    models::{
6
        app_config::Config,
7
        connection::{Authentication, Connection, DBType, PostgresAuthentication},
8
    },
9
    serde_yaml,
10
};
11
use rustyline::{
12
    completion::{Completer, Pair},
13
    Context,
14
};
15
use rustyline::{error::ReadlineError, Editor};
16
use rustyline_derive::{Helper, Highlighter, Hinter, Validator};
17

18
#[derive(Helper, Highlighter, Hinter, Validator)]
19
pub struct InitHelper {}
20

21
impl Completer for InitHelper {
22
    type Candidate = Pair;
23
    fn complete(
×
24
        &self,
×
25
        line: &str,
×
26
        _pos: usize,
×
27
        _ctx: &Context,
×
28
    ) -> rustyline::Result<(usize, Vec<Self::Candidate>)> {
×
29
        let line = format!("{line}_");
×
30
        let mut tokens = line.split_whitespace();
×
31
        let mut last_token = String::from(tokens.next_back().unwrap());
×
32
        last_token.pop();
×
33
        let candidates: Vec<String> = vec![
×
34
            "Postgres".to_owned(),
×
35
            "Ethereum".to_owned(),
×
36
            "Snowflake".to_owned(),
×
37
        ];
×
38
        let mut match_pair: Vec<Pair> = candidates
×
39
            .iter()
×
40
            .filter_map(|f| {
×
41
                if f.to_lowercase().starts_with(&last_token.to_lowercase()) {
×
42
                    Some(Pair {
×
43
                        display: f.to_owned(),
×
44
                        replacement: f.to_owned(),
×
45
                    })
×
46
                } else {
47
                    None
×
48
                }
49
            })
×
50
            .collect();
×
51
        if match_pair.is_empty() {
×
52
            match_pair = vec![Pair {
×
53
                display: "Postgres".to_owned(),
×
54
                replacement: "Postgres".to_owned(),
×
55
            }]
×
56
        }
×
57
        Ok((line.len() - last_token.len() - 1, match_pair))
×
58
    }
×
59
}
60

61
fn sample_connection(connection_name: &str) -> Connection {
×
62
    match connection_name {
×
63
        "Snowflake" | "snowflake" | "S" | "s" => {
×
64
            let snowflake_config = SnowflakeConfig {
×
65
                server: "server".to_owned(),
×
66
                port: "443".to_owned(),
×
67
                user: "bob".to_owned(),
×
68
                password: "password".to_owned(),
×
69
                database: "database".to_owned(),
×
70
                schema: "schema".to_owned(),
×
71
                warehouse: "warehouse".to_owned(),
×
72
                driver: Some("SnowflakeDSIIDriver".to_owned()),
×
73
            };
×
74
            let connection: Connection = Connection {
×
75
                name: "snowflake".to_owned(),
×
76
                authentication: Some(Authentication::Snowflake(snowflake_config)),
×
77
                db_type: DBType::Ethereum as i32,
×
78
                ..Connection::default()
×
79
            };
×
80
            connection
×
81
        }
82
        "Ethereum" | "ethereum" | "E" | "e" => {
×
83
            let eth_filter = EthFilter {
×
84
                from_block: Some(0),
×
85
                to_block: None,
×
86
                addresses: vec![],
×
87
                topics: vec![],
×
88
            };
×
89
            let ethereum_auth = EthConfig {
×
90
                filter: Some(eth_filter),
×
91
                wss_url: "wss://link".to_owned(),
×
92
                contracts: vec![],
×
93
            };
×
94
            let connection: Connection = Connection {
×
95
                name: "ethereum".to_owned(),
×
96
                authentication: Some(Authentication::Ethereum(ethereum_auth)),
×
97
                db_type: DBType::Ethereum as i32,
×
98
                ..Connection::default()
×
99
            };
×
100
            connection
×
101
        }
102
        _ => {
103
            let postgres_auth = PostgresAuthentication {
×
104
                user: "postgres".to_owned(),
×
105
                password: "postgres".to_owned(),
×
106
                host: "localhost".to_owned(),
×
107
                port: 5432,
×
108
                database: "users".to_owned(),
×
109
            };
×
110
            let connection: Connection = Connection {
×
111
                name: "postgres".to_owned(),
×
112
                authentication: Some(Authentication::Postgres(postgres_auth)),
×
113
                db_type: DBType::Postgres as i32,
×
114
                ..Connection::default()
×
115
            };
×
116
            connection
×
117
        }
118
    }
119
}
×
120
type Question = (
121
    &'static str,
122
    Box<dyn Fn((String, &mut Config)) -> Result<(), OrchestrationError>>,
123
);
124
pub fn init_simple_config_file_with_question() -> Result<(), OrchestrationError> {
×
125
    let mut rl = Editor::<InitHelper>::new()
×
126
        .map_err(|e| OrchestrationError::CliError(CliError::ReadlineError(e)))?;
×
127
    rl.set_helper(Some(InitHelper {}));
×
128
    let mut default_config = Config::default();
×
129
    let questions: Vec<Question> = vec![
×
130
        (
×
131
            "question: App name (quick-start-app): ",
×
132
            Box::new(move |(app_name, config)| {
×
133
                let app_name = app_name.trim();
×
134
                if app_name.is_empty() {
×
135
                    config.app_name = "quick-start-app".to_string();
×
136
                } else {
×
137
                    config.app_name = app_name.to_string();
×
138
                }
×
139
                Ok(())
×
140
            }),
×
141
        ),
×
142
        (
×
143
            "question: Home directior (./dozer): ",
×
144
            Box::new(move |(home_dir, config)| {
×
145
                if home_dir.is_empty() {
×
146
                    config.home_dir = "./dozer".to_string();
×
147
                } else {
×
148
                    config.home_dir = home_dir;
×
149
                }
×
150
                Ok(())
×
151
            }),
×
152
        ),
×
153
        (
×
154
            "question: Connection Type - one of: [P]ostgres, [E]thereum, [S]nowflake (Postgres): ",
×
155
            Box::new(move |(connection, config)| {
×
156
                let connections_available = vec!["Postgres", "Ethereum", "Snowflake"];
×
157
                if connections_available.contains(&connection.as_str()) {
×
158
                    let sample_connection = sample_connection(&connection);
×
159
                    config.connections.push(sample_connection);
×
160
                } else {
×
161
                    let sample_connection = sample_connection("Postgres");
×
162
                    config.connections.push(sample_connection);
×
163
                }
×
164
                Ok(())
×
165
            }),
×
166
        ),
×
167
        (
×
168
            "question: Config path (dozer-config.yaml): ",
×
169
            Box::new(move |(yaml_path, config)| {
×
170
                let mut yaml_path = yaml_path.trim();
×
171
                if yaml_path.is_empty() {
×
172
                    yaml_path = "dozer-config.yaml";
×
173
                }
×
174
                let f = std::fs::OpenOptions::new()
×
175
                    .create(true)
×
176
                    .write(true)
×
177
                    .open(yaml_path)
×
178
                    .map_err(|e| {
×
179
                        OrchestrationError::CliError(CliError::InternalError(Box::new(e)))
×
180
                    })?;
×
181
                serde_yaml::to_writer(f, &config)
×
182
                    .map_err(OrchestrationError::FailedToWriteConfigYaml)?;
×
183
                info!("\nGenerating configuration at: {}\n• More details about our config: https://getdozer.io/docs/reference/configuration/introduction\n• Connector & Sources: https://getdozer.io/docs/reference/configuration/connectors\n• Endpoints: https://getdozer.io/docs/reference/configuration/endpoints/",
×
184
                   yaml_path.to_owned());
×
185
                Ok(())
×
186
            }),
×
187
        ),
×
188
    ];
×
189
    let result = questions.iter().try_for_each(|(question, func)| {
×
190
        let readline = rl.readline(question);
×
191
        match readline {
×
192
            Ok(input) => func((input, &mut default_config)),
×
193
            Err(err) => Err(OrchestrationError::CliError(CliError::ReadlineError(err))),
×
194
        }
195
    });
×
196
    if let Err(e) = result {
×
197
        return match e {
×
198
            OrchestrationError::CliError(CliError::ReadlineError(ReadlineError::Interrupted)) => {
199
                info!("Exiting..");
×
200
                Ok(())
×
201
            }
202
            OrchestrationError::CliError(CliError::ReadlineError(ReadlineError::Eof)) => {
203
                info!("CTRL-D - exiting...");
×
204
                Ok(())
×
205
            }
206
            _ => Err(e),
×
207
        };
208
    };
×
209
    result
×
210
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc