drizzle_cli/commands/
introspect.rs

1//! Introspect command implementation
2//!
3//! Introspects an existing database and generates a snapshot/schema.
4
5use std::path::Path;
6
7use crate::config::{DrizzleConfig, IntrospectCasing};
8use crate::error::CliError;
9use crate::output;
10
11/// Run the introspect command
12pub fn run(
13    config: &DrizzleConfig,
14    db_name: Option<&str>,
15    init_metadata: bool,
16    casing: Option<IntrospectCasing>,
17    out_override: Option<&Path>,
18    breakpoints_override: Option<bool>,
19) -> Result<(), CliError> {
20    let db = config.database(db_name)?;
21
22    // CLI flags override config
23    let _effective_casing = casing.unwrap_or_else(|| db.effective_introspect_casing());
24    let effective_out = out_override.unwrap_or(db.migrations_dir());
25    let _effective_breakpoints = breakpoints_override.unwrap_or(db.breakpoints);
26
27    println!("{}", output::heading("Introspecting database..."));
28    println!();
29
30    if !config.is_single_database() {
31        let name = db_name.unwrap_or("(default)");
32        println!("  {}: {}", output::label("Database"), name);
33    }
34
35    println!("  {}: {}", output::label("Dialect"), db.dialect.as_str());
36    if let Some(ref driver) = db.driver {
37        println!("  {}: {:?}", output::label("Driver"), driver);
38    }
39    println!("  {}: {}", output::label("Output"), effective_out.display());
40
41    if init_metadata {
42        println!("  {}: enabled", output::label("Init metadata"));
43    }
44    println!();
45
46    // Get credentials
47    let credentials = db.credentials()?;
48
49    let credentials = match credentials {
50        Some(c) => c,
51        None => {
52            println!("{}", output::warning("No database credentials configured."));
53            println!();
54            println!("Add credentials to your drizzle.config.toml:");
55            println!();
56            println!("  {}", output::muted("[dbCredentials]"));
57            match db.dialect.to_base() {
58                drizzle_types::Dialect::SQLite => {
59                    println!("  {}", output::muted("url = \"./dev.db\""));
60                }
61                drizzle_types::Dialect::PostgreSQL => {
62                    println!(
63                        "  {}",
64                        output::muted("url = \"postgres://user:pass@localhost:5432/db\"")
65                    );
66                }
67                drizzle_types::Dialect::MySQL => {
68                    // drizzle-cli doesn't currently support MySQL end-to-end, but the base
69                    // dialect type includes it, so keep the match exhaustive.
70                    println!(
71                        "  {}",
72                        output::muted("url = \"mysql://user:pass@localhost:3306/db\"")
73                    );
74                }
75            }
76            println!();
77            println!("Or use an environment variable:");
78            println!();
79            println!("  {}", output::muted("[dbCredentials]"));
80            println!("  {}", output::muted("url = { env = \"DATABASE_URL\" }"));
81            return Ok(());
82        }
83    };
84
85    // Run introspection
86    let result = crate::db::run_introspection(
87        &credentials,
88        db.dialect,
89        effective_out,
90        init_metadata,
91        db.migrations_table(),
92        db.migrations_schema(),
93    )?;
94
95    println!();
96    println!(
97        "  {} {} table(s), {} index(es)",
98        output::success("Found"),
99        result.table_count,
100        result.index_count
101    );
102
103    if result.view_count > 0 {
104        println!(
105            "  {} {} view(s)",
106            output::success("Found"),
107            result.view_count
108        );
109    }
110
111    println!();
112    println!(
113        "{} Snapshot saved to {}",
114        output::success("Done!"),
115        result.snapshot_path.display()
116    );
117
118    if init_metadata {
119        println!();
120        println!(
121            "  {} Migration metadata initialized in database.",
122            output::label("Note:")
123        );
124        println!("  The current database state is now the baseline for future migrations.");
125    }
126
127    Ok(())
128}