diff --git a/src/db/migrations/0002_update_fts_and_triggers.sql b/src/db/migrations/0002_update_fts_and_triggers.sql index 39695a7..0973731 100644 --- a/src/db/migrations/0002_update_fts_and_triggers.sql +++ b/src/db/migrations/0002_update_fts_and_triggers.sql @@ -1,3 +1,4 @@ +-- src/db/migrations/0002_update_fts_and_triggers.sql PRAGMA foreign_keys = ON; PRAGMA journal_mode = WAL; -- Use WAL for better concurrency diff --git a/src/db/mod.rs b/src/db/mod.rs index 42f617f..2e8286b 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -31,7 +31,7 @@ pub fn open>(db_path: P) -> Result { conn.pragma_update(None, "journal_mode", "WAL")?; conn.pragma_update(None, "foreign_keys", "ON")?; - // Apply migrations + // Apply migrations (drops & recreates all FTS triggers) apply_migrations(&mut conn)?; Ok(conn) @@ -40,6 +40,7 @@ pub fn open>(db_path: P) -> Result { /* ─── migration runner ──────────────────────────────────────────────── */ fn apply_migrations(conn: &mut Connection) -> Result<()> { + // Ensure schema_version table conn.execute_batch( "CREATE TABLE IF NOT EXISTS schema_version ( version INTEGER PRIMARY KEY, @@ -47,10 +48,11 @@ fn apply_migrations(conn: &mut Connection) -> Result<()> { );", )?; - // legacy patch (ignore if already exists) + // Legacy patch (ignore if exists) let _ = conn.execute("ALTER TABLE schema_version ADD COLUMN applied_on TEXT", []); let tx = conn.transaction()?; + for (fname, sql) in MIGRATIONS { let version: i64 = fname .split('_') @@ -67,25 +69,25 @@ fn apply_migrations(conn: &mut Connection) -> Result<()> { .optional()?; if already.is_some() { - debug!("migration {fname} already applied"); + debug!("migration {} already applied", fname); continue; } - info!("applying migration {fname}"); - // For debugging: + info!("applying migration {}", fname); println!( "\nSQL SCRIPT FOR MIGRATION: {}\nBEGIN SQL >>>\n{}\n<<< END SQL\n", fname, sql ); tx.execute_batch(sql) - .with_context(|| format!("could not apply migration {fname}"))?; + .with_context(|| format!("could not apply migration {}", fname))?; tx.execute( "INSERT INTO schema_version (version, applied_on) VALUES (?1, ?2)", params![version, Local::now().to_rfc3339()], )?; } + tx.commit()?; Ok(()) } diff --git a/src/main.rs b/src/main.rs index 13410ae..46fe75b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,6 +21,7 @@ fn main() -> Result<()> { // Parse CLI and bootstrap logging let args = Cli::parse(); if args.verbose { + // switch on debug‐level logs env::set_var("RUST_LOG", "debug"); } logging::init(); @@ -44,10 +45,13 @@ fn main() -> Result<()> { } Commands::Scan { paths } => { - if paths.is_empty() { - anyhow::bail!("At least one directory must be supplied to `scan`"); - } - for p in paths { + // if none given, default to current dir + let scan_paths = if paths.is_empty() { + vec![env::current_dir()?] + } else { + paths + }; + for p in scan_paths { scan::scan_directory(&mut conn, &p)?; } } @@ -101,11 +105,7 @@ fn apply_tag(conn: &rusqlite::Connection, pattern: &str, tag_path: &str) -> Resu conn.prepare("INSERT OR IGNORE INTO file_tags(file_id, tag_id) VALUES (?1, ?2)")?; let mut count = 0; - for entry in WalkDir::new(&root) - .into_iter() - .filter_map(Result::ok) - .filter(|e| e.file_type().is_file()) - { + for entry in WalkDir::new(&root).into_iter().filter_map(Result::ok).filter(|e| e.file_type().is_file()) { let path_str = entry.path().to_string_lossy(); debug!("testing path: {}", path_str); if !pat.matches(&path_str) { @@ -155,11 +155,7 @@ fn attr_set( let mut stmt_file = conn.prepare("SELECT id FROM files WHERE path = ?1")?; let mut count = 0; - for entry in WalkDir::new(&root) - .into_iter() - .filter_map(Result::ok) - .filter(|e| e.file_type().is_file()) - { + for entry in WalkDir::new(&root).into_iter().filter_map(Result::ok).filter(|e| e.file_type().is_file()) { let path_str = entry.path().to_string_lossy(); debug!("testing attr path: {}", path_str); if !pat.matches(&path_str) { @@ -237,9 +233,7 @@ fn run_search(conn: &rusqlite::Connection, raw_query: &str, exec: Option .collect(); if let Some(cmd_tpl) = exec { - // Exec-on-hits logic let mut ran_without_placeholder = false; - // If no hits and no placeholder, run once if hits.is_empty() && !cmd_tpl.contains("{}") { if let Some(mut parts) = shlex::split(&cmd_tpl) { if !parts.is_empty() { @@ -252,7 +246,6 @@ fn run_search(conn: &rusqlite::Connection, raw_query: &str, exec: Option } ran_without_placeholder = true; } - // Otherwise, run per hit if !ran_without_placeholder { for path in hits { let quoted = shlex::try_quote(&path).unwrap_or(path.clone().into()); @@ -291,7 +284,7 @@ fn escape_fts_query_term(term: &str) -> String { if term.contains(|c: char| c.is_whitespace() || "-:()\"".contains(c)) || ["AND","OR","NOT","NEAR"].contains(&term.to_uppercase().as_str()) { - format!("\"{}\"", term.replace('"', "\"\"")) + format!("\"{}\"", term.replace('"', "\"\"")) } else { term.to_string() } diff --git a/target/release/marlin b/target/release/marlin index ce9c145..2f4693c 100755 Binary files a/target/release/marlin and b/target/release/marlin differ