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() }