fix: address all 6 P2 review issues from PR #8 round 4

- BackgroundTasks: per-task Retry now dispatches to the correct backend —
  retryFailedEmbeddings for embedding failures, queueTaggingJobs for tagging
  failures, or both; previously always called embedding retry only

- commands: tag-cloud cache key now hashes both image IDs and embedding bytes
  (xxh3) so re-embedding a file after reindex correctly invalidates the cache;
  removed now-dead fnv_hash_ids helper

- db: update_folder_path uses SUBSTR instead of replace() to rewrite only the
  leading path prefix, preventing corruption when the old folder name also
  appears in a subdirectory name

- db: add_user_tag promotes an existing AI-owned tag to user-owned on conflict
  instead of DO NOTHING, preventing the tagger from deleting a manually added
  tag that coincides with an AI tag

- db/commands: add clear_duplicate_scan_cache / invalidate_duplicate_scan_cache
  so deletion removes the stale persisted cache entry; without this a restart
  would reload groups containing deleted images

- store: setSimilarScope re-runs loadSimilarByRegion (with saved crop) when the
  active collection is Region Search Results, instead of silently switching to
  whole-image similarity and discarding the crop
This commit is contained in:
2026-06-07 09:45:57 +01:00
parent 4e5923ba84
commit 183cdff6b1
5 changed files with 61 additions and 21 deletions
+17 -3
View File
@@ -1371,9 +1371,10 @@ pub fn update_folder_path(conn: &Connection, folder_id: i64, old_path: &str, new
)?;
// Rewrite image paths so the indexer can match them by path and skip
// re-generating thumbnails and embeddings for unchanged files.
// SQLite's replace() does a literal prefix substitution on each path.
// Use SUBSTR to replace only the leading prefix; SQLite's replace()
// would corrupt paths where the old folder name also appears deeper in the tree.
conn.execute(
"UPDATE images SET path = replace(path, ?1, ?2) WHERE folder_id = ?3",
"UPDATE images SET path = ?2 || SUBSTR(path, LENGTH(?1) + 1) WHERE folder_id = ?3",
params![old_path, new_path, folder_id],
)?;
Ok(())
@@ -1887,7 +1888,11 @@ pub fn add_user_tag(conn: &Connection, image_id: i64, tag: &str) -> Result<Image
conn.execute(
"INSERT INTO image_tags (image_id, tag, source, ai_model, confidence, created_at)
VALUES (?1, ?2, 'user', NULL, NULL, datetime('now'))
ON CONFLICT(image_id, tag) DO NOTHING",
ON CONFLICT(image_id, tag) DO UPDATE SET
source = 'user',
ai_model = NULL,
confidence = NULL
WHERE source = 'ai'",
params![image_id, tag],
)?;
let row = conn.query_row(
@@ -2130,6 +2135,15 @@ pub fn get_duplicate_scan_cache(
}
}
/// Deletes the duplicate scan cache for the given scope.
pub fn clear_duplicate_scan_cache(conn: &Connection, folder_scope: &str) -> Result<()> {
conn.execute(
"DELETE FROM duplicate_scan_cache WHERE folder_scope = ?1",
params![folder_scope],
)?;
Ok(())
}
/// Upserts the duplicate scan cache for the given scope.
pub fn set_duplicate_scan_cache(
conn: &Connection,