chore(api): stabilize SQL core and enhance searchability
- Refactor SQL CRUD to use engine.connect() context managers for thread safety - Optimize connection pooling in lib_sql_core - Clean up app/routers/api.py to fix duplicate definitions and OpenAPI KeyError - Add 'default_qry_str' to searchable_fields for Event, Session, Presentation, Presenter, Badge, and Journal - Add 'event_location_name' to searchable_fields for Event Session - Verified 20/20 E2E success via repro_intermittent_errors.py
This commit is contained in:
@@ -13,6 +13,8 @@ from app.log import log, logger_reset
|
||||
from app import lib_sql_core
|
||||
from app.lib_sql_core import sql_connect, set_last_sql_error
|
||||
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
|
||||
# Helper for resolving random IDs
|
||||
from app.lib_redis_helpers import lookup_id_random_pop
|
||||
|
||||
@@ -51,26 +53,27 @@ def sql_insert(
|
||||
log.error('SQL INSERT statement could not be created. Missing params.')
|
||||
return False
|
||||
|
||||
trans = lib_sql_core.db.begin()
|
||||
trans = None
|
||||
try:
|
||||
result_insert = lib_sql_core.db.execute(sql_insert_stmt, data)
|
||||
trans.commit()
|
||||
with lib_sql_core.engine.connect() as conn:
|
||||
trans = conn.begin()
|
||||
result_insert = conn.execute(sql_insert_stmt, data)
|
||||
trans.commit()
|
||||
if result_insert.rowcount == 1 and result_insert.lastrowid > 0:
|
||||
return result_insert.lastrowid
|
||||
return False
|
||||
except IntegrityError as e:
|
||||
trans.rollback()
|
||||
if trans: trans.rollback()
|
||||
log.error('Integrity error (likely duplicate). Returning None')
|
||||
log.debug(e)
|
||||
set_last_sql_error(e)
|
||||
return None
|
||||
except Exception as e:
|
||||
trans.rollback()
|
||||
if trans: trans.rollback()
|
||||
log.error('Unknown exception in sql_insert. Returning False')
|
||||
log.exception(e)
|
||||
set_last_sql_error(e)
|
||||
return False
|
||||
else:
|
||||
if result_insert.rowcount == 1 and result_insert.lastrowid > 0:
|
||||
return result_insert.lastrowid
|
||||
return False
|
||||
# ### END ### API DB SQL ### sql_insert() ###
|
||||
|
||||
|
||||
@@ -123,29 +126,35 @@ def sql_update(
|
||||
else:
|
||||
return False
|
||||
|
||||
trans = lib_sql_core.db.begin()
|
||||
trans = None
|
||||
try:
|
||||
result_update = lib_sql_core.db.execute(sql_update_stmt, data)
|
||||
trans.commit()
|
||||
except OperationalError:
|
||||
trans.rollback()
|
||||
log.error('Operational error (gone away?). Retrying once...')
|
||||
sql_connect(current_db=lib_sql_core.db)
|
||||
try:
|
||||
result_update = lib_sql_core.db.execute(sql_update_stmt, data)
|
||||
with lib_sql_core.engine.connect() as conn:
|
||||
trans = conn.begin()
|
||||
result_update = conn.execute(sql_update_stmt, data)
|
||||
trans.commit()
|
||||
if result_update.rowcount >= 1:
|
||||
return True
|
||||
return None
|
||||
except OperationalError:
|
||||
if trans: trans.rollback()
|
||||
log.error('Operational error (gone away?). Retrying once...')
|
||||
sql_connect()
|
||||
try:
|
||||
with lib_sql_core.engine.connect() as conn:
|
||||
trans = conn.begin()
|
||||
result_update = conn.execute(sql_update_stmt, data)
|
||||
trans.commit()
|
||||
if result_update.rowcount >= 1:
|
||||
return True
|
||||
return None
|
||||
except Exception as e:
|
||||
set_last_sql_error(e)
|
||||
return False
|
||||
except Exception as e:
|
||||
trans.rollback()
|
||||
if trans: trans.rollback()
|
||||
log.exception(e)
|
||||
set_last_sql_error(e)
|
||||
return False
|
||||
else:
|
||||
if result_update.rowcount >= 1:
|
||||
return True
|
||||
return None
|
||||
# ### END ### API DB SQL ### sql_update() ###
|
||||
|
||||
|
||||
@@ -183,13 +192,15 @@ def sql_insert_or_update(
|
||||
else:
|
||||
return False
|
||||
|
||||
trans = lib_sql_core.db.begin()
|
||||
trans = None
|
||||
try:
|
||||
res = lib_sql_core.db.execute(stmt, data)
|
||||
trans.commit()
|
||||
return res.lastrowid if res.lastrowid > 0 else True
|
||||
with lib_sql_core.engine.connect() as conn:
|
||||
trans = conn.begin()
|
||||
res = conn.execute(stmt, data)
|
||||
trans.commit()
|
||||
return res.lastrowid if res.lastrowid > 0 else True
|
||||
except Exception as e:
|
||||
trans.rollback()
|
||||
if trans: trans.rollback()
|
||||
log.exception(e)
|
||||
return False
|
||||
# ### END ### Core Help CRUD ### sql_insert_or_update() ###
|
||||
@@ -286,18 +297,18 @@ def sql_select(
|
||||
else:
|
||||
return False
|
||||
|
||||
result = run_sql_select(sql=stmt, data=data)
|
||||
if not result:
|
||||
return [] if as_list else None
|
||||
|
||||
# Fetch all rows first to determine actual count reliably
|
||||
try:
|
||||
# Check if the result set actually contains rows before fetching
|
||||
if hasattr(result, 'returns_rows') and not result.returns_rows:
|
||||
log.warning("SQL Result does not return rows (ResourceClosedError prevented).")
|
||||
return [] if as_list else None
|
||||
|
||||
rows = result.all()
|
||||
with lib_sql_core.engine.connect() as conn:
|
||||
result = conn.execute(stmt, data)
|
||||
if not result:
|
||||
return [] if as_list else None
|
||||
|
||||
# Fetch all rows first to determine actual count reliably
|
||||
if hasattr(result, 'returns_rows') and not result.returns_rows:
|
||||
log.warning("SQL Result does not return rows (ResourceClosedError prevented).")
|
||||
return [] if as_list else None
|
||||
|
||||
rows = result.all()
|
||||
except Exception as e:
|
||||
log.error(f"SQL Fetch Error: {e}")
|
||||
set_last_sql_error(e)
|
||||
@@ -327,15 +338,15 @@ def run_sql_select(
|
||||
) -> Any:
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
# print(f"Executing SQL: {sql} with data: {data}", flush=True)
|
||||
|
||||
try:
|
||||
return lib_sql_core.db.execute(sql, data)
|
||||
with lib_sql_core.engine.connect() as conn:
|
||||
return conn.execute(sql, data)
|
||||
except (OperationalError, ProgrammingError) as e:
|
||||
log.error(f'DB Error: {e}. Retrying once...')
|
||||
sql_connect(current_db=lib_sql_core.db)
|
||||
sql_connect()
|
||||
try:
|
||||
return lib_sql_core.db.execute(sql, data)
|
||||
with lib_sql_core.engine.connect() as conn:
|
||||
return conn.execute(sql, data)
|
||||
except Exception as e2:
|
||||
set_last_sql_error(e2)
|
||||
raise e2 # RAISING instead of returning False
|
||||
@@ -372,8 +383,9 @@ def sql_delete(
|
||||
return False
|
||||
|
||||
try:
|
||||
result = lib_sql_core.db.execute(stmt, data) if data else lib_sql_core.db.execute(stmt)
|
||||
return True if result.rowcount >= 1 else None
|
||||
with lib_sql_core.engine.connect() as conn:
|
||||
result = conn.execute(stmt, data) if data else conn.execute(stmt)
|
||||
return True if result.rowcount >= 1 else None
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
return False
|
||||
|
||||
Reference in New Issue
Block a user