drizzle_cli/commands/
check.rs1use std::path::Path;
4
5use crate::config::{Config, Credentials, PostgresCreds};
6use crate::error::CliError;
7use crate::output;
8
9pub fn run(
10 config: &Config,
11 db_name: Option<&str>,
12 _dialect_override: Option<&str>,
13 out_override: Option<&Path>,
14) -> Result<(), CliError> {
15 let db = config.database(db_name)?;
16
17 let effective_out = out_override
19 .map(Path::to_path_buf)
20 .unwrap_or(db.out.clone());
21
22 println!("{}", output::heading("Checking configuration..."));
23 println!();
24
25 if !config.is_single_database() {
26 let name = db_name.unwrap_or("(default)");
27 println!(" {}: {}", output::label("Database"), name);
28 }
29
30 let mut warnings = Vec::new();
31 let mut has_errors = false;
32
33 println!(" {}: {}", output::label("Dialect"), db.dialect);
35 if let Some(driver) = db.driver {
36 println!(" {}: {}", output::label("Driver"), driver);
37 }
38 println!(" {}: {}", output::label("Schema"), db.schema_display());
39 println!(" {}: {}", output::label("Output"), effective_out.display());
40
41 println!();
43 print!(" {} Schema files... ", output::label("Checking"));
44 match db.schema_files() {
45 Ok(files) => {
46 println!("{}", output::status_ok());
47 for f in &files {
48 println!(" {}", f.display());
49 }
50 }
51 Err(e) => {
52 println!("{}", output::status_error());
53 println!(" {e}");
54 has_errors = true;
55 }
56 }
57
58 println!();
60 print!(" {} Migrations... ", output::label("Checking"));
61 let dir = &effective_out;
62 let journal_path = effective_out.join("meta").join("_journal.json");
63 if dir.exists() {
64 println!("{}", output::status_ok());
65 if journal_path.exists() {
66 println!(" Journal: {}", output::success("found"));
67 } else {
68 println!(
69 " Journal: {} (run generate first)",
70 output::warning("missing")
71 );
72 warnings.push("No migration journal");
73 }
74 } else {
75 println!("{}", output::status_warning("NOT CREATED"));
76 warnings.push("Migrations directory doesn't exist yet");
77 }
78
79 println!();
81 print!(" {} Credentials... ", output::label("Checking"));
82 match db.credentials() {
83 Ok(Some(creds)) => {
84 println!("{}", output::status_ok());
85 print_credentials(&creds);
86 }
87 Ok(None) => {
88 println!("{}", output::status_warning("NOT SET"));
89 warnings.push("No credentials (needed for push/pull/migrate)");
90 }
91 Err(e) => {
92 println!("{}", output::status_error());
93 println!(" {}", e);
94 has_errors = true;
95 }
96 }
97
98 println!();
100 if has_errors {
101 println!("{}", output::error("Configuration has errors."));
102 Err(CliError::Other("config check failed".into()))
103 } else if warnings.is_empty() {
104 println!("{}", output::success("Configuration OK."));
105 Ok(())
106 } else {
107 println!(
108 "{}",
109 output::warning(&format!("{} warning(s):", warnings.len()))
110 );
111 for w in warnings {
112 println!(" - {w}");
113 }
114 Ok(())
115 }
116}
117
118fn print_credentials(creds: &Credentials) {
119 match creds {
120 Credentials::Sqlite { path } => {
121 println!(" {}: {path}", output::label("SQLite"));
122 }
123 Credentials::Turso { url, auth_token } => {
124 println!(" {}: {}", output::label("Turso"), mask_url(url));
125 if auth_token.is_some() {
126 println!(" Token: ****");
127 }
128 }
129 Credentials::Postgres(pg) => match pg {
130 PostgresCreds::Url(url) => {
131 println!(" {}: {}", output::label("PostgreSQL"), mask_url(url))
132 }
133 PostgresCreds::Host {
134 host,
135 port,
136 database,
137 user,
138 ..
139 } => {
140 println!(
141 " {}: {host}:{port}/{database}",
142 output::label("PostgreSQL")
143 );
144 if let Some(u) = user {
145 println!(" User: {u}");
146 }
147 }
148 },
149 }
150}
151
152fn mask_url(url: &str) -> String {
153 if let Some(at) = url.find('@')
154 && let Some(colon) = url[..at].rfind(':')
155 {
156 let scheme_end = url.find("://").map(|p| p + 3).unwrap_or(0);
157 if colon > scheme_end {
158 return format!("{}****{}", &url[..colon + 1], &url[at..]);
159 }
160 }
161 url.to_string()
162}