mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-09-30 03:01:21 +02:00
Both `created_at` columns the restore dedupes on are
`server_default=func.now()`. SQLite fills those from `CURRENT_TIMESTAMP`,
which has second precision and stores `'2026-08-02 11:28:41'`, while
SQLAlchemy binds a Python datetime as `'2026-08-02 11:28:41.000000'`.
SQLite compares the two as strings, so `Model.created_at == created_at`
never matched a row the application itself created — not even when handed
that row's own value straight back out of the ORM.
Every dedupe keyed on it therefore missed, on the ordinary case rather
than an edge one:
* `_find_spool`'s composite fallback duplicated every tag-less spool on
each restore, and `overwrite_existing=True` never reached the original;
* the usage-history dedupe re-inserted the user's entire consumption
history on each restore.
Rows the restore itself had inserted did match, because those carry an
explicit bind in the same microsecond format — which is why the existing
repeat-restore tests passed throughout.
Fixed by filtering the candidates in SQL and comparing `created_at` in
Python, which sidesteps the bind format and behaves identically on
PostgreSQL, where the column keeps microseconds and the SQL comparison
happened to work. `_parse_dt` now also normalises an offset-bearing value
to naive UTC, matching what the naive columns actually hold; the collector
never writes one, so that guards hand-edited and foreign backups.
Seven tests, six of which fail without the fix. They seed the "existing"
row the way the application does — no explicit `created_at` — which is
what the existing coverage was missing.