Make selectors serialisable

A smart collection stores its selector as JSON in collections.selector_json,
and cache rules carry one across a sync, so the predicate language has to
round-trip. Derive-only: no serde machinery leaks into the rest of core/.

FlagState gains Default = Unflagged, which is what an image is before anyone
has looked at it. Any other default would assert a judgement the
photographer never made.

Assisted-by: LLM
This commit is contained in:
2026-08-09 20:37:02 +02:00
parent 02b66ddfcf
commit b6a5c0f090
3 changed files with 22 additions and 8 deletions
+4
View File
@@ -7,3 +7,7 @@ license.workspace = true
[dependencies]
thiserror.workspace = true
# Selectors are stored as JSON in `collections.selector_json` and travel in
# sync'd cache rules, so the predicate language has to serialise. Derive-only:
# no serde machinery leaks into the rest of `core/`.
serde.workspace = true
+5 -3
View File
@@ -14,7 +14,8 @@ pub use selector::{ColourLabel, DateSelector, FlagState, Selector, Tier};
/// Identifies a granted library location — a directory on Linux, a persisted
/// document tree on Android.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
#[serde(transparent)]
pub struct RootId(pub u64);
/// Identifies an image within a catalog.
@@ -26,7 +27,8 @@ pub struct ImageId(pub u64);
pub struct VersionId(pub u64);
/// Identifies a user-defined collection.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
#[serde(transparent)]
pub struct CollectionId(pub u64);
/// Identifies a folder within a root.
@@ -244,7 +246,7 @@ impl FormatFilter {
///
/// Surfaced in the UI so a user always knows what they have — the failure
/// Lightroom makes by showing an original's filename beside a 2560px proxy.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
pub enum Availability {
/// Catalogued, nothing cached.
MetadataOnly,
+13 -5
View File
@@ -20,7 +20,7 @@ use crate::{Availability, CollectionId, RootId};
/// Compiles to indexed SQL in `dr-catalog`; evaluated against catalog state
/// for cache rules. Deliberately data — no closures, so it serialises into a
/// saved collection or a sync'd cache rule.
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum Selector {
/// Everything. The empty filter, and the implicit default cache rule.
All,
@@ -103,7 +103,7 @@ impl Selector {
}
/// A date constraint, absolute or moving.
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum DateSelector {
/// UTC seconds, half-open: `from <= t < to`.
Between { from: i64, to: i64 },
@@ -115,7 +115,7 @@ pub enum DateSelector {
}
/// Colour labels, matching the conventional set.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize)]
pub enum ColourLabel {
Red,
Yellow,
@@ -125,9 +125,17 @@ pub enum ColourLabel {
}
/// The pick/reject axis, independent of star rating.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
///
/// `Unflagged` is the [`Default`] because it is what an image *is* before
/// anyone has looked at it — an unjudged frame, not a rejected one. Any other
/// default would silently assert a judgement the photographer never made.
#[derive(
Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash,
serde::Serialize, serde::Deserialize,
)]
pub enum FlagState {
/// Not yet judged. What "filter to unjudged" selects (FR-CULL-4).
#[default]
Unflagged,
Pick,
Reject,
@@ -136,7 +144,7 @@ pub enum FlagState {
/// How much of an image a cache rule asks to keep locally.
///
/// Ordered so the most generous matching rule wins (ARCH §9.3).
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize)]
pub enum Tier {
/// Catalog rows and sidecars only. Never evicted — authoritative and tiny.
Metadata,