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}