diff --git a/exerr/data.go b/exerr/data.go index 17a4f6f..c103056 100644 --- a/exerr/data.go +++ b/exerr/data.go @@ -1,94 +1,14 @@ package exerr -import ( - "gogs.mikescher.com/BlackForestBytes/goext/dataext" - "gogs.mikescher.com/BlackForestBytes/goext/langext" +type Method string + +const ( + MethodOutput Method = "OUTPUT" + MethodPrint Method = "PRINT" + MethodBuild Method = "BUILD" + MethodFatal Method = "FATAL" ) -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 -) - -//goland:noinspection GoUnusedGlobalVariable -var AllCategories = []ErrorCategory{CatWrap, CatSystem, CatUser, CatForeign} - -type ErrorSeverity struct{ Severity string } - -var ( - SevTrace = ErrorSeverity{"Trace"} - SevDebug = ErrorSeverity{"Debug"} - SevInfo = ErrorSeverity{"Info"} - SevWarn = ErrorSeverity{"Warn"} - SevErr = ErrorSeverity{"Err"} - SevFatal = ErrorSeverity{"Fatal"} -) - -//goland:noinspection GoUnusedGlobalVariable -var AllSeverities = []ErrorSeverity{SevTrace, SevDebug, SevInfo, SevWarn, SevErr, SevFatal} - -type ErrorType struct { - Key string - DefaultStatusCode *int -} - -//goland:noinspection GoUnusedGlobalVariable -var ( - TypeInternal = NewType("INTERNAL_ERROR", langext.Ptr(500)) - TypePanic = NewType("PANIC", langext.Ptr(500)) - TypeNotImplemented = NewType("NOT_IMPLEMENTED", langext.Ptr(500)) - - TypeMongoQuery = NewType("MONGO_QUERY", langext.Ptr(500)) - TypeCursorTokenDecode = NewType("CURSOR_TOKEN_DECODE", langext.Ptr(500)) - TypeMongoFilter = NewType("MONGO_FILTER", langext.Ptr(500)) - TypeMongoReflection = NewType("MONGO_REFLECTION", langext.Ptr(500)) - TypeMongoInvalidOpt = NewType("MONGO_INVALIDOPT", langext.Ptr(500)) - - TypeSQLQuery = NewType("SQL_QUERY", langext.Ptr(500)) - TypeSQLBuild = NewType("SQL_BUILD", langext.Ptr(500)) - TypeSQLDecode = NewType("SQL_DECODE", langext.Ptr(500)) - - TypeWrap = NewType("Wrap", nil) - - TypeBindFailURI = NewType("BINDFAIL_URI", langext.Ptr(400)) - TypeBindFailQuery = NewType("BINDFAIL_QUERY", langext.Ptr(400)) - TypeBindFailJSON = NewType("BINDFAIL_JSON", langext.Ptr(400)) - TypeBindFailFormData = NewType("BINDFAIL_FORMDATA", langext.Ptr(400)) - TypeBindFailHeader = NewType("BINDFAIL_HEADER", langext.Ptr(400)) - - TypeMarshalEntityID = NewType("MARSHAL_ENTITY_ID", langext.Ptr(400)) - TypeInvalidCSID = NewType("INVALID_CSID", langext.Ptr(400)) - - TypeGoogleStatuscode = NewType("GOOGLE_STATUSCODE", langext.Ptr(400)) - TypeGoogleResponse = NewType("GOOGLE_RESPONSE", langext.Ptr(400)) - - TypeUnauthorized = NewType("UNAUTHORIZED", langext.Ptr(401)) - TypeAuthFailed = NewType("AUTH_FAILED", langext.Ptr(401)) - - TypeInvalidImage = NewType("IMAGEEXT_INVALID_IMAGE", langext.Ptr(400)) - TypeInvalidMimeType = NewType("IMAGEEXT_INVALID_MIMETYPE", langext.Ptr(400)) - - // other values come from the downstream application that uses goext -) - -var registeredTypes = dataext.SyncMap[string, ErrorType]{} - -func NewType(key string, defStatusCode *int) ErrorType { - et := ErrorType{key, defStatusCode} - - registeredTypes.Set(key, et) - - return et -} - -func ListRegisteredTypes() []ErrorType { - return registeredTypes.GetAllValues() -} - type LogPrintLevel string const ( diff --git a/exerr/dataCategory.go b/exerr/dataCategory.go new file mode 100644 index 0000000..f2aef8f --- /dev/null +++ b/exerr/dataCategory.go @@ -0,0 +1,89 @@ +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} diff --git a/exerr/dataSeverity.go b/exerr/dataSeverity.go new file mode 100644 index 0000000..18a6529 --- /dev/null +++ b/exerr/dataSeverity.go @@ -0,0 +1,91 @@ +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 ErrorSeverity struct{ Severity string } + +var ( + SevTrace = ErrorSeverity{"Trace"} + SevDebug = ErrorSeverity{"Debug"} + SevInfo = ErrorSeverity{"Info"} + SevWarn = ErrorSeverity{"Warn"} + SevErr = ErrorSeverity{"Err"} + SevFatal = ErrorSeverity{"Fatal"} +) + +func (e *ErrorSeverity) UnmarshalJSON(bytes []byte) error { + return json.Unmarshal(bytes, &e.Severity) +} + +func (e ErrorSeverity) MarshalJSON() ([]byte, error) { + return json.Marshal(e.Severity) +} + +func (e *ErrorSeverity) 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 = ErrorSeverity{} + 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 = ErrorSeverity{tt} + return nil +} + +func (e ErrorSeverity) MarshalBSONValue() (bsontype.Type, []byte, error) { + return bson.MarshalValue(e.Severity) +} + +func (e ErrorSeverity) 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 AllSeverities = []ErrorSeverity{SevTrace, SevDebug, SevInfo, SevWarn, SevErr, SevFatal} diff --git a/exerr/dataType.go b/exerr/dataType.go new file mode 100644 index 0000000..79700f1 --- /dev/null +++ b/exerr/dataType.go @@ -0,0 +1,155 @@ +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" + "gogs.mikescher.com/BlackForestBytes/goext/dataext" + "gogs.mikescher.com/BlackForestBytes/goext/langext" + "reflect" +) + +type ErrorType struct { + Key string + DefaultStatusCode *int +} + +//goland:noinspection GoUnusedGlobalVariable +var ( + TypeInternal = NewType("INTERNAL_ERROR", langext.Ptr(500)) + TypePanic = NewType("PANIC", langext.Ptr(500)) + TypeNotImplemented = NewType("NOT_IMPLEMENTED", langext.Ptr(500)) + + TypeMongoQuery = NewType("MONGO_QUERY", langext.Ptr(500)) + TypeCursorTokenDecode = NewType("CURSOR_TOKEN_DECODE", langext.Ptr(500)) + TypeMongoFilter = NewType("MONGO_FILTER", langext.Ptr(500)) + TypeMongoReflection = NewType("MONGO_REFLECTION", langext.Ptr(500)) + TypeMongoInvalidOpt = NewType("MONGO_INVALIDOPT", langext.Ptr(500)) + + TypeSQLQuery = NewType("SQL_QUERY", langext.Ptr(500)) + TypeSQLBuild = NewType("SQL_BUILD", langext.Ptr(500)) + TypeSQLDecode = NewType("SQL_DECODE", langext.Ptr(500)) + + TypeWrap = NewType("Wrap", nil) + + TypeBindFailURI = NewType("BINDFAIL_URI", langext.Ptr(400)) + TypeBindFailQuery = NewType("BINDFAIL_QUERY", langext.Ptr(400)) + TypeBindFailJSON = NewType("BINDFAIL_JSON", langext.Ptr(400)) + TypeBindFailFormData = NewType("BINDFAIL_FORMDATA", langext.Ptr(400)) + TypeBindFailHeader = NewType("BINDFAIL_HEADER", langext.Ptr(400)) + + TypeMarshalEntityID = NewType("MARSHAL_ENTITY_ID", langext.Ptr(400)) + TypeInvalidCSID = NewType("INVALID_CSID", langext.Ptr(400)) + + TypeGoogleStatuscode = NewType("GOOGLE_STATUSCODE", langext.Ptr(400)) + TypeGoogleResponse = NewType("GOOGLE_RESPONSE", langext.Ptr(400)) + + TypeUnauthorized = NewType("UNAUTHORIZED", langext.Ptr(401)) + TypeAuthFailed = NewType("AUTH_FAILED", langext.Ptr(401)) + + TypeInvalidImage = NewType("IMAGEEXT_INVALID_IMAGE", langext.Ptr(400)) + TypeInvalidMimeType = NewType("IMAGEEXT_INVALID_MIMETYPE", langext.Ptr(400)) + + // other values come from the downstream application that uses goext +) + +func (e *ErrorType) UnmarshalJSON(bytes []byte) error { + var k string + err := json.Unmarshal(bytes, &k) + if err != nil { + return err + } + + if d, ok := registeredTypes.Get(k); ok { + *e = d + return nil + } else { + *e = ErrorType{k, nil} + return nil + } +} + +func (e ErrorType) MarshalJSON() ([]byte, error) { + return json.Marshal(e.Key) +} + +func (e *ErrorType) 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 = ErrorType{} + 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 + } + + if d, ok := registeredTypes.Get(tt); ok { + *e = d + return nil + } else { + *e = ErrorType{tt, nil} + return nil + } +} + +func (e ErrorType) MarshalBSONValue() (bsontype.Type, []byte, error) { + return bson.MarshalValue(e.Key) +} + +func (e ErrorType) 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 +} + +var registeredTypes = dataext.SyncMap[string, ErrorType]{} + +func NewType(key string, defStatusCode *int) ErrorType { + et := ErrorType{key, defStatusCode} + + registeredTypes.Set(key, et) + + return et +} + +func ListRegisteredTypes() []ErrorType { + return registeredTypes.GetAllValues() +} diff --git a/exerr/data_test.go b/exerr/data_test.go new file mode 100644 index 0000000..4331008 --- /dev/null +++ b/exerr/data_test.go @@ -0,0 +1,153 @@ +package exerr + +import ( + "context" + "encoding/json" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "gogs.mikescher.com/BlackForestBytes/goext/tst" + "testing" + "time" +) + +func TestJSONMarshalErrorCategory(t *testing.T) { + + c1 := CatSystem + + jsonbin := tst.Must(json.Marshal(c1))(t) + + var c2 ErrorCategory + tst.AssertNoErr(t, json.Unmarshal(jsonbin, &c2)) + + tst.AssertEqual(t, c1, c2) + + tst.AssertEqual(t, string(jsonbin), "\"System\"") +} + +func TestJSONMarshalErrorSeverity(t *testing.T) { + + c1 := SevErr + + jsonbin := tst.Must(json.Marshal(c1))(t) + + var c2 ErrorSeverity + tst.AssertNoErr(t, json.Unmarshal(jsonbin, &c2)) + + tst.AssertEqual(t, c1, c2) + + tst.AssertEqual(t, string(jsonbin), "\"Err\"") +} + +func TestJSONMarshalErrorType(t *testing.T) { + + c1 := TypeNotImplemented + + jsonbin := tst.Must(json.Marshal(c1))(t) + + var c2 ErrorType + tst.AssertNoErr(t, json.Unmarshal(jsonbin, &c2)) + + tst.AssertEqual(t, c1, c2) + + tst.AssertEqual(t, string(jsonbin), "\"NOT_IMPLEMENTED\"") +} + +func TestBSONMarshalErrorCategory(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 350*time.Millisecond) + defer cancel() + + client, err := mongo.Connect(ctx) + if err != nil { + t.Skip("Skip test - no local mongo found") + return + } + err = client.Ping(ctx, nil) + if err != nil { + t.Skip("Skip test - no local mongo found") + return + } + + primimd := primitive.NewObjectID() + + _, err = client.Database("_test").Collection("goext-cicd").InsertOne(ctx, bson.M{"_id": primimd, "val": CatSystem}) + tst.AssertNoErr(t, err) + + cursor := client.Database("_test").Collection("goext-cicd").FindOne(ctx, bson.M{"_id": primimd, "val": bson.M{"$type": "string"}}) + + var c1 struct { + ID primitive.ObjectID `bson:"_id"` + Val ErrorCategory `bson:"val"` + } + + err = cursor.Decode(&c1) + tst.AssertNoErr(t, err) + + tst.AssertEqual(t, c1.Val, CatSystem) +} + +func TestBSONMarshalErrorSeverity(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 350*time.Millisecond) + defer cancel() + + client, err := mongo.Connect(ctx) + if err != nil { + t.Skip("Skip test - no local mongo found") + return + } + err = client.Ping(ctx, nil) + if err != nil { + t.Skip("Skip test - no local mongo found") + return + } + + primimd := primitive.NewObjectID() + + _, err = client.Database("_test").Collection("goext-cicd").InsertOne(ctx, bson.M{"_id": primimd, "val": SevErr}) + tst.AssertNoErr(t, err) + + cursor := client.Database("_test").Collection("goext-cicd").FindOne(ctx, bson.M{"_id": primimd, "val": bson.M{"$type": "string"}}) + + var c1 struct { + ID primitive.ObjectID `bson:"_id"` + Val ErrorSeverity `bson:"val"` + } + + err = cursor.Decode(&c1) + tst.AssertNoErr(t, err) + + tst.AssertEqual(t, c1.Val, SevErr) +} + +func TestBSONMarshalErrorType(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 350*time.Millisecond) + defer cancel() + + client, err := mongo.Connect(ctx) + if err != nil { + t.Skip("Skip test - no local mongo found") + return + } + err = client.Ping(ctx, nil) + if err != nil { + t.Skip("Skip test - no local mongo found") + return + } + + primimd := primitive.NewObjectID() + + _, err = client.Database("_test").Collection("goext-cicd").InsertOne(ctx, bson.M{"_id": primimd, "val": TypeNotImplemented}) + tst.AssertNoErr(t, err) + + cursor := client.Database("_test").Collection("goext-cicd").FindOne(ctx, bson.M{"_id": primimd, "val": bson.M{"$type": "string"}}) + + var c1 struct { + ID primitive.ObjectID `bson:"_id"` + Val ErrorType `bson:"val"` + } + + err = cursor.Decode(&c1) + tst.AssertNoErr(t, err) + + tst.AssertEqual(t, c1.Val, TypeNotImplemented) +} diff --git a/exerr/exerr_test.go b/exerr/exerr_test.go index ee98351..5242c72 100644 --- a/exerr/exerr_test.go +++ b/exerr/exerr_test.go @@ -2,10 +2,19 @@ package exerr import ( "errors" + "gogs.mikescher.com/BlackForestBytes/goext/langext" "gogs.mikescher.com/BlackForestBytes/goext/tst" + "os" "testing" ) +func TestMain(m *testing.M) { + if !Initialized() { + Init(ErrorPackageConfigInit{ZeroLogErrTraces: langext.PFalse, ZeroLogAllTraces: langext.PFalse}) + } + os.Exit(m.Run()) +} + type golangErr struct { Message string } diff --git a/exerr/listener.go b/exerr/listener.go index 8cd4002..54b4ea4 100644 --- a/exerr/listener.go +++ b/exerr/listener.go @@ -4,15 +4,6 @@ import ( "sync" ) -type Method string - -const ( - MethodOutput Method = "OUTPUT" - MethodPrint Method = "PRINT" - MethodBuild Method = "BUILD" - MethodFatal Method = "FATAL" -) - type Listener = func(method Method, v *ExErr) var listenerLock = sync.Mutex{} diff --git a/goextVersion.go b/goextVersion.go index 62112e6..0816697 100644 --- a/goextVersion.go +++ b/goextVersion.go @@ -1,5 +1,5 @@ package goext -const GoextVersion = "0.0.454" +const GoextVersion = "0.0.455" -const GoextVersionTimestamp = "2024-05-14T15:10:27+0200" +const GoextVersionTimestamp = "2024-05-16T15:38:42+0200" diff --git a/mongoext/registry.go b/mongoext/registry.go index d2cecf4..623415b 100644 --- a/mongoext/registry.go +++ b/mongoext/registry.go @@ -5,6 +5,7 @@ import ( "go.mongodb.org/mongo-driver/bson/bsoncodec" "go.mongodb.org/mongo-driver/bson/bsontype" "go.mongodb.org/mongo-driver/bson/primitive" + "gogs.mikescher.com/BlackForestBytes/goext/exerr" "gogs.mikescher.com/BlackForestBytes/goext/langext" "gogs.mikescher.com/BlackForestBytes/goext/rfctime" "reflect" @@ -34,6 +35,15 @@ func CreateGoExtBsonRegistry() *bsoncodec.Registry { rb.RegisterTypeDecoder(reflect.TypeOf(rfctime.SecondsF64(0)), rfctime.SecondsF64(0)) rb.RegisterTypeDecoder(reflect.TypeOf(langext.Ptr(rfctime.SecondsF64(0))), rfctime.SecondsF64(0)) + rb.RegisterTypeDecoder(reflect.TypeOf(exerr.ErrorCategory{}), exerr.ErrorCategory{}) + rb.RegisterTypeDecoder(reflect.TypeOf(langext.Ptr(exerr.ErrorCategory{})), exerr.ErrorCategory{}) + + rb.RegisterTypeDecoder(reflect.TypeOf(exerr.ErrorSeverity{}), exerr.ErrorSeverity{}) + rb.RegisterTypeDecoder(reflect.TypeOf(langext.Ptr(exerr.ErrorSeverity{})), exerr.ErrorSeverity{}) + + rb.RegisterTypeDecoder(reflect.TypeOf(exerr.ErrorType{}), exerr.ErrorType{}) + rb.RegisterTypeDecoder(reflect.TypeOf(langext.Ptr(exerr.ErrorType{})), exerr.ErrorType{}) + bsoncodec.DefaultValueEncoders{}.RegisterDefaultEncoders(rb) bsoncodec.DefaultValueDecoders{}.RegisterDefaultDecoders(rb)