|
| 1 | +package end_user_errors |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | +) |
| 6 | + |
| 7 | +// EndUserError This represents an error that can be shown to the end user. |
| 8 | +type EndUserError struct { |
| 9 | + errorType *ErrorType |
| 10 | + details string |
| 11 | + internalDetails string |
| 12 | + originError error // this can be nil |
| 13 | +} |
| 14 | + |
| 15 | +// Error this is the error interface implementation. This message is logged in the logs. |
| 16 | +func (e *EndUserError) Error() string { |
| 17 | + |
| 18 | + details := "" |
| 19 | + |
| 20 | + if e.internalDetails != "" { |
| 21 | + details = fmt.Sprintf("%s %s", details, e.internalDetails) |
| 22 | + } |
| 23 | + |
| 24 | + if e.details != "" { |
| 25 | + details += e.details |
| 26 | + } |
| 27 | + |
| 28 | + if e.originError == nil { |
| 29 | + return fmt.Sprintf("%s %s", e.errorType.String(), details) |
| 30 | + } else { |
| 31 | + return fmt.Sprintf("%s %s: %s", e.errorType.String(), details, e.originError) |
| 32 | + } |
| 33 | +} |
| 34 | + |
| 35 | +// Reason returns message logged in to reason field |
| 36 | +func (e *EndUserError) Reason() string { |
| 37 | + return e.errorType.Message |
| 38 | +} |
| 39 | + |
| 40 | +// EndUserErrorMessage returns the error message that can be shown to the end user. |
| 41 | +func (e *EndUserError) EndUserErrorMessage() string { |
| 42 | + return fmt.Sprintf("%s%s", e.errorType.String(), e.details) |
| 43 | +} |
| 44 | + |
| 45 | +// Details sets details about the error. It will be available for end user. |
| 46 | +func (e *EndUserError) Details(format string, args ...any) *EndUserError { |
| 47 | + e.details = fmt.Sprintf(format, args...) |
| 48 | + return e |
| 49 | +} |
| 50 | + |
| 51 | +// InternalDetails sets our internal details. |
| 52 | +func (e *EndUserError) InternalDetails(format string, args ...any) *EndUserError { |
| 53 | + e.internalDetails = fmt.Sprintf(format, args...) |
| 54 | + return e |
| 55 | +} |
| 56 | + |
| 57 | +type ErrorType struct { |
| 58 | + Number int |
| 59 | + Message string |
| 60 | +} |
| 61 | + |
| 62 | +func (t *ErrorType) String() string { |
| 63 | + return fmt.Sprintf("Q%04d: %s", t.Number, t.Message) |
| 64 | +} |
| 65 | + |
| 66 | +// New create an error instance based on the error type. |
| 67 | +func (t *ErrorType) New(err error) *EndUserError { |
| 68 | + return &EndUserError{ |
| 69 | + errorType: t, |
| 70 | + originError: err, |
| 71 | + } |
| 72 | +} |
| 73 | + |
| 74 | +func errorType(number int, message string) *ErrorType { |
| 75 | + return &ErrorType{Number: number, Message: message} |
| 76 | +} |
| 77 | + |
| 78 | +// Error type numbers follow the pattern QXXXX |
| 79 | +// Where |
| 80 | +// Q1XXX - Preprocessing errors (related to HTTP requests, JSON parsing, etc.) |
| 81 | +// Q2XXX - Query processing errors. Query translation etc. |
| 82 | +// Q3XXX - Errors related to external storages like Clickhouse, Elasticsearch, etc. |
| 83 | +// Q4XXX - Errors related to other internal components telemetry, etc. |
| 84 | + |
| 85 | +var ErrSearchCondition = errorType(2001, "Not supported search condition.") |
| 86 | +var ErrNoSuchTable = errorType(2002, "Missing table.") |
| 87 | + |
| 88 | +var ErrDatabaseTableNotFound = errorType(3001, "Table not found in database.") |
| 89 | +var ErrDatabaseFieldNotFound = errorType(3002, "Field not found in database.") |
| 90 | +var ErrDatabaseConnectionError = errorType(3003, "Error connecting to database.") |
| 91 | +var ErrDatabaseQueryError = errorType(3004, "Error executing query in database.") |
| 92 | +var ErrDatabaseAuthenticationError = errorType(3005, "Error authenticating with database.") |
| 93 | +var ErrDatabaseOtherError = errorType(3006, "Unspecified database error.") |
0 commit comments