errors.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. // Package database provides database functionality
  2. package database
  3. import (
  4. "errors"
  5. "fmt"
  6. )
  7. // Common database error types
  8. var (
  9. // ErrInvalidConfig indicates missing or invalid database configuration
  10. ErrInvalidConfig = errors.New("invalid database configuration")
  11. // ErrConnectionFailed indicates failure to connect to the database
  12. ErrConnectionFailed = errors.New("failed to connect to database")
  13. // ErrQueryFailed indicates a query execution failure
  14. ErrQueryFailed = errors.New("query execution failed")
  15. // ErrTransactionFailed indicates a transaction operation failure
  16. ErrTransactionFailed = errors.New("transaction operation failed")
  17. // ErrMigrationFailed indicates a database migration failure
  18. ErrMigrationFailed = errors.New("database migration failed")
  19. // ErrPragmaFailed indicates failure to set database pragma
  20. ErrPragmaFailed = errors.New("failed to set database pragma")
  21. // ErrInvalidPath indicates an invalid database file path
  22. ErrInvalidPath = errors.New("invalid database path")
  23. // ErrDatabaseLocked indicates the database is locked
  24. ErrDatabaseLocked = errors.New("database is locked")
  25. // ErrNoRows indicates no rows were found
  26. ErrNoRows = errors.New("no rows found")
  27. // ErrDuplicateKey indicates a unique constraint violation
  28. ErrDuplicateKey = errors.New("duplicate key violation")
  29. )
  30. // Error represents a database-specific error with detailed context
  31. type Error struct {
  32. // Op is the operation that failed (e.g., "connect", "query", "migrate")
  33. Op string
  34. // Query is the SQL query that failed (if applicable)
  35. Query string
  36. // Err is the underlying error
  37. Err error
  38. // Details contains additional error context
  39. Details string
  40. }
  41. // Error returns a string representation of the error
  42. func (e *Error) Error() string {
  43. msg := fmt.Sprintf("database %s failed", e.Op)
  44. if e.Query != "" {
  45. // Truncate long queries in the error message
  46. const maxQueryLen = 100
  47. query := e.Query
  48. if len(query) > maxQueryLen {
  49. query = query[:maxQueryLen] + "..."
  50. }
  51. msg = fmt.Sprintf("%s for query %q", msg, query)
  52. }
  53. if e.Details != "" {
  54. msg = fmt.Sprintf("%s: %s", msg, e.Details)
  55. }
  56. if e.Err != nil {
  57. msg = fmt.Sprintf("%s: %v", msg, e.Err)
  58. }
  59. return msg
  60. }
  61. // Unwrap returns the underlying error
  62. func (e *Error) Unwrap() error {
  63. return e.Err
  64. }
  65. // Is reports whether target matches this error
  66. func (e *Error) Is(target error) bool {
  67. return errors.Is(e.Err, target)
  68. }
  69. // NewError creates a new database error
  70. func NewError(op string, err error, details string) *Error {
  71. return &Error{
  72. Op: op,
  73. Err: err,
  74. Details: details,
  75. }
  76. }
  77. // NewQueryError creates a new database error with query context
  78. func NewQueryError(op string, query string, err error, details string) *Error {
  79. return &Error{
  80. Op: op,
  81. Query: query,
  82. Err: err,
  83. Details: details,
  84. }
  85. }
  86. // IsLockError returns true if the error indicates a database lock
  87. func IsLockError(err error) bool {
  88. var e *Error
  89. return errors.As(err, &e) && errors.Is(e.Err, ErrDatabaseLocked)
  90. }
  91. // IsNotFoundError returns true if the error indicates no rows were found
  92. func IsNotFoundError(err error) bool {
  93. var e *Error
  94. return errors.As(err, &e) && errors.Is(e.Err, ErrNoRows)
  95. }
  96. // IsDuplicateError returns true if the error indicates a duplicate key
  97. func IsDuplicateError(err error) bool {
  98. var e *Error
  99. return errors.As(err, &e) && errors.Is(e.Err, ErrDuplicateKey)
  100. }