boltease/bolteasable.go

190 lines
4.7 KiB
Go

package boltease
import (
"errors"
"fmt"
"reflect"
)
type any interface{}
func (b *DB) Load(path []string, dest any) error {
destValue := reflect.ValueOf(dest)
fmt.Println("Loading:", path, destValue)
if destValue.Kind() != reflect.Pointer {
return errors.New("Destination must be a pointer")
}
d := reflect.Indirect(destValue)
fmt.Println(">> d.Kind() ->", d.Kind())
if d.Kind() != reflect.Struct {
fmt.Println(">> Kind != Struct; GetForInterface")
path, name := path[:len(path)-1], path[len(path)-1]
return b.GetForInterface(path, name, dest)
}
entityType := reflect.TypeOf(dest).Elem()
var ret error
for i := 0; i < entityType.NumField(); i++ {
structFld := entityType.Field(i)
fldName := FieldName(structFld)
fmt.Println("Loading Field:", fldName, "->", structFld.Type.Kind())
switch structFld.Type.Kind() {
case reflect.Pointer, reflect.Struct:
fmt.Println("Getting Pointer or Struct")
var wrk interface{}
var wrkV reflect.Value
if structFld.Type.Kind() == reflect.Pointer {
fmt.Println(" It's a pointer to something")
wrkV = reflect.New(structFld.Type).Elem()
} else {
fmt.Println(" It's a struct itself")
wrkV = reflect.New(reflect.TypeOf(structFld))
}
wrk = wrkV.Interface()
fmt.Println("-> Recurse (struct)", reflect.TypeOf(wrk))
err := b.Load(append(path, fldName), &wrk)
if err != nil {
fmt.Println("-> -> Error loading.", err.Error())
if ret == nil {
ret = err
}
} else {
// Set the value
reflect.ValueOf(dest).Elem().FieldByName(structFld.Name).Set(reflect.ValueOf(wrk))
}
case reflect.String:
fmt.Println("Getting String")
var wrk string
err := b.GetForInterface(path, fldName, &wrk)
if err != nil {
if ret == nil {
ret = err
}
} else {
// Set the value
reflect.ValueOf(dest).Elem().FieldByName(structFld.Name).Set(reflect.ValueOf(wrk))
}
case reflect.Bool:
fmt.Println("Getting Boolean")
var wrk bool
err := b.GetForInterface(path, fldName, &wrk)
if err != nil {
if ret == nil {
ret = err
}
} else {
// Set the value
reflect.ValueOf(dest).Elem().FieldByName(structFld.Name).Set(reflect.ValueOf(wrk))
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
fmt.Println("Getting Integer")
var wrk int
err := b.GetForInterface(path, fldName, &wrk)
if err != nil {
if ret == nil {
ret = err
}
} else {
// Set the value
reflect.ValueOf(dest).Elem().FieldByName(structFld.Name).Set(reflect.ValueOf(wrk))
}
}
/*
setField := reflect.ValueOf(dest).Elem().Field(i)
value := entityType.Field(i)
fldName := FieldName(value)
if value.Type.Kind() == reflect.Struct {
b.LoadStruct(append(path, fldName), setField.Interface())
} else {
err := b.GetForInterface(path, fldName, &value)
if err != nil {
fmt.Println(err)
return err
}
fmt.Println("value:", value)
}
*/
/*
if value.Type.Kind() == reflect.Struct {
b.LoadStruct(append(path, fldName), setField.Interface())
} else {
v, err := b.GetForType(path, fldName, value)
if err != nil {
return err
}
setField.Set(reflect.ValueOf(v))
}
*/
}
return ret
}
func (b *DB) Save(path []string, src any) error {
t := reflect.TypeOf(src)
if t.Kind() == reflect.Pointer {
// Save the actual struct
elem := reflect.ValueOf(src).Elem()
return b.Save(path, elem.Interface())
}
if t.Kind() == reflect.Struct {
fields := reflect.VisibleFields(t)
r := reflect.ValueOf(src)
for _, fld := range fields {
f := r.FieldByName(fld.Name)
if (f.Kind() == reflect.Struct || f.Kind() == reflect.Pointer) && f != src {
if f.CanInterface() {
err := b.Save(append(path, FieldName(fld)), f.Interface())
if err != nil {
return err
}
} else {
err := b.Save(append(path, FieldName(fld)), reflect.Indirect(f))
if err != nil {
return err
}
}
} else {
if err := b.Set(path, FieldName(fld), f); err != nil {
return err
}
}
}
} else {
return b.Set(path[:len(path)-1], path[len(path)-1], src)
}
return nil
}
func FieldName(fld reflect.StructField) string {
nm := fld.Name
tag := fld.Tag.Get("boltease")
if tag != "" {
nm = tag
}
return nm
}
func FieldIgnored(fld reflect.StructField) bool {
return fld.Tag.Get("boltease") == "-"
}
func ReflectValueToInterface(val reflect.Value) interface{} {
switch val.Kind() {
case reflect.Pointer:
return ReflectValueToInterface(reflect.Indirect(val))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return val.Int()
case reflect.Bool:
return val.Bool()
case reflect.String:
return val.String()
default:
return val.Bytes()
}
}