import datetime from typing import TypedDict from folkugat_web.dal.sql import Connection, get_connection from folkugat_web.model import sessions as model from folkugat_web.model.sql import OrderCol, Range from folkugat_web.typing import OptionalListOrValue as OLV from . import conversion class QueryData(TypedDict, total=False): session_id: int | None date_ub: datetime.date date_lb: datetime.date is_live: bool limit: int offset: int def _filter_clause(session_id: int | None = None, date_range: Range[datetime.date] | None = None, is_live: bool | None = None) -> tuple[str, QueryData]: filter_clauses: list[str] = [] filter_data: QueryData = {} if session_id is not None: filter_clauses.append(f"id = :session_id") filter_data["session_id"] = session_id if date_range: if ub := date_range.upper_bound(): operator = "<=" if ub[1] else "<" filter_clauses.append(f"date {operator} :date_ub") filter_data["date_ub"] = ub[0] if lb := date_range.lower_bound(): operator = ">=" if lb[1] else ">" filter_clauses.append(f"date {operator} :date_lb") filter_data["date_lb"] = lb[0] if is_live is not None: filter_clauses.append(f"is_live = :is_live") filter_data["is_live"] = is_live if filter_clauses: filter_clause_str = " AND ".join(filter_clauses) filter_clause = f"WHERE {filter_clause_str}" return filter_clause, filter_data else: return "", {} def _order_clause(order_by: OLV[OrderCol[model.SessionCols]]) -> str: if not order_by: return "" if not isinstance(order_by, list): order_by = [order_by] order_clauses = [f"{ocol.column.value} {ocol.order.value}" for ocol in order_by] order_clauses_str = " ".join(order_clauses) return f"ORDER BY {order_clauses_str}" def get_sessions(session_id: int | None = None, date_range: Range[datetime.date] | None = None, is_live: bool | None = None, order_by: OLV[OrderCol[model.SessionCols]] = None, limit: int | None = None, offset: int | None = None, con: Connection | None = None) -> list[model.Session]: clauses: list[str] = [] filter_clause, data = _filter_clause(session_id=session_id, date_range=date_range, is_live=is_live) if filter_clause: clauses.append(filter_clause) if order_clause := _order_clause(order_by=order_by): clauses.append(order_clause) if limit is not None: clauses.append("LIMIT :limit") data["limit"] = limit if offset is not None: clauses.append("OFFSET :offset") data["offset"] = offset clauses_str = " ".join(clauses) query = f""" SELECT id, date, start_time, end_time, venue_name, venue_url, notes, cartell_url, is_live FROM sessions {clauses_str} """ with get_connection(con) as con: cur = con.cursor() _ = cur.execute(query, data) return list(map(conversion.row_to_session, cur.fetchall()))