Merge PR #1845: Match f:/aperture:/focal: search tokens at f32 precision

This commit is contained in:
Brandon Thomas committed 2026-10-18 09:18:19 -04:00
commit d6a9a2e8f9
2 files changed
+30 -2

No files matched your search

+9 -2
View File
@@ -157,13 +157,20 @@ fn token_matches(p: &Photo, tok: &str) -> bool {
Some((_, v)) => (x - v).abs() < 1e-9,
None => false,
};
// Fields stored as `f32` compare at f32 precision: 2.8f32 widened to f64 is not 2.8.
let cmp32 = |x: f32, s: &str| match num(s) {
Some(('>', v)) => x > v as f32,
Some(('<', v)) => x < v as f32,
Some((_, v)) => x == v as f32,
None => false,
};
return match field {
"rating" | "stars" => cmp(p.rating as f64, val),
"flag" => Flag::parse(val) == Some(p.flag),
"label" | "color" => p.label.is_some_and(|l| format!("{l:?}").eq_ignore_ascii_case(val)),
"iso" => p.meta.iso.is_some_and(|i| cmp(i as f64, val)),
"f" | "aperture" => p.meta.aperture.is_some_and(|a| cmp(a as f64, val)),
"focal" => p.meta.focal_mm.is_some_and(|a| cmp(a as f64, val)),
"f" | "aperture" => p.meta.aperture.is_some_and(|a| cmp32(a, val)),
"focal" => p.meta.focal_mm.is_some_and(|a| cmp32(a, val)),
"camera" => p.meta.camera.to_lowercase().contains(val),
"lens" => p.meta.lens.to_lowercase().contains(val),
"keyword" | "kw" => p.meta.keywords.iter().any(|k| crate::keywords::is_under(k, val)),
+21
View File
@@ -144,6 +144,27 @@ fn free_text_with_a_colon_searches_the_text_fields() {
assert_eq!(q("11:45"), Vec::<PhotoId>::new(), "an unknown field matching no text finds nothing");
}
/// `f:`/`aperture:` and `focal:` are stored as `f32`; a typed value that isn't exact in binary
/// (2.8, 5.6) must still match, and `<`/`>` must not count the photo's own value.
#[test]
fn search_tokens_match_f32_aperture_and_focal() {
let mut c = Catalog::new();
let a = photo(&mut c, "a.jpg", "2026-05-01T10:00:00");
let mut m = c.photo(a).unwrap().meta.clone();
m.aperture = Some(2.8);
m.focal_mm = Some(5.6);
c.apply(Op::SetMeta { id: a, meta: Box::new(m) }).unwrap();
let q = |t: &str| c.query(&Filter { text: t.into(), ..Default::default() }, &Sort::default());
assert_eq!(q("f:2.8"), vec![a], "f:2.8");
assert_eq!(q("aperture:=2.8"), vec![a], "aperture:=2.8");
assert_eq!(q("focal:5.6"), vec![a], "focal:5.6");
assert!(q("f:2.9").is_empty(), "f:2.9");
assert!(q("f:<2.8").is_empty(), "f:<2.8");
assert!(q("f:>2.8").is_empty(), "f:>2.8");
assert!(q("focal:<5.6").is_empty(), "focal:<5.6");
assert_eq!(q("f:>2.7"), vec![a], "f:>2.7");
}
/// A `captured` string that is not ASCII (the Lightroom importer copies `captureTime` into an
/// `AddPhoto` op verbatim, and a JSON snapshot is valid UTF-8 whatever it holds) must not be
/// sliced on a byte index in `date_groups`: grouping counts the well-formed dates and ignores