326 lines
8.8 KiB
Go
326 lines
8.8 KiB
Go
package errors
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
)
|
|
|
|
// ErrorCode 错误码
|
|
type ErrorCode int
|
|
|
|
const (
|
|
// 成功
|
|
ErrOK ErrorCode = iota
|
|
|
|
// 通用错误 (1000-1999)
|
|
ErrInternalError
|
|
ErrInvalidRequest
|
|
ErrNotImplemented
|
|
|
|
// 数据库错误 (2000-2999)
|
|
ErrDatabaseError
|
|
ErrCollectionNotFound
|
|
ErrDocumentNotFound
|
|
ErrDuplicateKey
|
|
ErrWriteConflict
|
|
ErrReadConflict
|
|
|
|
// 查询错误 (3000-3999)
|
|
ErrQueryParseError
|
|
ErrQueryExecutionError
|
|
ErrInvalidOperator
|
|
ErrInvalidExpression
|
|
ErrTypeMismatch
|
|
|
|
// 聚合错误 (4000-4999)
|
|
ErrAggregationError
|
|
ErrPipelineError
|
|
ErrStageError
|
|
ErrGroupError
|
|
ErrSortError
|
|
|
|
// 索引错误 (5000-5999)
|
|
ErrIndexError
|
|
ErrIndexNotFound
|
|
ErrIndexOptionsError
|
|
|
|
// 事务错误 (6000-6999)
|
|
ErrTransactionError
|
|
ErrTransactionAbort
|
|
ErrTransactionCommit
|
|
|
|
// 认证授权错误 (7000-7999)
|
|
ErrAuthenticationError
|
|
ErrAuthorizationError
|
|
ErrPermissionDenied
|
|
|
|
// 资源错误 (8000-8999)
|
|
ErrResourceNotFound
|
|
ErrResourceExhausted
|
|
ErrTimeout
|
|
ErrUnavailable
|
|
)
|
|
|
|
// GomogError Gomog 错误类型
|
|
type GomogError struct {
|
|
Code ErrorCode `json:"code"`
|
|
Message string `json:"message"`
|
|
Details string `json:"details,omitempty"`
|
|
Cause error `json:"-"`
|
|
Metadata map[string]string `json:"metadata,omitempty"`
|
|
HTTPStatus int `json:"-"`
|
|
}
|
|
|
|
func (e *GomogError) Error() string {
|
|
if e.Cause != nil {
|
|
return fmt.Sprintf("[%d] %s: %v", e.Code, e.Message, e.Cause)
|
|
}
|
|
if e.Details != "" {
|
|
return fmt.Sprintf("[%d] %s: %s", e.Code, e.Message, e.Details)
|
|
}
|
|
return fmt.Sprintf("[%d] %s", e.Code, e.Message)
|
|
}
|
|
|
|
func (e *GomogError) Unwrap() error {
|
|
return e.Cause
|
|
}
|
|
|
|
// WithDetails 添加详细信息
|
|
func (e *GomogError) WithDetails(details string) *GomogError {
|
|
e.Details = details
|
|
return e
|
|
}
|
|
|
|
// WithMetadata 添加元数据
|
|
func (e *GomogError) WithMetadata(key, value string) *GomogError {
|
|
if e.Metadata == nil {
|
|
e.Metadata = make(map[string]string)
|
|
}
|
|
e.Metadata[key] = value
|
|
return e
|
|
}
|
|
|
|
// WithHTTPStatus 设置 HTTP 状态码
|
|
func (e *GomogError) WithHTTPStatus(status int) *GomogError {
|
|
e.HTTPStatus = status
|
|
return e
|
|
}
|
|
|
|
// GetHTTPStatus 获取 HTTP 状态码
|
|
func (e *GomogError) GetHTTPStatus() int {
|
|
if e.HTTPStatus != 0 {
|
|
return e.HTTPStatus
|
|
}
|
|
// 根据错误码返回默认 HTTP 状态码
|
|
switch e.Code {
|
|
case ErrOK:
|
|
return http.StatusOK
|
|
case ErrInternalError, ErrDatabaseError, ErrAggregationError:
|
|
return http.StatusInternalServerError
|
|
case ErrInvalidRequest, ErrQueryParseError, ErrInvalidOperator, ErrTypeMismatch:
|
|
return http.StatusBadRequest
|
|
case ErrCollectionNotFound, ErrDocumentNotFound, ErrResourceNotFound:
|
|
return http.StatusNotFound
|
|
case ErrDuplicateKey, ErrWriteConflict:
|
|
return http.StatusConflict
|
|
case ErrPermissionDenied, ErrAuthorizationError:
|
|
return http.StatusForbidden
|
|
case ErrAuthenticationError:
|
|
return http.StatusUnauthorized
|
|
case ErrTimeout:
|
|
return http.StatusRequestTimeout
|
|
case ErrUnavailable:
|
|
return http.StatusServiceUnavailable
|
|
default:
|
|
return http.StatusInternalServerError
|
|
}
|
|
}
|
|
|
|
// 预定义错误 - 通用错误 (1000-1999)
|
|
var (
|
|
ErrInternal = &GomogError{Code: ErrInternalError, Message: "internal error"}
|
|
ErrInvalidReq = &GomogError{Code: ErrInvalidRequest, Message: "invalid request"}
|
|
ErrNotImpl = &GomogError{Code: ErrNotImplemented, Message: "not implemented"}
|
|
)
|
|
|
|
// 预定义错误 - 数据库错误 (2000-2999)
|
|
var (
|
|
ErrCollectionNotFnd = &GomogError{Code: ErrCollectionNotFound, Message: "collection not found"}
|
|
ErrDocumentNotFnd = &GomogError{Code: ErrDocumentNotFound, Message: "document not found"}
|
|
ErrDuplicate = &GomogError{Code: ErrDuplicateKey, Message: "duplicate key"}
|
|
ErrDatabase = &GomogError{Code: ErrDatabaseError, Message: "database error"}
|
|
ErrWriteConf = &GomogError{Code: ErrWriteConflict, Message: "write conflict"}
|
|
ErrReadConf = &GomogError{Code: ErrReadConflict, Message: "read conflict"}
|
|
)
|
|
|
|
// 预定义错误 - 查询错误 (3000-3999)
|
|
var (
|
|
ErrQueryParse = &GomogError{Code: ErrQueryParseError, Message: "query parse error"}
|
|
ErrQueryExec = &GomogError{Code: ErrQueryExecutionError, Message: "query execution error"}
|
|
ErrInvalidOp = &GomogError{Code: ErrInvalidOperator, Message: "invalid operator"}
|
|
ErrInvalidExpr = &GomogError{Code: ErrInvalidExpression, Message: "invalid expression"}
|
|
ErrTypeMis = &GomogError{Code: ErrTypeMismatch, Message: "type mismatch"}
|
|
)
|
|
|
|
// 预定义错误 - 聚合错误 (4000-4999)
|
|
var (
|
|
ErrAggregation = &GomogError{Code: ErrAggregationError, Message: "aggregation error"}
|
|
ErrPipeline = &GomogError{Code: ErrPipelineError, Message: "pipeline error"}
|
|
ErrStage = &GomogError{Code: ErrStageError, Message: "stage error"}
|
|
ErrGroup = &GomogError{Code: ErrGroupError, Message: "group error"}
|
|
ErrSort = &GomogError{Code: ErrSortError, Message: "sort error"}
|
|
)
|
|
|
|
// 预定义错误 - 索引错误 (5000-5999)
|
|
var (
|
|
ErrIndex = &GomogError{Code: ErrIndexError, Message: "index error"}
|
|
ErrIndexNotFnd = &GomogError{Code: ErrIndexNotFound, Message: "index not found"}
|
|
ErrIndexOpts = &GomogError{Code: ErrIndexOptionsError, Message: "index options error"}
|
|
)
|
|
|
|
// 预定义错误 - 事务错误 (6000-6999)
|
|
var (
|
|
ErrTransaction = &GomogError{Code: ErrTransactionError, Message: "transaction error"}
|
|
ErrTransAbort = &GomogError{Code: ErrTransactionAbort, Message: "transaction aborted"}
|
|
ErrTransCommit = &GomogError{Code: ErrTransactionCommit, Message: "transaction commit error"}
|
|
)
|
|
|
|
// 预定义错误 - 认证授权错误 (7000-7999)
|
|
var (
|
|
ErrAuthentication = &GomogError{Code: ErrAuthenticationError, Message: "authentication error"}
|
|
ErrAuthorization = &GomogError{Code: ErrAuthorizationError, Message: "authorization error"}
|
|
ErrPermDenied = &GomogError{Code: ErrPermissionDenied, Message: "permission denied"}
|
|
)
|
|
|
|
// 预定义错误 - 资源错误 (8000-8999)
|
|
var (
|
|
ErrResourceNotFnd = &GomogError{Code: ErrResourceNotFound, Message: "resource not found"}
|
|
ErrResourceExhaust = &GomogError{Code: ErrResourceExhausted, Message: "resource exhausted"}
|
|
ErrTimeoutErr = &GomogError{Code: ErrTimeout, Message: "timeout"}
|
|
ErrUnavailableErr = &GomogError{Code: ErrUnavailable, Message: "service unavailable"}
|
|
)
|
|
|
|
// New 创建新错误
|
|
func New(code ErrorCode, message string) *GomogError {
|
|
return &GomogError{
|
|
Code: code,
|
|
Message: message,
|
|
}
|
|
}
|
|
|
|
// Newf 创建带格式化的新错误
|
|
func Newf(code ErrorCode, format string, args ...interface{}) *GomogError {
|
|
return &GomogError{
|
|
Code: code,
|
|
Message: fmt.Sprintf(format, args...),
|
|
}
|
|
}
|
|
|
|
// Wrap 包装错误
|
|
func Wrap(err error, code ErrorCode, message string) *GomogError {
|
|
return &GomogError{
|
|
Code: code,
|
|
Message: message,
|
|
Cause: err,
|
|
}
|
|
}
|
|
|
|
// Wrapf 包装错误并添加格式化消息
|
|
func Wrapf(err error, code ErrorCode, format string, args ...interface{}) *GomogError {
|
|
return &GomogError{
|
|
Code: code,
|
|
Message: fmt.Sprintf(format, args...),
|
|
Cause: err,
|
|
}
|
|
}
|
|
|
|
// Is 判断错误是否为目标类型
|
|
func (e *GomogError) Is(target error) bool {
|
|
if te, ok := target.(*GomogError); ok {
|
|
return e.Code == te.Code
|
|
}
|
|
return false
|
|
}
|
|
|
|
// IsCollectionNotFound 判断是否是集合不存在错误
|
|
func IsCollectionNotFound(err error) bool {
|
|
if e, ok := err.(*GomogError); ok {
|
|
return e.Code == ErrCollectionNotFound
|
|
}
|
|
return false
|
|
}
|
|
|
|
// IsDocumentNotFound 判断是否是文档不存在错误
|
|
func IsDocumentNotFound(err error) bool {
|
|
if e, ok := err.(*GomogError); ok {
|
|
return e.Code == ErrDocumentNotFound
|
|
}
|
|
return false
|
|
}
|
|
|
|
// IsDuplicateKey 判断是否是重复键错误
|
|
func IsDuplicateKey(err error) bool {
|
|
if e, ok := err.(*GomogError); ok {
|
|
return e.Code == ErrDuplicateKey
|
|
}
|
|
return false
|
|
}
|
|
|
|
// IsInvalidRequest 判断是否是无效请求错误
|
|
func IsInvalidRequest(err error) bool {
|
|
if e, ok := err.(*GomogError); ok {
|
|
return e.Code == ErrInvalidRequest
|
|
}
|
|
return false
|
|
}
|
|
|
|
// IsTypeMismatch 判断是否是类型不匹配错误
|
|
func IsTypeMismatch(err error) bool {
|
|
if e, ok := err.(*GomogError); ok {
|
|
return e.Code == ErrTypeMismatch
|
|
}
|
|
return false
|
|
}
|
|
|
|
// IsTimeout 判断是否是超时错误
|
|
func IsTimeout(err error) bool {
|
|
if e, ok := err.(*GomogError); ok {
|
|
return e.Code == ErrTimeout
|
|
}
|
|
return false
|
|
}
|
|
|
|
// GetErrorCode 获取错误码
|
|
func GetErrorCode(err error) ErrorCode {
|
|
if e, ok := err.(*GomogError); ok {
|
|
return e.Code
|
|
}
|
|
return ErrInternalError
|
|
}
|
|
|
|
// GetErrorMessage 获取错误消息
|
|
func GetErrorMessage(err error) string {
|
|
if e, ok := err.(*GomogError); ok {
|
|
return e.Message
|
|
}
|
|
return err.Error()
|
|
}
|
|
|
|
// ToHTTPStatus 将错误转换为 HTTP 状态码
|
|
func ToHTTPStatus(err error) int {
|
|
if e, ok := err.(*GomogError); ok {
|
|
return e.GetHTTPStatus()
|
|
}
|
|
return http.StatusInternalServerError
|
|
}
|
|
|
|
// Equal 判断两个错误是否相等
|
|
func Equal(err1, err2 error) bool {
|
|
if e1, ok := err1.(*GomogError); ok {
|
|
if e2, ok := err2.(*GomogError); ok {
|
|
return e1.Code == e2.Code && e1.Message == e2.Message
|
|
}
|
|
}
|
|
return err1 == err2
|
|
}
|