|
1 | 1 | from __future__ import annotations |
2 | 2 |
|
3 | 3 | import re |
| 4 | +from collections.abc import Sequence |
4 | 5 | from datetime import datetime, timezone |
5 | 6 | from typing import NotRequired, TypedDict, get_type_hints |
6 | 7 |
|
7 | 8 | from fastapi import Request |
8 | | -from pydantic import ConfigDict, computed_field, field_validator |
| 9 | +from pydantic import ConfigDict, Field, computed_field, field_validator |
9 | 10 |
|
10 | 11 | from endpoints.responses.assets import SaveSchema, ScreenshotSchema, StateSchema |
11 | 12 | from handler.metadata.flashpoint_handler import FlashpointMetadata |
|
18 | 19 | from handler.metadata.ra_handler import RAMetadata |
19 | 20 | from handler.metadata.ss_handler import SSMetadata |
20 | 21 | from models.collection import Collection |
21 | | -from models.rom import Rom, RomArchiveMember, RomFileCategory, RomUserStatus |
| 22 | +from models.rom import Rom, RomArchiveMember, RomFile, RomFileCategory, RomUserStatus |
22 | 23 |
|
23 | 24 | from .base import BaseModel, UTCDatetime |
24 | 25 |
|
@@ -335,16 +336,50 @@ def sort_comparator(self) -> str: |
335 | 336 | .lower() |
336 | 337 | ) |
337 | 338 |
|
| 339 | + @classmethod |
| 340 | + def from_rom(cls, rom: Rom) -> SiblingRomSchema: |
| 341 | + return cls( |
| 342 | + id=rom.id, |
| 343 | + name=rom.name, |
| 344 | + fs_name_no_tags=rom.fs_name_no_tags, |
| 345 | + fs_name_no_ext=rom.fs_name_no_ext, |
| 346 | + ) |
| 347 | + |
338 | 348 |
|
339 | 349 | class SimpleRomSchema(RomSchema): |
340 | 350 | sibling_ids: list[int] |
| 351 | + # `files` binds to a dedicated attribute via validation alias rather than the |
| 352 | + # `Rom.files` relationship: that keeps the full file list out of the default |
| 353 | + # gallery payload, and avoids tripping the relationship's lazy="raise" in |
| 354 | + # factory contexts where files aren't loaded. Populated only when requested. |
| 355 | + files: list[RomFileSchema] = Field( |
| 356 | + default_factory=list, validation_alias="included_files" |
| 357 | + ) |
| 358 | + siblings: list[SiblingRomSchema] = Field(default_factory=list) |
| 359 | + |
| 360 | + @field_validator("files") |
| 361 | + def sort_files(cls, v: list[RomFileSchema]) -> list[RomFileSchema]: |
| 362 | + return sorted(v, key=lambda x: x.file_name) |
| 363 | + |
| 364 | + @field_validator("siblings") |
| 365 | + def sort_siblings(cls, v: list[SiblingRomSchema]) -> list[SiblingRomSchema]: |
| 366 | + return sorted(v, key=lambda x: x.sort_comparator) |
341 | 367 |
|
342 | 368 | @classmethod |
343 | 369 | def from_orm_with_request( |
344 | | - cls, db_rom: Rom, request: Request, sibling_ids: list[int] | None = None |
| 370 | + cls, |
| 371 | + db_rom: Rom, |
| 372 | + request: Request, |
| 373 | + sibling_ids: list[int] | None = None, |
| 374 | + files: Sequence[RomFile] | None = None, |
| 375 | + siblings: Sequence[Rom] | None = None, |
345 | 376 | ) -> SimpleRomSchema: |
346 | 377 | db_rom = cls.populate_properties(db_rom, request) |
347 | 378 | db_rom.sibling_ids = sibling_ids or [] # type: ignore |
| 379 | + db_rom.included_files = files or [] # type: ignore |
| 380 | + db_rom.siblings = ( # type: ignore |
| 381 | + [SiblingRomSchema.from_rom(s) for s in siblings] if siblings else [] |
| 382 | + ) |
348 | 383 | return cls.model_validate(db_rom) |
349 | 384 |
|
350 | 385 | @classmethod |
@@ -397,15 +432,7 @@ def from_orm_with_request(cls, db_rom: Rom, request: Request) -> DetailedRomSche |
397 | 432 | db_rom = cls.populate_properties(db_rom, request) |
398 | 433 |
|
399 | 434 | sorted_siblings = sorted( |
400 | | - ( |
401 | | - SiblingRomSchema( |
402 | | - id=s.id, |
403 | | - name=s.name, |
404 | | - fs_name_no_tags=s.fs_name_no_tags, |
405 | | - fs_name_no_ext=s.fs_name_no_ext, |
406 | | - ) |
407 | | - for s in db_rom.sibling_roms |
408 | | - ), |
| 435 | + (SiblingRomSchema.from_rom(s) for s in db_rom.sibling_roms), |
409 | 436 | key=lambda x: x.sort_comparator, |
410 | 437 | ) |
411 | 438 | db_rom.siblings = sorted_siblings # type: ignore |
|
0 commit comments