Error Bubbling: Implement machine-readable rich error objects for CRUD operations

This commit is contained in:
Scott Idem
2026-01-19 17:01:58 -05:00
parent 19e64135ca
commit eeb19647f5
4 changed files with 70 additions and 13 deletions

View File

@@ -1,27 +1,58 @@
from typing import Any, Dict, Optional
from typing import Any, Dict, Optional, Union
import json
import logging
import re
from app.lib_general_v3 import AccountContext, StatusFilterParams
from app.models.error_models import StandardError
log = logging.getLogger(__name__)
def format_db_error(raw_error: str) -> str:
def format_db_error(raw_error: str) -> StandardError:
"""
Parses raw SQLAlchemy/MariaDB errors into user-friendly strings.
Parses raw SQLAlchemy/MariaDB errors into structured StandardError objects.
"""
if not raw_error:
return ""
return StandardError(
category="unknown",
message="An unspecified database error occurred."
)
# 1. Extract Error Code and Message using regex
# Standard MariaDB pattern: (code, "message")
match = re.search(r'\(\d+,\s*["\'](.*?)["\']\s*\)', raw_error)
if match:
return match.group(1).strip()
code = None
message = raw_error
recoverable = False
# Fallback: remove all (parenthesized) blocks which often contain codes
clean = re.sub(r'\(.*?\)', '', raw_error)
return clean.strip()
match = re.search(r'\((\d+),\s*["\'](.*?)["\']\s*\)', raw_error)
if match:
code = int(match.group(1))
message = match.group(2).strip()
else:
# Fallback: remove all (parenthesized) blocks which often contain codes
message = re.sub(r'\(.*?\)', '', raw_error).strip()
# 2. Categorize based on known MariaDB codes
# Ref: https://mariadb.com/kb/en/mariadb-error-codes/
if code in [1062]: # Duplicate Entry
category = "database_duplicate"
elif code in [1451, 1452]: # Foreign Key Constraint
category = "database_constraint"
elif code in [1045, 2002, 2003, 2006]: # Connection / Auth issues
category = "database_connection"
recoverable = True
elif code in [1054, 1146]: # Unknown column / Table
category = "database_schema"
else:
category = "database"
return StandardError(
category=category,
code=code,
message=message,
recoverable=recoverable,
details=raw_error if category == "database" else None # Only include raw details for uncategorized errors
)
def check_account_access(sql_result: Any, account: AccountContext, obj_name: str = None) -> bool:
"""