package wmo import ( "errors" "fmt" "gogs.mikescher.com/BlackForestBytes/goext/langext" "reflect" "strconv" "time" ) func (c *Coll[TData]) init() { c.dataTypeMap = make(map[string]fullTypeRef[TData]) example := *new(TData) v := reflect.ValueOf(example) c.initFields("", v, make([]int, 0)) } func (c *Coll[TData]) initFields(prefix string, rval reflect.Value, idxarr []int) { rtyp := rval.Type() for i := 0; i < rtyp.NumField(); i++ { rsfield := rtyp.Field(i) rvfield := rval.Field(i) if !rsfield.IsExported() { continue } bsonkey, found := rsfield.Tag.Lookup("bson") if !found || bsonkey == "-" { continue } fullKey := prefix + bsonkey newIdxArr := langext.ArrCopy(idxarr) newIdxArr = append(newIdxArr, i) if rvfield.Type().Kind() == reflect.Pointer { c.dataTypeMap[fullKey] = fullTypeRef[TData]{ IsPointer: true, Kind: rvfield.Type().Elem().Kind(), Type: rvfield.Type().Elem(), UnderlyingType: langext.Underlying(rvfield.Type().Elem()), Name: rsfield.Name, Index: newIdxArr, } } else { c.dataTypeMap[fullKey] = fullTypeRef[TData]{ IsPointer: false, Kind: rvfield.Type().Kind(), Type: rvfield.Type(), UnderlyingType: langext.Underlying(rvfield.Type()), Name: rsfield.Name, Index: newIdxArr, } } if rvfield.Kind() == reflect.Struct { c.initFields(fullKey+".", rvfield, newIdxArr) } } } func (c *Coll[TData]) getTokenValueAsMongoType(value string, fieldName string) (any, error) { fref := c.dataTypeMap[fieldName] if fref.IsPointer && value == "" { pointertype := reflect.New(fref.Type).Type() nilvalue := reflect.Zero(pointertype) outvalue := nilvalue.Interface() return outvalue, nil } pointerize := func(v any) any { if !fref.IsPointer { return v } rval1 := reflect.ValueOf(v) rval2 := rval1.Convert(fref.Type) rval3 := reflect.New(fref.Type) rval3.Elem().Set(rval2) return rval3.Interface() } if fref.UnderlyingType == reflect.TypeOf("") { rt, ok := langext.TryCastType(value, fref.Type) if !ok { return nil, errors.New(fmt.Sprintf("failed to parse field '%s' from string to %s", fieldName, fref.Type.String())) } return pointerize(rt), nil } if fref.UnderlyingType == reflect.TypeOf(time.Time{}) { t, err := time.Parse(time.RFC3339Nano, value) if err != nil { return nil, errors.New(fmt.Sprintf("failed to parse field '%s' as time.Time ('%s')", fieldName, value)) } rt, ok := langext.TryCastType(t, fref.Type) if !ok { return nil, errors.New(fmt.Sprintf("failed to parse field '%s' from time.Time to %s", fieldName, fref.Type.String())) } return pointerize(rt), nil } if fref.UnderlyingType == reflect.TypeOf(int(0)) { t, err := strconv.ParseInt(value, 10, 64) if err != nil { return nil, errors.New(fmt.Sprintf("failed to parse field '%s' as int64 ('%s')", fieldName, value)) } rt, ok := langext.TryCastType(int(t), fref.Type) if !ok { return nil, errors.New(fmt.Sprintf("failed to parse field '%s' from int to %s", fieldName, fref.Type.String())) } return pointerize(rt), nil } if fref.UnderlyingType == reflect.TypeOf(int32(0)) { t, err := strconv.ParseInt(value, 10, 64) if err != nil { return nil, errors.New(fmt.Sprintf("failed to parse field '%s' as int32 ('%s')", fieldName, value)) } rt, ok := langext.TryCastType(int32(t), fref.Type) if !ok { return nil, errors.New(fmt.Sprintf("failed to parse field '%s' from int32 to %s", fieldName, fref.Type.String())) } return pointerize(rt), nil } if fref.UnderlyingType == reflect.TypeOf(int64(0)) { t, err := strconv.ParseInt(value, 10, 64) if err != nil { return nil, errors.New(fmt.Sprintf("failed to parse field '%s' as int64 ('%s')", fieldName, value)) } rt, ok := langext.TryCastType(int64(t), fref.Type) if !ok { return nil, errors.New(fmt.Sprintf("failed to parse field '%s' from int64 to %s", fieldName, fref.Type.String())) } return pointerize(rt), nil } if fref.UnderlyingType == reflect.TypeOf(float32(0)) { t, err := strconv.ParseFloat(value, 64) if err != nil { return nil, errors.New(fmt.Sprintf("failed to parse field '%s' as float32 ('%s')", fieldName, value)) } rt, ok := langext.TryCastType(float32(t), fref.Type) if !ok { return nil, errors.New(fmt.Sprintf("failed to parse field '%s' from float32 to %s", fieldName, fref.Type.String())) } return pointerize(rt), nil } if fref.UnderlyingType == reflect.TypeOf(float64(0)) { t, err := strconv.ParseFloat(value, 64) if err != nil { return nil, errors.New(fmt.Sprintf("failed to parse field '%s' as float64 ('%s')", fieldName, value)) } rt, ok := langext.TryCastType(float64(t), fref.Type) if !ok { return nil, errors.New(fmt.Sprintf("failed to parse field '%s' from float64 to %s", fieldName, fref.Type.String())) } return pointerize(rt), nil } return nil, errors.New(fmt.Sprintf("failed to parse field '%s' of type %s (%s)", fieldName, fref.Type.String(), fref.UnderlyingType.String())) } func (c *Coll[TData]) getFieldValueAsTokenString(entity TData, fieldName string) (string, error) { fref := c.dataTypeMap[fieldName] realValue := c.getFieldValue(entity, fieldName) if langext.IsNil(realValue) { return "", nil } reflValue := reflect.ValueOf(realValue) if reflValue.Kind() == reflect.Pointer { reflValue = reflValue.Elem() realValue = reflValue.Interface() } if fref.UnderlyingType == reflect.TypeOf("") { rt, ok := langext.TryCastType(realValue, reflect.TypeOf("")) if !ok { return "", errors.New(fmt.Sprintf("failed to cast field '%s' from %s to string", fieldName, fref.Type.String())) } return rt.(string), nil } if fref.UnderlyingType == reflect.TypeOf(time.Time{}) { rt, ok := langext.TryCastType(realValue, reflect.TypeOf(time.Time{})) if !ok { return "", errors.New(fmt.Sprintf("failed to cast field '%s' from %s to time.Time", fieldName, fref.Type.String())) } return rt.(time.Time).Format(time.RFC3339Nano), nil } if fref.UnderlyingType == reflect.TypeOf(int(0)) { rt, ok := langext.TryCastType(realValue, reflect.TypeOf(int(0))) if !ok { return "", errors.New(fmt.Sprintf("failed to cast field '%s' from %s to int", fieldName, fref.Type.String())) } return strconv.Itoa(rt.(int)), nil } if fref.UnderlyingType == reflect.TypeOf(int32(0)) { rt, ok := langext.TryCastType(realValue, reflect.TypeOf(int32(0))) if !ok { return "", errors.New(fmt.Sprintf("failed to cast field '%s' from %s to int32", fieldName, fref.Type.String())) } return strconv.FormatInt(int64(rt.(int32)), 10), nil } if fref.UnderlyingType == reflect.TypeOf(int64(0)) { rt, ok := langext.TryCastType(realValue, reflect.TypeOf(int64(0))) if !ok { return "", errors.New(fmt.Sprintf("failed to cast field '%s' from %s to int64", fieldName, fref.Type.String())) } return strconv.FormatInt(rt.(int64), 10), nil } if fref.UnderlyingType == reflect.TypeOf(float32(0)) { rt, ok := langext.TryCastType(realValue, reflect.TypeOf(float32(0))) if !ok { return "", errors.New(fmt.Sprintf("failed to cast field '%s' from %s to float32", fieldName, fref.Type.String())) } return strconv.FormatFloat(float64(rt.(float32)), 'f', -1, 32), nil } if fref.UnderlyingType == reflect.TypeOf(float64(0)) { rt, ok := langext.TryCastType(realValue, reflect.TypeOf(float64(0))) if !ok { return "", errors.New(fmt.Sprintf("failed to cast field '%s' from %s to float64", fieldName, fref.Type.String())) } return strconv.FormatFloat(rt.(float64), 'f', -1, 64), nil } return "", errors.New(fmt.Sprintf("failed to parse field '%s' of type %s (%s)", fieldName, fref.Type.String(), fref.UnderlyingType.String())) } func (c *Coll[TData]) getFieldType(fieldName string) fullTypeRef[TData] { return c.dataTypeMap[fieldName] } func (c *Coll[TData]) getFieldValue(data TData, fieldName string) any { fref := c.dataTypeMap[fieldName] rval := reflect.ValueOf(data) return rval.FieldByIndex(fref.Index).Interface() }