fix(live): translate IMEI↔UUID in snapshot + device-event-map joins
Build and Push processor / build (push) Successful in 58s
Build and Push processor / build (push) Successful in 58s
positions.device_id stores the IMEI (text); entry_devices.device_id is a
uuid FK to devices.id. snapshot.ts and device-event-map.ts joined the two
columns directly, causing:
- snapshot.ts: Postgres rejected with `operator does not exist: uuid =
text` (42883). The registry caught the error and returned an empty
snapshot, masking the failure.
- device-event-map.ts: cache keyed on entry_devices.device_id (uuid),
but broadcast.ts:141 looks up by position.device_id (imei). Cache
missed every record → no live frames fanned out, silently.
Both queries now hop through the devices table (devices.imei =
positions.device_id, devices.id = entry_devices.device_id). The
device-event-map cache aliases d.imei AS device_id so cache keys stay
IMEI strings — broadcast.ts is unchanged.
The integration-test fixture schema previously had entry_devices.device_id
as text (IMEI) — a deliberate simplification that hid the production type
mismatch. Now matches production: adds a devices table and changes the FK
to uuid. seedDatabase inserts devices first.
178/178 unit tests pass. Integration test exercises the corrected join
shape.
This commit is contained in:
@@ -63,9 +63,11 @@ const BROADCAST_GROUP_PREFIX = 'live-broadcast';
|
||||
const EVENT_ID = 'ee000000-0000-0000-0000-000000000001';
|
||||
const OTHER_EVENT_ID = 'ee000000-0000-0000-0000-000000000002';
|
||||
const ENTRY_ID = 'aa000000-0000-0000-0000-000000000001';
|
||||
const DEVICE_1 = '111111111111111'; // IMEI
|
||||
const DEVICE_2 = '222222222222222'; // IMEI
|
||||
const DEVICE_ORPHAN = '999999999999999'; // not in entry_devices
|
||||
const DEVICE_1_ID = 'dd000000-0000-0000-0000-000000000001';
|
||||
const DEVICE_2_ID = 'dd000000-0000-0000-0000-000000000002';
|
||||
const DEVICE_1 = '111111111111111'; // IMEI for DEVICE_1_ID
|
||||
const DEVICE_2 = '222222222222222'; // IMEI for DEVICE_2_ID
|
||||
const DEVICE_ORPHAN = '999999999999999'; // not registered to any entry
|
||||
|
||||
const USER_A: FakeUser = {
|
||||
id: 'user-aaaa-0000-0000-0000-000000000001',
|
||||
@@ -220,12 +222,20 @@ async function seedDatabase(pool: pg.Pool): Promise<void> {
|
||||
[ENTRY_ID, EVENT_ID],
|
||||
);
|
||||
|
||||
// entry_devices — Phase 1 uses IMEI as device_id
|
||||
// devices — durable catalog. positions.device_id stores the IMEI text;
|
||||
// entry_devices.device_id is a uuid FK to devices.id. The live-broadcast
|
||||
// joins translate via devices.imei.
|
||||
await pool.query(
|
||||
`INSERT INTO devices (id, imei) VALUES ($1, $2), ($3, $4)`,
|
||||
[DEVICE_1_ID, DEVICE_1, DEVICE_2_ID, DEVICE_2],
|
||||
);
|
||||
|
||||
// entry_devices — uuid FK to devices.id (matches production schema).
|
||||
await pool.query(
|
||||
`INSERT INTO entry_devices (id, entry_id, device_id) VALUES
|
||||
(gen_random_uuid(), $1, $2),
|
||||
(gen_random_uuid(), $1, $3)`,
|
||||
[ENTRY_ID, DEVICE_1, DEVICE_2],
|
||||
[ENTRY_ID, DEVICE_1_ID, DEVICE_2_ID],
|
||||
);
|
||||
|
||||
// positions for DEVICE_1 (two: one non-faulty, one faulty)
|
||||
|
||||
Reference in New Issue
Block a user