fix(plex): stop /facets 500 on a metadata-poor library
A mirrored Shows library whose items have no genres stored `genres` as JSON `null` — SQLAlchemy's JSONB persists a Python None as a JSON scalar, not SQL NULL. /facets unnested it with jsonb_array_elements_text(), which raises "cannot extract elements from a scalar", so a single bare library 500'd the whole Plex module on open (the grid loads, the filter sidebar's facets call dies). - Guard the /facets genre unnest with jsonb_typeof(genres)='array', mirroring the guard people.py already applies to the same columns. - Persist the JSONB tag columns (genres/directors/cast_names/collection_keys on plex_items and plex_shows) with none_as_null=True, so an empty list round-trips as SQL NULL and self-heals on the next sync — closing the trap for any future unnest. Verified against the real prod row (DumaTV show, genres = JSON null): the unguarded query errors, the guarded one returns cleanly.
This commit is contained in:
@@ -675,10 +675,15 @@ def facets(
|
||||
# the result down to zero, i.e. a dead-end chip. (The already-selected genres still appear, since
|
||||
# every matching title carries them, so they stay togglable.)
|
||||
genre_pp = p if p.get("genre_mode") == "all" else {**p, "genres": None}
|
||||
# Only rows whose `genres` is a JSON array can be unnested. A genre-less item stores JSON
|
||||
# `null` (SQLAlchemy's JSONB persists a Python None as JSON null, not SQL NULL), and
|
||||
# jsonb_array_elements_text() raises on a scalar ("cannot extract elements from a scalar") —
|
||||
# so a single metadata-poor library (e.g. one bare Shows library with no genres) 500'd the
|
||||
# whole facets endpoint. Mirror the exact guard people.py already applies to the same columns.
|
||||
expanded = wsq(
|
||||
db.query(func.jsonb_array_elements_text(model.genres).label("g")),
|
||||
model, ids, genre_pp, kind_movie, True,
|
||||
).subquery()
|
||||
).filter(func.jsonb_typeof(model.genres) == "array").subquery()
|
||||
for g, c in db.query(expanded.c.g, func.count()).group_by(expanded.c.g).all():
|
||||
genre_counts[g] = genre_counts.get(g, 0) + c
|
||||
# Content ratings — exclude its own.
|
||||
|
||||
Reference in New Issue
Block a user