90 lines
2.5 KiB
Go
90 lines
2.5 KiB
Go
|
package exerr
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"go.mongodb.org/mongo-driver/bson"
|
||
|
"go.mongodb.org/mongo-driver/bson/bsoncodec"
|
||
|
"go.mongodb.org/mongo-driver/bson/bsonrw"
|
||
|
"go.mongodb.org/mongo-driver/bson/bsontype"
|
||
|
"reflect"
|
||
|
)
|
||
|
|
||
|
type ErrorCategory struct{ Category string }
|
||
|
|
||
|
var (
|
||
|
CatWrap = ErrorCategory{"Wrap"} // The error is simply wrapping another error (e.g. when a grpc call returns an error)
|
||
|
CatSystem = ErrorCategory{"System"} // An internal system error (e.g. connection to db failed)
|
||
|
CatUser = ErrorCategory{"User"} // The user (the API caller) did something wrong (e.g. he has no permissions to do this)
|
||
|
CatForeign = ErrorCategory{"Foreign"} // A foreign error that some component threw (e.g. an unknown mongodb error), happens if we call Wrap(..) on an non-bmerror value
|
||
|
)
|
||
|
|
||
|
func (e *ErrorCategory) UnmarshalJSON(bytes []byte) error {
|
||
|
return json.Unmarshal(bytes, &e.Category)
|
||
|
}
|
||
|
|
||
|
func (e ErrorCategory) MarshalJSON() ([]byte, error) {
|
||
|
return json.Marshal(e.Category)
|
||
|
}
|
||
|
|
||
|
func (e *ErrorCategory) UnmarshalBSONValue(bt bsontype.Type, data []byte) error {
|
||
|
if bt == bson.TypeNull {
|
||
|
// we can't set nil in UnmarshalBSONValue (so we use default(struct))
|
||
|
// Use mongoext.CreateGoExtBsonRegistry if you need to unmarsh pointer values
|
||
|
// https://stackoverflow.com/questions/75167597
|
||
|
// https://jira.mongodb.org/browse/GODRIVER-2252
|
||
|
*e = ErrorCategory{}
|
||
|
return nil
|
||
|
}
|
||
|
if bt != bson.TypeString {
|
||
|
return errors.New(fmt.Sprintf("cannot unmarshal %v into String", bt))
|
||
|
}
|
||
|
var tt string
|
||
|
err := bson.RawValue{Type: bt, Value: data}.Unmarshal(&tt)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
*e = ErrorCategory{tt}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (e ErrorCategory) MarshalBSONValue() (bsontype.Type, []byte, error) {
|
||
|
return bson.MarshalValue(e.Category)
|
||
|
}
|
||
|
|
||
|
func (e ErrorCategory) DecodeValue(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
|
||
|
if val.Kind() == reflect.Ptr && val.IsNil() {
|
||
|
if !val.CanSet() {
|
||
|
return errors.New("ValueUnmarshalerDecodeValue")
|
||
|
}
|
||
|
val.Set(reflect.New(val.Type().Elem()))
|
||
|
}
|
||
|
|
||
|
tp, src, err := bsonrw.Copier{}.CopyValueToBytes(vr)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if val.Kind() == reflect.Ptr && len(src) == 0 {
|
||
|
val.Set(reflect.Zero(val.Type()))
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
err = e.UnmarshalBSONValue(tp, src)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if val.Kind() == reflect.Ptr {
|
||
|
val.Set(reflect.ValueOf(&e))
|
||
|
} else {
|
||
|
val.Set(reflect.ValueOf(e))
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
//goland:noinspection GoUnusedGlobalVariable
|
||
|
var AllCategories = []ErrorCategory{CatWrap, CatSystem, CatUser, CatForeign}
|