Working on Struct Save/Load

This commit is contained in:
Brian Buller 2023-05-31 17:36:34 -05:00
parent 0e0dff859f
commit de7d97d96b
3 changed files with 205 additions and 58 deletions

View File

@ -1,51 +1,98 @@
package boltease
import (
"errors"
"fmt"
"reflect"
)
func (b *DB) LoadStruct(path []string, dest interface{}) error {
return nil
type any interface{}
func (b *DB) LoadStruct(path []string, dest any) error {
destValue := reflect.ValueOf(dest)
if destValue.Kind().String() != "ptr" {
return errors.New("Destination must be a pointer")
}
d := reflect.Indirect(destValue)
if d.Kind().String() != "struct" {
path, name := path[:len(path)-1], path[len(path)-1]
return b.GetForInterface(path, name, dest)
}
entityType := reflect.TypeOf(dest).Elem()
fmt.Println("EntityType:", entityType.String())
var ret error
for i := 0; i < entityType.NumField(); i++ {
structFld := entityType.Field(i)
fldName := FieldName(structFld)
fmt.Printf("Field (%d): %s (%s)\n", i, fldName, structFld.Type)
switch structFld.Type.Kind() {
case reflect.String:
var wrk string
err := b.GetForInterface(path, fldName, &wrk)
if err != nil {
if ret == nil {
ret = err
}
} else {
// Set the value
}
case reflect.Bool:
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
}
err := b.GetForInterface(path, fldName, fld)
if err != nil {
fmt.Printf(" Err: %s\n", err.Error())
}
if err != nil && ret == nil {
ret = err
}
/*
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) SaveStruct(path []string, src interface{}) error {
func (b *DB) SaveStruct(path []string, src any) error {
t := reflect.TypeOf(src)
fields := reflect.VisibleFields(t)
// Build the PropertyList
var props PropertyList
for _, fld := range fields {
if FieldIgnored(fld) {
continue
r := reflect.ValueOf(src)
f := reflect.Indirect(r).FieldByName(fld.Name)
if err := b.Set(path, FieldName(fld), f); err != nil {
return err
}
p := Property{
Path: path,
Name: FieldName(fld),
Value: reflect.ValueOf(fld),
}
props = append(props, p)
}
return b.SavePropertyList(path, &props)
}
type Property struct {
Path []string
Name string
Value reflect.Value
}
func PropertyValueToInterface(val reflect.Value) interface{} {
if val.CanInterface() {
return val.Interface()
}
switch val.Kind() {
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()
}
return nil
}
func FieldName(fld reflect.StructField) string {
@ -60,24 +107,15 @@ func FieldIgnored(fld reflect.StructField) bool {
return fld.Tag.Get("boltease") == "-"
}
type PropertyList []Property
func (b *DB) LoadPropertyList(path []string) (*PropertyList, error) {
return nil, nil
}
func (b *DB) SavePropertyList(path []string, l *PropertyList) error {
// Make sure the path exists
err := b.MkBucketPath(path)
if err != nil {
return err
func ReflectValueToInterface(val reflect.Value) interface{} {
switch val.Kind() {
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()
}
for _, prop := range *l {
propPath := append(path, prop.Path...)
err = b.MkBucketPath(propPath)
if err != nil {
return err
}
b.Set(propPath, prop.Name, prop.Value)
}
return nil
}

View File

@ -2,7 +2,6 @@ package boltease
import (
"encoding/binary"
"errors"
"fmt"
"os"
"reflect"
@ -105,17 +104,86 @@ func (b *DB) MkBucketPath(path []string) error {
func (b *DB) Set(path []string, key string, val interface{}) error {
switch v := val.(type) {
case reflect.Value:
return b.Set(path, key, PropertyValueToInterface(v))
return b.Set(path, key, ReflectValueToInterface(v))
case string:
return b.SetString(path, key, v)
case int:
return b.SetInt(path, key, v)
case int8:
return b.SetInt(path, key, int(v))
case int16:
return b.SetInt(path, key, int(v))
case int32:
return b.SetInt(path, key, int(v))
case int64:
return b.SetInt(path, key, int(v))
case bool:
return b.SetBool(path, key, v)
case []byte:
return b.SetBytes(path, key, v)
default:
return fmt.Errorf("Unknown Data Type: %v", v)
}
return errors.New("Unknown Data Type")
}
func (b *DB) GetForInterface(path []string, key string, val interface{}) error {
var err error
switch v := val.(type) {
case *string:
*v, err = b.GetString(path, key)
case *int:
*v, err = b.GetInt(path, key)
case *int8:
var wrk int
wrk, err = b.GetInt(path, key)
*v = int8(wrk)
case *int16:
var wrk int
wrk, err = b.GetInt(path, key)
*v = int16(wrk)
case *int32:
var wrk int
wrk, err = b.GetInt(path, key)
*v = int32(wrk)
case *int64:
var wrk int
wrk, err = b.GetInt(path, key)
*v = int64(wrk)
case *bool:
*v, err = b.GetBool(path, key)
case *[]byte:
*v, err = b.GetBytes(path, key)
default:
return fmt.Errorf("Unknown Data Type: %v", v)
}
return err
}
func (b *DB) Load(path []string, key string, into interface{}) error {
var err error
switch v := into.(type) {
case string:
i := new(string)
*i, err = b.GetString(path, key)
fmt.Printf("Loading String: %v\n", i)
into = i
case int, int8, int16, int32, int64:
i := new(int)
*i, err = b.GetInt(path, key)
fmt.Printf("Loading Int: %v\n", i)
into = i
case bool:
i := new(bool)
*i, err = b.GetBool(path, key)
fmt.Printf("Loading Bool: %v\n", i)
into = i
case []byte:
i := new([]byte)
*i, err = b.GetBytes(path, key)
fmt.Printf("Loading []byte: %v\n", i)
into = i
default:
return fmt.Errorf("Unknown Data Type: %v", v)
}
return err
}
func (b *DB) GetBytes(path []string, key string) ([]byte, error) {

View File

@ -12,6 +12,10 @@ type ExampleType struct {
Age int `boltease:"age"`
}
func (e ExampleType) String() string {
return fmt.Sprintf("{\"Name\":\"%s\",\"Age\":%d}", e.Name, e.Age)
}
type ExampleSubType struct {
SubName string `boltease:"subname"`
}
@ -22,6 +26,35 @@ func main() {
fmt.Printf("Error Opening File: %s\n", err.Error())
os.Exit(1)
}
fmt.Println("# Example 1: Simple")
var v string
err = db.GetForInterface([]string{"examples", "example1"}, "name", &v)
if err != nil {
fmt.Println("Error:", err.Error())
}
fmt.Println("Name:", v)
var age int
err = db.GetForInterface([]string{"examples", "example1"}, "age", &age)
if err != nil {
fmt.Println("Error:", err.Error())
}
fmt.Println("Age:", age)
fmt.Println("")
fmt.Println("# Example 2: LoadStruct, simple")
var name string
err = db.LoadStruct(
[]string{"examples", "example1", "name"},
&name,
)
fmt.Println("Name:", name)
if err != nil {
fmt.Println("Err:", err)
}
fmt.Println("")
fmt.Println("# Example 3: Struct")
err = db.SaveStruct(
[]string{"examples", "example1"},
ExampleType{
@ -32,4 +65,12 @@ func main() {
fmt.Printf("Error saving struct: %s\n", err.Error())
os.Exit(1)
}
fmt.Println("Loading into Struct")
newStruct := ExampleType{}
err = db.LoadStruct(
[]string{"examples", "example1"},
&newStruct,
)
fmt.Println(newStruct)
}