image_exif: add date_taken_source column

New nullable TEXT column tracks which step of the canonical-date
waterfall (kamadak-exif → exiftool → filename → fs_time) populated
`date_taken`. Lets a later per-tick drain re-resolve weak sources
(`fs_time`) once stronger ones become available, and gives the UI/debug
surface a way to answer "why does this photo show up under this date?".

Adds the column at all `InsertImageExif` construction sites with `None`
placeholders (the resolver wiring lands in a follow-up commit), and
extends the `update_exif` SET tuple so the column survives the GPS-write
re-read path. Partial index `idx_image_exif_date_backfill` is created
for the upcoming drain query.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Cameron Cordes
2026-05-06 15:57:49 -04:00
parent 5de9a322ac
commit 84326501a9
7 changed files with 45 additions and 0 deletions

View File

@@ -730,6 +730,7 @@ impl ExifDao for SqliteExifDao {
shutter_speed.eq(&exif_data.shutter_speed),
iso.eq(&exif_data.iso),
date_taken.eq(&exif_data.date_taken),
date_taken_source.eq(&exif_data.date_taken_source),
last_modified.eq(&exif_data.last_modified),
))
.execute(connection.deref_mut())
@@ -1819,6 +1820,7 @@ mod exif_dao_tests {
size_bytes: None,
phash_64: None,
dhash_64: None,
date_taken_source: None,
},
)
.expect("insert exif row");

View File

@@ -63,6 +63,12 @@ pub struct InsertImageExif {
pub phash_64: Option<i64>,
/// 64-bit dHash (gradient). NULL for videos and decode failures.
pub dhash_64: Option<i64>,
/// Which step of the canonical-date waterfall populated `date_taken`:
/// `"exif"` | `"exiftool"` | `"filename"` | `"fs_time"`. NULL when
/// `date_taken` is NULL (no source resolved it). The per-tick backfill
/// drain re-resolves rows whose source is `"fs_time"` once exiftool
/// has had a chance to run.
pub date_taken_source: Option<String>,
}
// Field order matches the post-migration column order in `image_exif`.
@@ -98,6 +104,8 @@ pub struct ImageExif {
pub duplicate_of_hash: Option<String>,
/// Unix seconds at which the resolve was committed.
pub duplicate_decided_at: Option<i64>,
/// Which step of the canonical-date waterfall populated `date_taken`.
pub date_taken_source: Option<String>,
}
#[derive(Insertable)]

View File

@@ -125,6 +125,7 @@ diesel::table! {
dhash_64 -> Nullable<BigInt>,
duplicate_of_hash -> Nullable<Text>,
duplicate_decided_at -> Nullable<BigInt>,
date_taken_source -> Nullable<Text>,
}
}