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