from numpy import place from db import get_connection from repositories.team_repository import get_team_id_by_external_id from repositories.stadium_repository import get_or_create_stadium def ensure_match_source_key_column() -> None: """Добавляет источник турнира для матчей, чтобы vMix выбирал правильную папку логотипов.""" conn = get_connection() try: with conn.cursor() as cur: cur.execute( """ ALTER TABLE matches ADD COLUMN IF NOT EXISTS source_key VARCHAR(50); """ ) conn.commit() except Exception: conn.rollback() raise finally: conn.close() def upsert_match( external_id: str, home_team_id: int, away_team_id: int, match_date=None, status: str = "scheduled", home_score: int | None = None, away_score: int | None = None, tour: str | None = None, season: str | None = None, place: str | None = None, stadium_id: int | None = None, date_raw: str | None = None, score_add: str | None = None, source_key: str | None = None, ) -> None: query = """ INSERT INTO matches ( external_id, home_team_id, away_team_id, match_date, status, home_score, away_score, tour, season, place, stadium_id, date_raw, score_add, source_key, created_at, updated_at ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW(), NOW()) ON CONFLICT (external_id) DO UPDATE SET home_team_id = EXCLUDED.home_team_id, away_team_id = EXCLUDED.away_team_id, match_date = EXCLUDED.match_date, status = EXCLUDED.status, home_score = EXCLUDED.home_score, away_score = EXCLUDED.away_score, tour = EXCLUDED.tour, season = EXCLUDED.season, place = EXCLUDED.place, stadium_id = EXCLUDED.stadium_id, date_raw = EXCLUDED.date_raw, score_add = EXCLUDED.score_add, source_key = COALESCE(EXCLUDED.source_key, matches.source_key), updated_at = NOW(); """ conn = get_connection() try: with conn.cursor() as cur: cur.execute( query, ( external_id, home_team_id, away_team_id, match_date, status, home_score, away_score, tour, season, place, stadium_id, date_raw, score_add, source_key, ), ) conn.commit() except Exception: conn.rollback() raise finally: conn.close() def upsert_match_by_team_external_ids( external_id: str, home_team_external_id: str, away_team_external_id: str, match_date=None, status: str = "scheduled", home_score: int | None = None, away_score: int | None = None, tour: str | None = None, season: str | None = None, place: str | None = None, stadium_id: int | None = None, date_raw: str | None = None, score_add: str | None = None, source_key: str | None = None, ) -> None: home_team_id = get_team_id_by_external_id(home_team_external_id) away_team_id = get_team_id_by_external_id(away_team_external_id) stadium_id = get_or_create_stadium(place) if home_team_id is None: raise ValueError(f"Home team not found by external_id: {home_team_external_id}") if away_team_id is None: raise ValueError(f"Away team not found by external_id: {away_team_external_id}") upsert_match( external_id=external_id, home_team_id=home_team_id, away_team_id=away_team_id, match_date=match_date, status=status, home_score=home_score, away_score=away_score, tour=tour, season=season, place=place, stadium_id=stadium_id, date_raw=date_raw, score_add=score_add, source_key=source_key, ) def clear_match_squad_data(match_id: int) -> None: conn = get_connection() try: with conn.cursor() as cur: cur.execute("DELETE FROM match_lineup_players WHERE match_id = %s", (match_id,)) cur.execute("DELETE FROM match_coaches WHERE match_id = %s", (match_id,)) cur.execute("DELETE FROM match_lineups WHERE match_id = %s", (match_id,)) # если есть таблица судей матча cur.execute("DELETE FROM match_referees WHERE match_id = %s", (match_id,)) # если есть матчевые расстановки cur.execute("DELETE FROM match_formations WHERE match_id = %s", (match_id,)) conn.commit() except Exception: conn.rollback() raise finally: conn.close() def get_match_by_external_id(external_id: str): query = """ SELECT id, external_id, home_team_id, away_team_id FROM matches WHERE external_id = %s LIMIT 1; """ conn = get_connection() try: with conn.cursor() as cur: cur.execute(query, (str(external_id).strip(),)) return cur.fetchone() finally: conn.close() def mark_match_parsed(external_id: str) -> None: query = """ UPDATE matches SET parsed = TRUE, parse_error = NULL, updated_at = NOW() WHERE external_id = %s; """ conn = get_connection() try: with conn.cursor() as cur: cur.execute(query, (str(external_id).strip(),)) conn.commit() except Exception: conn.rollback() raise finally: conn.close() def mark_match_parse_error(external_id: str, error_text: str) -> None: query = """ UPDATE matches SET parsed = FALSE, parse_error = %s, updated_at = NOW() WHERE external_id = %s; """ conn = get_connection() try: with conn.cursor() as cur: cur.execute(query, (str(error_text)[:2000], str(external_id).strip())) conn.commit() except Exception: conn.rollback() raise finally: conn.close() def get_tour_schedule_by_match_id(match_id: int) -> list[dict]: conn = get_connection() try: with conn.cursor() as cur: cur.execute( """ SELECT m.tour FROM matches m WHERE m.id = %s """, (match_id,), ) row = cur.fetchone() if not row or not row[0]: return [] tour = row[0] cur.execute( """ SELECT m.id, m.external_id, m.match_date, m.place, m.status, m.home_score, m.away_score, ht.name AS home_team_name, at.name AS away_team_name, COALESCE(m.channel, '') AS channel FROM matches m LEFT JOIN teams ht ON ht.id = m.home_team_id LEFT JOIN teams at ON at.id = m.away_team_id WHERE m.tour = %s ORDER BY m.match_date NULLS LAST, m.id """, (tour,), ) rows = cur.fetchall() return [ { "match_id": r[0], "match_external_id": r[1], "match_date": r[2], "stadium_name": r[3] or "", "status": r[4] or "", "home_score": r[5], "away_score": r[6], "home_team_name": r[7] or "", "away_team_name": r[8] or "", "channel": r[9] or "", } for r in rows ] finally: conn.close()