drizzle_cli/commands/
push.rs1use crate::config::{Casing, Config};
8use crate::error::CliError;
9use crate::output;
10use crate::snapshot::parse_result_to_snapshot;
11
12#[derive(Debug, Clone)]
13pub struct PushOptions {
14 pub cli_verbose: bool,
15 pub cli_strict: bool,
16 pub force: bool,
17 pub cli_explain: bool,
18 pub casing: Option<Casing>,
19 pub extensions_filters: Option<Vec<String>>,
20}
21
22pub fn run(config: &Config, db_name: Option<&str>, opts: PushOptions) -> Result<(), CliError> {
24 use drizzle_migrations::parser::SchemaParser;
25
26 let db = config.database(db_name)?;
27
28 let verbose = opts.cli_verbose || db.verbose;
30 let explain = opts.cli_explain;
31 let _effective_casing = opts.casing.unwrap_or_else(|| db.effective_casing());
32 let _extensions_filters = opts.extensions_filters;
35
36 if opts.cli_strict {
37 println!(
38 "{}",
39 output::warning("Deprecated: Do not use '--strict'. Use '--explain' instead.")
40 );
41 return Err(CliError::Other("strict flag is deprecated".into()));
42 }
43
44 if !config.is_single_database() {
45 let name = db_name.unwrap_or("(default)");
46 println!("{}: {}", output::label("Database"), name);
47 }
48
49 println!("{}", output::heading("Pushing schema to database..."));
50 println!();
51
52 let credentials = db.credentials()?;
54 let credentials = match credentials {
55 Some(c) => c,
56 None => {
57 println!("{}", output::warning("No database credentials configured."));
58 println!();
59 println!("Add credentials to your drizzle.config.toml:");
60 println!();
61 println!(" {}", output::muted("[dbCredentials]"));
62 match db.dialect.to_base() {
63 drizzle_types::Dialect::SQLite => {
64 println!(" {}", output::muted("url = \"./dev.db\""));
65 }
66 drizzle_types::Dialect::PostgreSQL => {
67 println!(
68 " {}",
69 output::muted("url = \"postgres://user:pass@localhost:5432/db\"")
70 );
71 }
72 drizzle_types::Dialect::MySQL => {
73 println!(
76 " {}",
77 output::muted("url = \"mysql://user:pass@localhost:3306/db\"")
78 );
79 }
80 }
81 println!();
82 println!("Or use an environment variable:");
83 println!();
84 println!(" {}", output::muted("[dbCredentials]"));
85 println!(" {}", output::muted("url = { env = \"DATABASE_URL\" }"));
86 return Ok(());
87 }
88 };
89
90 let schema_files = db.schema_files()?;
92 if schema_files.is_empty() {
93 return Err(CliError::NoSchemaFiles(db.schema_display()));
94 }
95
96 println!(
97 " {} {} schema file(s)",
98 output::label("Parsing"),
99 schema_files.len()
100 );
101
102 let mut combined_code = String::new();
103 for path in &schema_files {
104 let code = std::fs::read_to_string(path)
105 .map_err(|e| CliError::IoError(format!("Failed to read {}: {}", path.display(), e)))?;
106 combined_code.push_str(&code);
107 combined_code.push('\n');
108 }
109
110 let parse_result = SchemaParser::parse(&combined_code);
111
112 if parse_result.tables.is_empty() && parse_result.indexes.is_empty() {
113 println!(
114 "{}",
115 output::warning("No tables or indexes found in schema files.")
116 );
117 return Ok(());
118 }
119
120 println!(
121 " {} {} table(s), {} index(es)",
122 output::label("Found"),
123 parse_result.tables.len(),
124 parse_result.indexes.len()
125 );
126
127 let dialect = db.dialect.to_base();
129 let desired_snapshot = parse_result_to_snapshot(&parse_result, dialect);
130
131 let plan = crate::db::plan_push(&credentials, db.dialect, &desired_snapshot, db.breakpoints)?;
133
134 if !plan.warnings.is_empty() {
135 println!("{}", output::warning("Warnings:"));
136 for w in &plan.warnings {
137 println!(" {} {}", output::warning("-"), w);
138 }
139 println!();
140 }
141
142 if explain || verbose {
144 if plan.sql_statements.is_empty() {
145 println!("{}", output::success("No schema changes detected."));
146 return Ok(());
147 }
148
149 println!("{}", output::muted("--- Planned SQL ---"));
150 println!();
151 for stmt in &plan.sql_statements {
152 println!("{stmt}\n");
153 }
154 println!("{}", output::muted("--- End SQL ---"));
155 println!();
156 }
157
158 if explain {
160 return Ok(());
161 }
162
163 if plan.sql_statements.is_empty() {
164 println!("{}", output::success("No schema changes detected."));
165 return Ok(());
166 }
167
168 crate::db::apply_push(&credentials, db.dialect, &plan, opts.force)?;
170
171 println!("{}", output::success("Push complete!"));
172
173 Ok(())
174}