Factor out rendering of game participants

This commit is contained in:
Jack Jackson 2024-06-26 19:23:04 -07:00
parent 61078f0201
commit 01e4c5e36b
5 changed files with 37 additions and 15 deletions

View File

@ -20,6 +20,7 @@
- [ ] "Display components" like "a tables of games" that can be inserted into multiple pages
* Oh no, did I just re-invent React? :P
- [ ] Data presentation methods like "translating a list of Deck IDs into Deck Names"
- [X] Externalize datastorage (currently)
...
- [ ] Authentication (will need to link `user` table to `player`)
...

View File

@ -10,6 +10,7 @@ from ..sql import crud, schemas
from ..sql.database import get_db
from .players import list_players
from .games import _render_game_participants
api_router = APIRouter(prefix="/deck", tags=["deck"])
html_router = APIRouter(
@ -115,6 +116,7 @@ def _build_deck_score_history(deck_id: str, db: Session):
)
.first()
.score,
"game_participants": _render_game_participants(game, db),
}
for game in games_involving_this_deck
]

View File

@ -1,14 +1,13 @@
import json
import logging
from functional import seq
from typing import List, Mapping
from typing import List, Mapping, Union
from fastapi import APIRouter, Depends, HTTPException, Request
from fastapi.responses import HTMLResponse
from sqlalchemy.orm import Session
from app.routers.decks import list_decks
from app.sql import models
from .players import list_players
from ..elo import rerank
@ -117,7 +116,7 @@ def games_html(request: Request, db=Depends(get_db)):
games = list_games(db=db)
# TODO - a more "data-intensive application" implementation would fetch only the decks involved in the games for
# this page
decks = list_decks(db=db, limit=-1)
decks = crud.get_decks(db=db, limit=-1)
decks_by_id = {deck.id: deck for deck in decks}
game_names = {game.id: _build_game_deck_names(game, decks_by_id) for game in games}
return jinja_templates.TemplateResponse(
@ -127,6 +126,25 @@ def games_html(request: Request, db=Depends(get_db)):
)
# Although this is underscore-prefixed, it _is_ intentionally called from `decks.py`, since that logic
# is used there, too.
# Maybe this should be extracted to a file that's appropriate for "logic that's to do with games, but which is not a
# router"?
# Still learning my way around FastAPI project structure!
def _render_game_participants(
game: models.Game, db: Session
) -> List[Mapping[str, Union[str, int]]]:
return (
seq(range(6))
.map(lambda i: i + 1)
.map(lambda i: f"deck_id_{i}")
.map(lambda key: getattr(game, key))
.filter(lambda x: x) # Not every game has 6 participants!
.map(lambda deck_id: crud.get_deck_by_id(db, deck_id))
.map(lambda deck: {"owner": deck.owner.name, "name": deck.name, "id": deck.id})
)
def _build_game_deck_names(
game: models.Game, decks_by_id: Mapping[int, models.Deck]
) -> List[str]:
@ -146,7 +164,7 @@ def _build_game_deck_names(
def game_html(request: Request, game_id: str, db=Depends(get_db)):
game = read_game(game_id, db)
decks = list_decks(db=db, limit=-1)
decks = crud.get_decks(db=db, limit=-1)
decks_by_id = {deck.id: deck for deck in decks}
game_deck_names = _build_game_deck_names(game, decks_by_id)

View File

@ -7,9 +7,12 @@ SQLALCHEMY_DATABASE_URL = os.environ.get(
"DATABASE_URL", "sqlite:///database/sql_app.db"
)
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
if SQLALCHEMY_DATABASE_URL.startswith("sqlite"):
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
else:
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

View File

@ -15,8 +15,6 @@
<h2>Game history</h2>
{% if game_history %}
(TODO - extract a translation-from-deckid-to-names method)
(Or...just link them as a relationship/ForeignKey)
<table>
<tr>
<th>Date</th>
@ -28,12 +26,12 @@
<tr>
<td><a href="/game/{{ entry.game.id }}">{{ entry.game.date.strftime('%Y-%m-%d') }}</a></td>
<td>
{% for participant_id in range(6) %}
{% set deck_id = entry.game['deck_id_' ~ (participant_id+1)] %}
{% if deck_id is not none %}
<a href="/deck/{{ deck_id }}">{{ deck_id }}</a>
{% endif %}
{% endfor %}</td>
<ul>
{% for participant in entry.game_participants %}
<li><a href="/deck/{{ participant.id }}">{{ participant.owner }} ({{ participant.name }})</a></li>
{% endfor %}
</ul>
</td>
<td>{{ "Win" if entry.game.winning_deck_id == deck.id else "Loss" }}</td>
<td>{{ entry.score|int }}</td>
</tr>