mirror of
https://github.com/PR0M3TH3AN/Marlin.git
synced 2025-09-08 07:08:44 +00:00
Add path normalization helper and apply
This commit is contained in:
@@ -18,6 +18,8 @@ use rusqlite::{
|
||||
use std::result::Result as StdResult;
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
use crate::utils::to_db_path;
|
||||
|
||||
/* ─── schema version ───────────────────────────────────────────────── */
|
||||
|
||||
/// Current library schema version.
|
||||
@@ -394,9 +396,13 @@ pub fn take_dirty(conn: &Connection) -> Result<Vec<i64>> {
|
||||
/* ─── rename helpers ────────────────────────────────────────────── */
|
||||
|
||||
pub fn update_file_path(conn: &Connection, old_path: &str, new_path: &str) -> Result<()> {
|
||||
let file_id: i64 = conn.query_row("SELECT id FROM files WHERE path = ?1", [old_path], |r| {
|
||||
r.get(0)
|
||||
})?;
|
||||
let old_path = to_db_path(old_path);
|
||||
let new_path = to_db_path(new_path);
|
||||
|
||||
let file_id: i64 =
|
||||
conn.query_row("SELECT id FROM files WHERE path = ?1", [&old_path], |r| {
|
||||
r.get(0)
|
||||
})?;
|
||||
conn.execute(
|
||||
"UPDATE files SET path = ?1 WHERE id = ?2",
|
||||
params![new_path, file_id],
|
||||
@@ -406,6 +412,8 @@ pub fn update_file_path(conn: &Connection, old_path: &str, new_path: &str) -> Re
|
||||
}
|
||||
|
||||
pub fn rename_directory(conn: &mut Connection, old_dir: &str, new_dir: &str) -> Result<()> {
|
||||
let old_dir = to_db_path(old_dir);
|
||||
let new_dir = to_db_path(new_dir);
|
||||
let like_pattern = format!("{}/%", old_dir.trim_end_matches('/'));
|
||||
let ids = {
|
||||
let mut stmt = conn.prepare("SELECT id FROM files WHERE path LIKE ?1")?;
|
||||
|
@@ -1,6 +1,7 @@
|
||||
// libmarlin/src/db_tests.rs
|
||||
|
||||
use super::db;
|
||||
use crate::utils::to_db_path;
|
||||
use rusqlite::Connection;
|
||||
use tempfile::tempdir;
|
||||
|
||||
@@ -283,7 +284,7 @@ fn tables_exist_and_fts_triggers() {
|
||||
.unwrap()
|
||||
.collect::<std::result::Result<Vec<_>, _>>()
|
||||
.unwrap();
|
||||
assert!(hits_tag.contains(&file_path.to_string_lossy().into_owned()));
|
||||
assert!(hits_tag.contains(&to_db_path(&file_path)));
|
||||
|
||||
let hits_attr: Vec<String> = marlin
|
||||
.conn()
|
||||
@@ -293,5 +294,5 @@ fn tables_exist_and_fts_triggers() {
|
||||
.unwrap()
|
||||
.collect::<std::result::Result<Vec<_>, _>>()
|
||||
.unwrap();
|
||||
assert!(hits_attr.contains(&file_path.to_string_lossy().into_owned()));
|
||||
assert!(hits_attr.contains(&to_db_path(&file_path)));
|
||||
}
|
||||
|
@@ -3,6 +3,8 @@
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::utils::to_db_path;
|
||||
|
||||
use anyhow::Result;
|
||||
use rusqlite::{params, Connection};
|
||||
use tracing::{debug, info};
|
||||
@@ -51,7 +53,7 @@ pub fn scan_directory(conn: &mut Connection, root: &Path) -> Result<usize> {
|
||||
.as_secs() as i64;
|
||||
|
||||
// Execute the upsert
|
||||
let path_str = path.to_string_lossy();
|
||||
let path_str = to_db_path(path);
|
||||
stmt.execute(params![path_str, size, mtime])?;
|
||||
count += 1;
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
//! Misc shared helpers.
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// Determine a filesystem root to limit recursive walking on glob scans.
|
||||
///
|
||||
@@ -44,3 +44,19 @@ pub fn determine_scan_root(pattern: &str) -> PathBuf {
|
||||
root
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a filesystem path to a normalized database path.
|
||||
///
|
||||
/// On Windows this replaces backslashes with forward slashes so that paths
|
||||
/// stored in the database are consistent across platforms.
|
||||
pub fn to_db_path<P: AsRef<Path>>(p: P) -> String {
|
||||
let s = p.as_ref().to_string_lossy();
|
||||
#[cfg(windows)]
|
||||
{
|
||||
s.replace('\\', "/")
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
s.into_owned()
|
||||
}
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@
|
||||
//! watcher can be paused, resumed and shut down cleanly.
|
||||
|
||||
use crate::db::{self, Database};
|
||||
use crate::utils::to_db_path;
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use crossbeam_channel::{bounded, Receiver};
|
||||
use notify::{
|
||||
@@ -463,8 +464,8 @@ impl FileWatcher {
|
||||
// update DB for renames
|
||||
if let EventKind::Modify(ModifyKind::Name(_)) = ev.kind {
|
||||
if let (Some(old_p), Some(new_p)) = (&ev.old_path, &ev.new_path) {
|
||||
let old_s = old_p.to_string_lossy();
|
||||
let new_s = new_p.to_string_lossy();
|
||||
let old_s = to_db_path(old_p);
|
||||
let new_s = to_db_path(new_p);
|
||||
let res =
|
||||
handle_db_update(db_mutex, &old_s, &new_s, new_p.is_dir());
|
||||
if let Err(e) = res {
|
||||
|
@@ -6,6 +6,7 @@ mod tests {
|
||||
use crate::backup::BackupManager;
|
||||
// These are still from the watcher module
|
||||
use crate::db::open as open_marlin_db;
|
||||
use crate::utils::to_db_path;
|
||||
use crate::watcher::{FileWatcher, WatcherConfig, WatcherState}; // Use your project's DB open function
|
||||
use crate::Marlin;
|
||||
|
||||
@@ -29,7 +30,7 @@ mod tests {
|
||||
.conn()
|
||||
.query_row(
|
||||
"SELECT COUNT(*) FROM files WHERE path = ?1",
|
||||
[path.to_string_lossy()],
|
||||
[to_db_path(path)],
|
||||
|r| r.get(0),
|
||||
)
|
||||
.unwrap();
|
||||
@@ -211,7 +212,7 @@ mod tests {
|
||||
.conn()
|
||||
.query_row(
|
||||
"SELECT COUNT(*) FROM files WHERE path = ?1",
|
||||
[new_file.to_string_lossy()],
|
||||
[to_db_path(&new_file)],
|
||||
|r| r.get(0),
|
||||
)
|
||||
.unwrap();
|
||||
@@ -262,7 +263,7 @@ mod tests {
|
||||
.conn()
|
||||
.query_row(
|
||||
"SELECT COUNT(*) FROM files WHERE path = ?1",
|
||||
[p.to_string_lossy()],
|
||||
[to_db_path(&p)],
|
||||
|r| r.get(0),
|
||||
)
|
||||
.unwrap();
|
||||
|
Reference in New Issue
Block a user