Error Bubbling: Implement machine-readable rich error objects for CRUD operations
This commit is contained in:
@@ -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:
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user