1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
//! `sqlx` row-mapping backend — domain ⇄ SQL row conversions for
//! Postgres, MySQL, and SQLite.
//!
//! Each backend is its own optional feature
//! (`sqlx-postgres` / `sqlx-mysql` / `sqlx-sqlite`); enable only what
//! you ship with. Off by default.
//!
//! ## Layout
//!
//! - [`error`](crate::sqlx::error) — backend-specific [`SqlxError`](crate::sqlx::error::SqlxError) (`Debug + Clone + PartialEq +
//! Eq + IsVariant + non_exhaustive`, implements [`core::error::Error`]).
//! - [`dto`](crate::sqlx::dto) — shared row-mapping helpers for the 16-byte UUID /
//! 32-byte checksum / ms-timestamp conversions. Nested value-objects
//! are no longer stored as JSON DTOs — each scalar VO is flattened
//! into its own real columns and the one many-to-many collection
//! rides in a join table.
//! - [`postgres`](crate::sqlx::postgres) / [`mysql`](crate::sqlx::mysql) / [`sqlite`](crate::sqlx::sqlite) — per-backend modules. Each
//! ships row structs with `sqlx::FromRow` derives, `TryFrom` impls
//! going to/from the domain aggregates, the canonical `schema.sql`
//! DDL, and a minimal `migrations/0001_init.sql` mirror.
//!
//! ## Mapping conventions
//!
//! - **Identity columns** (`id` / `parent` / FKs): `uuid` (Postgres
//! native), `BINARY(16)` (MySQL), `BLOB` 16 bytes (SQLite). Domain
//! `Uuid7` is `pub use crate::sqlx::dto::{uuid7_to_uuid, uuid_to_uuid7,
//! bytes_to_uuid7}` for symmetric conversion.
//! - **File checksum** (`FileChecksum`): `BYTEA` (Postgres),
//! `BINARY(32)` (MySQL), `BLOB(32)` (SQLite). Round-trip via
//! [`dto::bytes_to_checksum`](crate::sqlx::dto::bytes_to_checksum).
//! - **Nested value-objects** (capture `Device`, capture `GeoLocation`,
//! `ErrorInfo`): flattened into real, individually-indexable columns
//! (e.g. `Device` → `device_make` / `device_model`, `ErrorInfo` →
//! `*_error_code` / `*_error_message`). Presence is encoded by the
//! discriminating column's nullability — no JSON columns.
//! - **Collections** (`SceneAnnotation::user_tags`): a many-to-many
//! join table (`scene_annotation_user_tag`) with an `ordinal` column
//! preserving the in-aggregate order.
//! - **Domain enums** (`MediaKind`, `ScanStatus`, `SubtitleKind`,
//! `AudioContentKind`, the `*IndexStage` types): mapped to `SMALLINT`
//! (Postgres) / `TINYINT` (MySQL) / `INTEGER` (SQLite) via the enum
//! `as u32`/`from_u32` round-trip helpers added per backend.
//! - **Bitflags** (`MediaErrorFlags`, the `*IndexStatus` types): stored
//! as their underlying `u16`/`u32` `bits()` value in an integer
//! column.
//! - **Wall-clock** (`jiff::Timestamp`): `TIMESTAMPTZ` (Postgres) /
//! `DATETIME` (MySQL) / `TEXT` ISO-8601 (SQLite). Converted via
//! `jiff::Timestamp` ⇄ `chrono::DateTime<Utc>` at the boundary so
//! sqlx's native chrono support drives the encode/decode.
//!
//! ## Coverage (this revision)
//!
//! Fully mapped (round-trip tests + schema): `Media` (incl. the
//! published [`mediaframe::container::Format`] container slug and the
//! [`mediaframe::capture::Device`] / [`mediaframe::capture::GeoLocation`]
//! EXIF descriptors, flattened into real columns),
//! `WatchedLocation`, `Speaker`, `UserTag`, `SceneAnnotation` (with its
//! `scene_annotation_user_tag` join table).
//!
//! The track-level aggregates (`AudioTrack`, `VideoTrack`,
//! `SubtitleTrack`) and per-track analysis aggregates (`AudioSegment`,
//! `Scene`, `Keyframe`, `SubtitleCue`) carry deep nested
//! [`mediaframe`] descriptor VOs (codecs, `ChannelLayout`, `Loudness`,
//! `Fingerprint`, `PixelFormat`, `color::Info`, `Dimensions`, the frame
//! geometry enums, subtitle `Format` / `TrackOrigin`, …). Their
//! flattened-column row-struct surface is **tracked as a follow-up PR**
//! to keep this revision focused.
pub use SqlxError;