18
18
from __future__ import annotations
19
19
20
20
from abc import ABC , abstractmethod
21
+ from enum import Enum
21
22
from typing import Generic , TypeVar
22
23
23
24
from fastapi import HTTPException , Request , status
@@ -38,26 +39,46 @@ def exception_handler(self, request: Request, exc: T):
38
39
raise NotImplementedError
39
40
40
41
42
+ class _DatabaseDialect (Enum ):
43
+ SQLITE = "sqlite"
44
+ MYSQL = "mysql"
45
+ POSTGRES = "postgres"
46
+
47
+
41
48
class _UniqueConstraintErrorHandler (BaseErrorHandler [IntegrityError ]):
42
49
"""Exception raised when trying to insert a duplicate value in a unique column."""
43
50
51
+ unique_constraint_error_prefix_dict : dict [_DatabaseDialect , str ] = {
52
+ _DatabaseDialect .SQLITE : "UNIQUE constraint failed" ,
53
+ _DatabaseDialect .MYSQL : "Duplicate entry" ,
54
+ _DatabaseDialect .POSTGRES : "violates unique constraint" ,
55
+ }
56
+
44
57
def __init__ (self ):
45
58
super ().__init__ (IntegrityError )
46
- self .unique_constraint_error_messages = [
47
- "UNIQUE constraint failed" , # SQLite
48
- "Duplicate entry" , # MySQL
49
- "violates unique constraint" , # PostgreSQL
50
- ]
59
+ self .dialect : _DatabaseDialect .value | None = None
51
60
52
61
def exception_handler (self , request : Request , exc : IntegrityError ):
53
62
"""Handle IntegrityError exception."""
54
- exc_orig_str = str (exc .orig )
55
- if any (error_msg in exc_orig_str for error_msg in self .unique_constraint_error_messages ):
63
+ if self ._is_dialect_matched (exc ):
56
64
raise HTTPException (
57
65
status_code = status .HTTP_409_CONFLICT ,
58
- detail = "Unique constraint violation" ,
66
+ detail = {
67
+ "reason" : "Unique constraint violation" ,
68
+ "statement" : str (exc .statement ),
69
+ "orig_error" : str (exc .orig ),
70
+ },
59
71
)
60
72
73
+ def _is_dialect_matched (self , exc : IntegrityError ) -> bool :
74
+ """Check if the exception matches the unique constraint error message for any dialect."""
75
+ exc_orig_str = str (exc .orig )
76
+ for dialect , error_msg in self .unique_constraint_error_prefix_dict .items ():
77
+ if error_msg in exc_orig_str :
78
+ self .dialect = dialect
79
+ return True
80
+ return False
81
+
61
82
62
83
DatabaseErrorHandlers = [
63
84
_UniqueConstraintErrorHandler (),
0 commit comments