perf(roms): make filter_roms file-loading opt-in for the gallery query

filter_roms feeds both the gallery/list endpoint (SimpleRomSchema, no
files) and the feed endpoints (which iterate rom.files / is_top_level).
The cleanup commit's unconditional selectinload(Rom.files) + joinedload
made the gallery/list and filter-value paths pay for files they never
serialize.

Gate the files load behind a new `include_files` flag (default False),
mirroring the existing `include_file_stats` opt-in, and plumb it through
get_roms_scalar. The 9 feed endpoints that actually read rom.files opt
in; the gallery/list, filter-values, identifiers, smart-collection, and
the three feeds that don't touch files (webrcade, fpkgi, kekatsu) skip
the load entirely — keeping the gallery query at zero file cost.

https://claude.ai/code/session_01PSXKmejPRzdxLFMN6P2QQ4
This commit is contained in:
Claude
2026-06-02 12:54:58 +00:00
parent 36c8f388f9
commit c4dd922491
2 changed files with 38 additions and 13 deletions

View File

@@ -213,7 +213,7 @@ async def tinfoil_index_feed(
return titledb
roms = db_rom_handler.get_roms_scalar(platform_ids=[switch.id])
roms = db_rom_handler.get_roms_scalar(platform_ids=[switch.id], include_files=True)
return TinfoilFeedSchema(
files=[
@@ -329,7 +329,9 @@ def pkgi_ps3_feed(
status_code=400, detail=f"Invalid content type: {content_type}"
) from e
roms = db_rom_handler.get_roms_scalar(platform_ids=[ps3_platform.id])
roms = db_rom_handler.get_roms_scalar(
platform_ids=[ps3_platform.id], include_files=True
)
txt_lines = []
for rom in roms:
@@ -405,7 +407,9 @@ def pkgi_psvita_feed(
status_code=400, detail=f"Invalid content type: {content_type}"
) from e
roms = db_rom_handler.get_roms_scalar(platform_ids=[psvita_platform.id])
roms = db_rom_handler.get_roms_scalar(
platform_ids=[psvita_platform.id], include_files=True
)
txt_lines = []
for rom in roms:
@@ -480,7 +484,9 @@ def pkgi_psp_feed(
status_code=400, detail=f"Invalid content type: {content_type}"
) from e
roms = db_rom_handler.get_roms_scalar(platform_ids=[psp_platform.id])
roms = db_rom_handler.get_roms_scalar(
platform_ids=[psp_platform.id], include_files=True
)
txt_lines = []
for rom in roms:
@@ -663,7 +669,9 @@ def pkgj_psp_games_feed(request: Request) -> Response:
status_code=404, detail="PlayStation Portable platform not found"
)
roms = db_rom_handler.get_roms_scalar(platform_ids=[platform.id])
roms = db_rom_handler.get_roms_scalar(
platform_ids=[platform.id], include_files=True
)
txt_lines = []
txt_lines.append(
"Title ID\tRegion\tType\tName\tPKG direct link\tContent ID\tLast Modification Date\tRAP\tDownload .RAP file\tFile Size\tSHA256"
@@ -727,7 +735,9 @@ def pkgj_psp_dlcs_feed(request: Request) -> Response:
status_code=404, detail="PlayStation Portable platform not found"
)
roms = db_rom_handler.get_roms_scalar(platform_ids=[platform.id])
roms = db_rom_handler.get_roms_scalar(
platform_ids=[platform.id], include_files=True
)
txt_lines = []
txt_lines.append(
"Title ID\tRegion\tName\tPKG direct link\tContent ID\tLast Modification Date\tRAP\tDownload .RAP file\tFile Size\tSHA256"
@@ -789,7 +799,9 @@ def pkgj_psv_games_feed(request: Request) -> Response:
status_code=404, detail="PlayStation Vita platform not found"
)
roms = db_rom_handler.get_roms_scalar(platform_ids=[platform.id])
roms = db_rom_handler.get_roms_scalar(
platform_ids=[platform.id], include_files=True
)
txt_lines = []
txt_lines.append(
"Title ID\tRegion\tName\tPKG direct link\tzRIF\tContent ID\tLast Modification Date\tOriginal Name\tFile Size\tSHA256\tRequired FW\tApp Version"
@@ -854,7 +866,9 @@ def pkgj_psv_dlcs_feed(request: Request) -> Response:
status_code=404, detail="PlayStation Vita platform not found"
)
roms = db_rom_handler.get_roms_scalar(platform_ids=[platform.id])
roms = db_rom_handler.get_roms_scalar(
platform_ids=[platform.id], include_files=True
)
txt_lines = []
txt_lines.append(
"Title ID\tRegion\tName\tPKG direct link\tzRIF\tContent ID\tLast Modification Date\tFile Size\tSHA256"
@@ -911,7 +925,9 @@ def pkgj_psx_games_feed(request: Request) -> Response:
if not platform:
raise HTTPException(status_code=404, detail="PlayStation platform not found")
roms = db_rom_handler.get_roms_scalar(platform_ids=[platform.id])
roms = db_rom_handler.get_roms_scalar(
platform_ids=[platform.id], include_files=True
)
txt_lines = []
txt_lines.append(
"Title ID\tRegion\tName\tPKG direct link\tContent ID\tLast Modification Date\tOriginal Name\tFile Size\tSHA256"

View File

@@ -586,6 +586,7 @@ class DBRomsHandler(DBBaseHandler):
user_id: int | None = None,
updated_after: datetime | None = None,
include_file_stats: bool = False,
include_files: bool = False,
session: Session = None, # type: ignore
) -> Query[Rom]:
from handler.scan_handler import MetadataSource
@@ -597,10 +598,6 @@ class DBRomsHandler(DBBaseHandler):
selectinload(Rom.rom_users).options(noload(RomUser.rom)),
# Sort table by metadata (first_release_date)
selectinload(Rom.metadatum).options(noload(RomMetadata.rom)),
# Multi-file downloads, 3DS QR codes, and metadata matching
selectinload(Rom.files).options(
joinedload(RomFile.rom).load_only(Rom.fs_path, Rom.fs_name)
),
# Show sibling rom badges on cards
selectinload(Rom.sibling_roms).options(
noload(Rom.platform), noload(Rom.metadatum)
@@ -609,6 +606,17 @@ class DBRomsHandler(DBBaseHandler):
selectinload(Rom.notes),
)
# Only load files (and the RomFile.rom backref needed by `is_top_level` /
# `file_name_for_download`) when the caller iterates them — e.g. the
# feed endpoints. The gallery/list and filter-value paths serialize
# SimpleRomSchema without files, so they skip this entirely.
if include_files:
query = query.options(
selectinload(Rom.files).options(
joinedload(RomFile.rom).load_only(Rom.fs_path, Rom.fs_name)
)
)
# Correlated subqueries and only undefer when the caller serializes the
# gallery-card flags. Feeds and filter-value lookups don't need them.
if include_file_stats:
@@ -917,6 +925,7 @@ class DBRomsHandler(DBBaseHandler):
player_counts_logic=kwargs.get("player_counts_logic", "any"),
user_id=kwargs.get("user_id", None),
group_by_meta_id=kwargs.get("group_by_meta_id", False),
include_files=kwargs.get("include_files", False),
)
return session.scalars(roms).all()