"""Database connectivity and query execution. Replaces database.js: - pyodbc connection pool (via DBUtils) - Health check (checkBackendOkay) - Parameterized query execution (runquery) - All SQL statement definitions - Stats query aggregations """ import logging logger = logging.getLogger(__name__) # TODO Phase 2: import pyodbc, DBUtils.PooledDB # import pyodbc # from DBUtils.PooledDB import PooledDB # Module-level connection pool _pool = None def init(config=None): """Initialize the MSSQL connection pool. Replaces database.init() from database.js. Uses the same config keys: user, password, server, port, database. """ global _pool # TODO Phase 2: create PooledDB raise NotImplementedError("Database not yet initialized") def connected(): """Check if the connection pool is alive.""" # TODO Phase 2 raise NotImplementedError def check_backend_okay(): """Health check: verify DB is reachable and has expected data. Replaces checkBackendOkay() from database.js. """ # TODO Phase 2 raise NotImplementedError def run_query(query_def, params): """Execute a parameterized query and return rows as list of dicts. Replaces runquery() from database.js. Args: query_def: dict with 'statement' (str) and 'params' (dict of names) or 'special' (str) for stats queries params: dict of parameter values Returns: list of dict rows """ # TODO Phase 2 raise NotImplementedError def run_query_stats_members(): """Special aggregation query for member count over time.""" # TODO Phase 2 raise NotImplementedError def run_query_stats_contracts(): """Special aggregation query for contract statistics.""" # TODO Phase 2 raise NotImplementedError def run_query_stats_genders(): """Special aggregation query for gender demographics.""" # TODO Phase 2 raise NotImplementedError def run_query_stats_ages(): """Special aggregation query for age demographics.""" # TODO Phase 2 raise NotImplementedError def member_lookup(crewname): """Look up a single member by crewname. Replaces memberlookup() from database.js. Returns a single dict row or raises. """ # TODO Phase 2 raise NotImplementedError # ─── SQL Statement Definitions ─────────────────────────────────────────────── # Replacing the QUERY_* constants from database.js # Parameter placeholders use pyodbc '?' style instead of T-SQL '@name' QUERY_CONTRACTLIST_BY_CREWNAME = { 'statement': ( 'SELECT MgVert.* FROM Adresse, MgVert ' 'WHERE Adresse.Kurzname = ? AND MgVert.AdrNr = Adresse.AdrNr' ), 'params': ['crewname'], } QUERY_CONTRACT_BY_CREWNAME_AND_CONTRACT = { 'statement': ( 'SELECT MgVert.* FROM Adresse, MgVert ' 'WHERE Adresse.Kurzname = ? AND MgVert.AdrNr = Adresse.AdrNr ' "AND (MgVert.VertragNr = ? OR MgVert.VertragNr = ' ' + ?)" ), 'params': ['crewname', 'contract'], } QUERY_DEBITLIST_BY_CREWNAME = { 'statement': ( 'SELECT MgSolln.* FROM Adresse, MgSolln ' 'WHERE Adresse.Kurzname = ? AND MgSolln.AdrNr = Adresse.AdrNr ' 'ORDER BY MgSolln.Jahr, MgSolln.Zeitraum' ), 'params': ['crewname'], } QUERY_DEBIT_BY_CREWNAME_AND_GUID = { 'statement': ( 'SELECT MgSolln.* FROM Adresse, MgSolln ' 'WHERE Adresse.Kurzname = ? AND MgSolln.AdrNr = Adresse.AdrNr ' 'AND MgSolln.GUID = ?' ), 'params': ['crewname', 'guid'], } QUERY_MEMBERLIST = { 'statement': ( "SELECT AdrNr, Firma4, Nachname, Vorname, Kurzname, Kennung3, " "Telefon3, Kontaktwoher, Eintritt, Austritt " "FROM Adresse WHERE Kurzname != '' ORDER BY Nachname" ), 'params': [], } QUERY_STATS_MEMBERS = { 'special': 'QUERY_STATS_MEMBERS', } QUERY_STATS_CONTRACTS = { 'special': 'QUERY_STATS_CONTRACTS', } QUERY_STATS_GENDERS = { 'special': 'QUERY_STATS_GENDERS', } QUERY_STATS_AGES = { 'special': 'QUERY_STATS_AGES', } QUERY_MEMBERLIST_RAW = { 'statement': 'SELECT * FROM Adresse ORDER BY Nachname', 'params': [], } QUERY_MEMBER_BY_CREWNAME = { 'statement': 'SELECT * FROM Adresse WHERE Kurzname = ?', 'params': ['crewname'], } QUERY_MEMBER_MEMO_BY_CREWNAME = { 'statement': ( 'SELECT Memof.* FROM Adresse, Memof ' 'WHERE Adresse.Kurzname = ? AND Memof.AdrNr = Adresse.AdrNr' ), 'params': ['crewname'], } QUERY_WITHDRAWALLIST_BY_CREWNAME = { 'statement': ( 'SELECT MgLast.* FROM Adresse, MgLast ' 'WHERE Adresse.Kurzname = ? AND MgLast.Adr_Nummer = Adresse.AdrNr' ), 'params': ['crewname'], } QUERY_WITHDRAWAL_BY_CREWNAME_AND_GUID = { 'statement': ( 'SELECT MgLast.* FROM Adresse, MgLast ' 'WHERE Adresse.Kurzname = ? AND MgLast.Adr_Nummer = Adresse.AdrNr ' 'AND MgLast.GUID = ?' ), 'params': ['crewname', 'guid'], } QUERY_PAYMENTLIST_BY_CREWNAME = { 'statement': ( 'SELECT F5bew4.* FROM Adresse, F5bew4 ' 'WHERE Adresse.Kurzname = ? AND F5bew4.AdrNr = Adresse.AdrNr' ), 'params': ['crewname'], }