diamond-orm/util.go

195 lines
4.1 KiB
Go

package orm
import (
"fmt"
"go.mongodb.org/mongo-driver/bson/primitive"
"reflect"
"regexp"
"strconv"
"strings"
)
func panik(err error) {
if err != nil {
panic(err)
}
}
func nameOf(i interface{}) string {
v := reflect.ValueOf(i)
var n string
switch v.Kind() {
case reflect.Slice, reflect.Map:
if v.Type().Elem().Kind() == reflect.Pointer {
n = v.Type().Elem().Elem().Name()
}
case reflect.Pointer:
n = nameOf(reflect.Indirect(v).Interface())
default:
n = v.Type().Name()
}
return n
}
func valueOf(i interface{}) reflect.Value {
v := reflect.ValueOf(i)
if v.Type().Kind() == reflect.Pointer {
v = valueOf(reflect.Indirect(v).Interface())
}
return v
}
func coerceInt(input reflect.Value, dst reflect.Value) interface{} {
if input.Type().Kind() == reflect.Pointer {
input = input.Elem()
}
if dst.Type().Kind() == reflect.Pointer {
dst = dst.Elem()
}
if input.Type().ConvertibleTo(dst.Type()) {
return input.Convert(dst.Type()).Interface()
}
return nil
}
var arrRegex, _ = regexp.Compile(`\[(?P<index>\d+)]$`)
func getNested(field string, aValue reflect.Value) (*reflect.Type, *reflect.Value, error) {
if strings.HasPrefix(field, ".") || strings.HasSuffix(field, ".") {
return nil, nil, fmt.Errorf(errFmtMalformedField, field)
}
value := aValue
if value.Kind() == reflect.Pointer {
value = value.Elem()
}
aft := value.Type()
dots := strings.Split(field, ".")
if value.Kind() != reflect.Struct {
if value.Kind() == reflect.Slice {
st := reflect.MakeSlice(value.Type().Elem(), 0, 0)
for i := 0; i < value.Len(); i++ {
cur := value.Index(i)
if len(dots) > 1 {
_, cv, _ := getNested(strings.Join(dots[1:], "."), cur.FieldByName(dots[0]))
reflect.Append(st, *cv)
//return getNested(, "."), fv)
} else {
reflect.Append(st, cur)
}
}
typ := st.Type().Elem()
return &typ, &st, nil
}
if len(dots) > 1 {
return nil, nil, ErrNotSliceOrStruct
} else {
return &aft, &value, nil
}
}
ref := value
if ref.Kind() == reflect.Pointer {
ref = ref.Elem()
}
var fv = ref.FieldByName(arrRegex.ReplaceAllString(dots[0], ""))
if arrRegex.FindString(dots[0]) != "" && fv.Kind() == reflect.Slice {
matches := arrRegex.FindStringSubmatch(dots[0])
ridx, _ := strconv.Atoi(matches[0])
idx := ridx
fv = fv.Index(idx)
}
ft, _ := ref.Type().FieldByName(arrRegex.ReplaceAllString(dots[0], ""))
if len(dots) > 1 {
return getNested(strings.Join(dots[1:], "."), fv)
} else {
return &ft.Type, &fv, nil
}
}
func makeSettable(rval reflect.Value, value interface{}) reflect.Value {
if !rval.CanSet() {
nv := reflect.New(rval.Type())
nv.Elem().Set(reflect.ValueOf(value))
return nv
}
return rval
}
func incrementInterface(t interface{}) interface{} {
switch pt := t.(type) {
case uint:
t = pt + 1
case uint32:
t = pt + 1
case uint64:
t = pt + 1
case int:
t = pt + 1
case int32:
t = pt + 1
case int64:
t = pt + 1
case string:
t = NextStringID()
case primitive.ObjectID:
t = primitive.NewObjectID()
default:
panic(ErrUnsupportedID)
}
return t
}
func pull(s reflect.Value, idx int, typ reflect.Type) reflect.Value {
retI := reflect.New(reflect.SliceOf(typ))
for i := 0; i < s.Len(); i++ {
if i == idx {
continue
}
retI.Elem().Set(reflect.Append(retI.Elem(), s.Index(i)))
}
return retI.Elem()
}
func checkStruct(ref reflect.Value) error {
if ref.Kind() == reflect.Slice {
return ErrAppendMultipleDocuments
}
if ref.Kind() != reflect.Struct {
return ErrNotAStruct
}
return nil
}
func checkSlice(ref reflect.Value) error {
if ref.Kind() != reflect.Slice {
return ErrNotASlice
}
return nil
}
func convertSlice[In, Out any](in []In) []Out {
out := make([]Out, 0)
for _, i := range in {
ii, ok := any(i).(Out)
if ok {
out = append(out, ii)
}
}
return out
}
func normalizeSliceToDocumentSlice(in any) *DocumentSlice {
ret := make(DocumentSlice, 0)
val := reflect.ValueOf(in)
if val.Kind() == reflect.Pointer {
val = val.Elem()
}
if val.Kind() == reflect.Slice {
for i := 0; i < val.Len(); i++ {
if idoc, ok := val.Index(i).Interface().(IDocument); ok {
ret = append(ret, idoc)
}
}
}
return &ret
}