This commit is contained in:
thePR0M3TH3AN
2025-05-15 14:00:44 -04:00
parent 432775e680
commit 977f36da61
4 changed files with 20 additions and 24 deletions

View File

@@ -1,3 +1,4 @@
-- src/db/migrations/0002_update_fts_and_triggers.sql
PRAGMA foreign_keys = ON; PRAGMA foreign_keys = ON;
PRAGMA journal_mode = WAL; -- Use WAL for better concurrency PRAGMA journal_mode = WAL; -- Use WAL for better concurrency

View File

@@ -31,7 +31,7 @@ pub fn open<P: AsRef<Path>>(db_path: P) -> Result<Connection> {
conn.pragma_update(None, "journal_mode", "WAL")?; conn.pragma_update(None, "journal_mode", "WAL")?;
conn.pragma_update(None, "foreign_keys", "ON")?; conn.pragma_update(None, "foreign_keys", "ON")?;
// Apply migrations // Apply migrations (drops & recreates all FTS triggers)
apply_migrations(&mut conn)?; apply_migrations(&mut conn)?;
Ok(conn) Ok(conn)
@@ -40,6 +40,7 @@ pub fn open<P: AsRef<Path>>(db_path: P) -> Result<Connection> {
/* ─── migration runner ──────────────────────────────────────────────── */ /* ─── migration runner ──────────────────────────────────────────────── */
fn apply_migrations(conn: &mut Connection) -> Result<()> { fn apply_migrations(conn: &mut Connection) -> Result<()> {
// Ensure schema_version table
conn.execute_batch( conn.execute_batch(
"CREATE TABLE IF NOT EXISTS schema_version ( "CREATE TABLE IF NOT EXISTS schema_version (
version INTEGER PRIMARY KEY, 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 _ = conn.execute("ALTER TABLE schema_version ADD COLUMN applied_on TEXT", []);
let tx = conn.transaction()?; let tx = conn.transaction()?;
for (fname, sql) in MIGRATIONS { for (fname, sql) in MIGRATIONS {
let version: i64 = fname let version: i64 = fname
.split('_') .split('_')
@@ -67,25 +69,25 @@ fn apply_migrations(conn: &mut Connection) -> Result<()> {
.optional()?; .optional()?;
if already.is_some() { if already.is_some() {
debug!("migration {fname} already applied"); debug!("migration {} already applied", fname);
continue; continue;
} }
info!("applying migration {fname}"); info!("applying migration {}", fname);
// For debugging:
println!( println!(
"\nSQL SCRIPT FOR MIGRATION: {}\nBEGIN SQL >>>\n{}\n<<< END SQL\n", "\nSQL SCRIPT FOR MIGRATION: {}\nBEGIN SQL >>>\n{}\n<<< END SQL\n",
fname, sql fname, sql
); );
tx.execute_batch(sql) tx.execute_batch(sql)
.with_context(|| format!("could not apply migration {fname}"))?; .with_context(|| format!("could not apply migration {}", fname))?;
tx.execute( tx.execute(
"INSERT INTO schema_version (version, applied_on) VALUES (?1, ?2)", "INSERT INTO schema_version (version, applied_on) VALUES (?1, ?2)",
params![version, Local::now().to_rfc3339()], params![version, Local::now().to_rfc3339()],
)?; )?;
} }
tx.commit()?; tx.commit()?;
Ok(()) Ok(())
} }

View File

@@ -21,6 +21,7 @@ fn main() -> Result<()> {
// Parse CLI and bootstrap logging // Parse CLI and bootstrap logging
let args = Cli::parse(); let args = Cli::parse();
if args.verbose { if args.verbose {
// switch on debuglevel logs
env::set_var("RUST_LOG", "debug"); env::set_var("RUST_LOG", "debug");
} }
logging::init(); logging::init();
@@ -44,10 +45,13 @@ fn main() -> Result<()> {
} }
Commands::Scan { paths } => { Commands::Scan { paths } => {
if paths.is_empty() { // if none given, default to current dir
anyhow::bail!("At least one directory must be supplied to `scan`"); let scan_paths = if paths.is_empty() {
} vec![env::current_dir()?]
for p in paths { } else {
paths
};
for p in scan_paths {
scan::scan_directory(&mut conn, &p)?; 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)")?; conn.prepare("INSERT OR IGNORE INTO file_tags(file_id, tag_id) VALUES (?1, ?2)")?;
let mut count = 0; let mut count = 0;
for entry in WalkDir::new(&root) for entry in WalkDir::new(&root).into_iter().filter_map(Result::ok).filter(|e| e.file_type().is_file()) {
.into_iter()
.filter_map(Result::ok)
.filter(|e| e.file_type().is_file())
{
let path_str = entry.path().to_string_lossy(); let path_str = entry.path().to_string_lossy();
debug!("testing path: {}", path_str); debug!("testing path: {}", path_str);
if !pat.matches(&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 stmt_file = conn.prepare("SELECT id FROM files WHERE path = ?1")?;
let mut count = 0; let mut count = 0;
for entry in WalkDir::new(&root) for entry in WalkDir::new(&root).into_iter().filter_map(Result::ok).filter(|e| e.file_type().is_file()) {
.into_iter()
.filter_map(Result::ok)
.filter(|e| e.file_type().is_file())
{
let path_str = entry.path().to_string_lossy(); let path_str = entry.path().to_string_lossy();
debug!("testing attr path: {}", path_str); debug!("testing attr path: {}", path_str);
if !pat.matches(&path_str) { if !pat.matches(&path_str) {
@@ -237,9 +233,7 @@ fn run_search(conn: &rusqlite::Connection, raw_query: &str, exec: Option<String>
.collect(); .collect();
if let Some(cmd_tpl) = exec { if let Some(cmd_tpl) = exec {
// Exec-on-hits logic
let mut ran_without_placeholder = false; let mut ran_without_placeholder = false;
// If no hits and no placeholder, run once
if hits.is_empty() && !cmd_tpl.contains("{}") { if hits.is_empty() && !cmd_tpl.contains("{}") {
if let Some(mut parts) = shlex::split(&cmd_tpl) { if let Some(mut parts) = shlex::split(&cmd_tpl) {
if !parts.is_empty() { if !parts.is_empty() {
@@ -252,7 +246,6 @@ fn run_search(conn: &rusqlite::Connection, raw_query: &str, exec: Option<String>
} }
ran_without_placeholder = true; ran_without_placeholder = true;
} }
// Otherwise, run per hit
if !ran_without_placeholder { if !ran_without_placeholder {
for path in hits { for path in hits {
let quoted = shlex::try_quote(&path).unwrap_or(path.clone().into()); let quoted = shlex::try_quote(&path).unwrap_or(path.clone().into());

Binary file not shown.