fixes and refactor
This commit is contained in:
130
app/database/schema_updates.py
Normal file
130
app/database/schema_updates.py
Normal file
@@ -0,0 +1,130 @@
|
||||
"""
|
||||
Lightweight, idempotent schema updates for SQLite.
|
||||
|
||||
Adds newly introduced columns to existing tables when running on an
|
||||
already-initialized database. Safe to call multiple times.
|
||||
"""
|
||||
from typing import Dict
|
||||
from sqlalchemy.engine import Engine
|
||||
|
||||
|
||||
def _existing_columns(conn, table: str) -> set[str]:
|
||||
rows = conn.execute(f"PRAGMA table_info('{table}')").fetchall()
|
||||
return {row[1] for row in rows} # name is column 2
|
||||
|
||||
|
||||
def ensure_schema_updates(engine: Engine) -> None:
|
||||
"""Ensure missing columns are added for backward-compatible updates."""
|
||||
# Map of table -> {column: SQL type}
|
||||
updates: Dict[str, Dict[str, str]] = {
|
||||
# Forms
|
||||
"form_index": {
|
||||
"keyword": "TEXT",
|
||||
},
|
||||
# Richer Life/Number tables (forms & pensions harmonized)
|
||||
"life_tables": {
|
||||
"le_aa": "FLOAT",
|
||||
"na_aa": "FLOAT",
|
||||
"le_am": "FLOAT",
|
||||
"na_am": "FLOAT",
|
||||
"le_af": "FLOAT",
|
||||
"na_af": "FLOAT",
|
||||
"le_wa": "FLOAT",
|
||||
"na_wa": "FLOAT",
|
||||
"le_wm": "FLOAT",
|
||||
"na_wm": "FLOAT",
|
||||
"le_wf": "FLOAT",
|
||||
"na_wf": "FLOAT",
|
||||
"le_ba": "FLOAT",
|
||||
"na_ba": "FLOAT",
|
||||
"le_bm": "FLOAT",
|
||||
"na_bm": "FLOAT",
|
||||
"le_bf": "FLOAT",
|
||||
"na_bf": "FLOAT",
|
||||
"le_ha": "FLOAT",
|
||||
"na_ha": "FLOAT",
|
||||
"le_hm": "FLOAT",
|
||||
"na_hm": "FLOAT",
|
||||
"le_hf": "FLOAT",
|
||||
"na_hf": "FLOAT",
|
||||
"table_year": "INTEGER",
|
||||
"table_type": "VARCHAR(45)",
|
||||
},
|
||||
"number_tables": {
|
||||
"month": "INTEGER",
|
||||
"na_aa": "FLOAT",
|
||||
"na_am": "FLOAT",
|
||||
"na_af": "FLOAT",
|
||||
"na_wa": "FLOAT",
|
||||
"na_wm": "FLOAT",
|
||||
"na_wf": "FLOAT",
|
||||
"na_ba": "FLOAT",
|
||||
"na_bm": "FLOAT",
|
||||
"na_bf": "FLOAT",
|
||||
"na_ha": "FLOAT",
|
||||
"na_hm": "FLOAT",
|
||||
"na_hf": "FLOAT",
|
||||
"table_type": "VARCHAR(45)",
|
||||
"description": "TEXT",
|
||||
},
|
||||
"form_list": {
|
||||
"status": "VARCHAR(45)",
|
||||
},
|
||||
# Printers: add advanced legacy fields
|
||||
"printers": {
|
||||
"number": "INTEGER",
|
||||
"page_break": "VARCHAR(50)",
|
||||
"setup_st": "VARCHAR(200)",
|
||||
"reset_st": "VARCHAR(200)",
|
||||
"b_underline": "VARCHAR(100)",
|
||||
"e_underline": "VARCHAR(100)",
|
||||
"b_bold": "VARCHAR(100)",
|
||||
"e_bold": "VARCHAR(100)",
|
||||
"phone_book": "BOOLEAN",
|
||||
"rolodex_info": "BOOLEAN",
|
||||
"envelope": "BOOLEAN",
|
||||
"file_cabinet": "BOOLEAN",
|
||||
"accounts": "BOOLEAN",
|
||||
"statements": "BOOLEAN",
|
||||
"calendar": "BOOLEAN",
|
||||
},
|
||||
# Pensions
|
||||
"pension_schedules": {
|
||||
"vests_on": "DATE",
|
||||
"vests_at": "FLOAT",
|
||||
},
|
||||
"marriage_history": {
|
||||
"married_from": "DATE",
|
||||
"married_to": "DATE",
|
||||
"married_years": "FLOAT",
|
||||
"service_from": "DATE",
|
||||
"service_to": "DATE",
|
||||
"service_years": "FLOAT",
|
||||
"marital_percent": "FLOAT",
|
||||
},
|
||||
"death_benefits": {
|
||||
"lump1": "FLOAT",
|
||||
"lump2": "FLOAT",
|
||||
"growth1": "FLOAT",
|
||||
"growth2": "FLOAT",
|
||||
"disc1": "FLOAT",
|
||||
"disc2": "FLOAT",
|
||||
},
|
||||
}
|
||||
|
||||
with engine.begin() as conn:
|
||||
for table, cols in updates.items():
|
||||
try:
|
||||
existing = _existing_columns(conn, table)
|
||||
except Exception:
|
||||
# Table may not exist yet
|
||||
continue
|
||||
for col_name, col_type in cols.items():
|
||||
if col_name not in existing:
|
||||
try:
|
||||
conn.execute(f"ALTER TABLE {table} ADD COLUMN {col_name} {col_type}")
|
||||
except Exception:
|
||||
# Ignore if not applicable (other engines) or race condition
|
||||
pass
|
||||
|
||||
|
||||
Reference in New Issue
Block a user