fix(addons): dedup existing Ring devices before the unique index (R15)
Codex R15: on an upgrade where the pre-index race already produced duplicate config.ring_id rows, CREATE UNIQUE INDEX would abort the migration. Now the migration first collapses duplicates (keep the earliest id per ring_id; the rest cascade-delete their entities/state) using portable subquery SQL that runs on Postgres (prod) and SQLite (tests) alike. Verified: 3 duplicates → 1 on Postgres, index then created; suite 43 green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>feat/phase-1-bootstrap
parent
8086a9647b
commit
ca98e21c18
|
|
@ -7,6 +7,23 @@ return new class extends Migration
|
||||||
{
|
{
|
||||||
public function up(): void
|
public function up(): void
|
||||||
{
|
{
|
||||||
|
// Reconcile any duplicates the pre-index race may already have created, otherwise the
|
||||||
|
// CREATE UNIQUE INDEX below would abort on existing data. Keep the earliest row per
|
||||||
|
// ring_id; the rest cascade-delete their entities/state (both FKs cascadeOnDelete).
|
||||||
|
// Portable subquery form (works on Postgres in prod and SQLite in tests).
|
||||||
|
DB::statement(<<<'SQL'
|
||||||
|
DELETE FROM devices
|
||||||
|
WHERE config->>'ring_id' IS NOT NULL
|
||||||
|
AND id NOT IN (
|
||||||
|
SELECT min_id FROM (
|
||||||
|
SELECT MIN(id) AS min_id
|
||||||
|
FROM devices
|
||||||
|
WHERE config->>'ring_id' IS NOT NULL
|
||||||
|
GROUP BY config->>'ring_id'
|
||||||
|
) keep
|
||||||
|
)
|
||||||
|
SQL);
|
||||||
|
|
||||||
// Concurrent first-sight Ring messages (retained info + motion on bridge startup) must not
|
// Concurrent first-sight Ring messages (retained info + motion on bridge startup) must not
|
||||||
// create two rows for one device. A partial unique index on the JSON ring_id lets the
|
// create two rows for one device. A partial unique index on the JSON ring_id lets the
|
||||||
// second concurrent insert fail so the ingest job can re-fetch the winner (race-safe).
|
// second concurrent insert fail so the ingest job can re-fetch the winner (race-safe).
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue