fix(media-items): normalize NOT NULL narrators on every write path
A2 made narrators/narrators_search NOT NULL DEFAULT '{}' (86f0af6), but an
explicit NULL in an INSERT/UPDATE column list bypasses the column default
— the API media-create path (POST /api/media-items without narrators)
500'd on every call, taking the whole integration suite down with it
(ISBN tests, capture seeds, all direct-DB seeds).
- set_library_type_name() trigger now coalesces NULL narrators/
narrators_search to '{}' at the row level, and its update trigger
widens from BEFORE UPDATE OF library_id to BEFORE UPDATE so every
write path is covered
- defense in depth at the callers: handler create/update normalize nil
to empty slices (normalizeNarrators), scanner seeds the same
(nilToEmpty) for files that carry no narrator credits
- analytics device-usage tests move to the dedicated per-test user
(the shared admin's device list accrues live rows mid-suite — the
documented testuser flapping class)
This commit is contained in:
1 parent
73ae1789c5
commit
a222ef5c27
5 files changed
+56
-13
No files matched your search
@@ -289,12 +289,25 @@ DROP TRIGGER IF EXISTS set_library_type_name_on_library_change ON media_items;
|
||||
DROP FUNCTION IF EXISTS set_library_type_name();
|
||||
|
||||
-- Add trigger to populate library_type_name on insert
|
||||
-- Recompute the denormalized library type on insert, and NORMALIZE the
|
||||
-- A2 NOT NULL narrators columns: narrators/narrators_search are NOT NULL
|
||||
-- DEFAULT '{}' but an explicit NULL in an INSERT/UPDATE column list
|
||||
-- bypasses the column default and 23502s (the API create path without
|
||||
-- narrators 500'd exactly this way). "No narrators known" is an empty
|
||||
-- array, never NULL — coalesce at the row level so every write path
|
||||
-- (API, scanner, direct seeds) is safe by construction.
|
||||
CREATE OR REPLACE FUNCTION set_library_type_name() RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
SELECT lt.name INTO NEW.library_type_name
|
||||
FROM libraries l
|
||||
JOIN library_types lt ON l.library_type_id = lt.id
|
||||
WHERE l.id = NEW.library_id;
|
||||
IF NEW.narrators IS NULL THEN
|
||||
NEW.narrators := '{}';
|
||||
END IF;
|
||||
IF NEW.narrators_search IS NULL THEN
|
||||
NEW.narrators_search := '{}';
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
@@ -305,9 +318,10 @@ CREATE TRIGGER set_library_type_name_on_insert
|
||||
|
||||
-- Keep library_type_name truthful when an item is repointed to another
|
||||
-- library (cross-library move detection reuses the same function; the row
|
||||
-- keeps its ID while its library changes).
|
||||
-- keeps its ID while its library changes). Fires on ALL updates so the
|
||||
-- narrators normalization guards every write path, not just library moves.
|
||||
CREATE TRIGGER set_library_type_name_on_library_change
|
||||
BEFORE UPDATE OF library_id ON media_items
|
||||
BEFORE UPDATE ON media_items
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION set_library_type_name();
|
||||
|
||||
|
||||
Reference in new issue
Block a user