diff --git a/README.md b/README.md index d4a50e3..6f71335 100644 --- a/README.md +++ b/README.md @@ -1306,7 +1306,7 @@ translator.RegisterConverter("color", ColorConverter{}) ## Embeded Structs -If we want to group columns into a complex type (`struct`) we just have to tag the firld as `sql:"embeded"`. +If we want to group columns into a complex type (`struct`) we just have to tag the field as `sql:"embeded"`. This is handy when working with Value Objects. Consider the table diff --git a/db/entity_property.go b/db/entity_property.go index 4f4de8a..af088e9 100644 --- a/db/entity_property.go +++ b/db/entity_property.go @@ -9,7 +9,6 @@ import ( ) type EntityProperty struct { - FieldName string Position int Type reflect.Type InnerType reflect.Type @@ -30,25 +29,25 @@ func (e *EntityProperty) IsMany() bool { type setter func(instance reflect.Value) reflect.Value -func makeSetter(previous setter, fieldname string) setter { +func makeSetter(index []int) setter { return func(instance reflect.Value) reflect.Value { - if previous != nil { - instance = previous(instance) - } + for _, x := range index { + if instance.Kind() == reflect.Ptr { + if instance.IsNil() { + t := instance.Type().Elem() + val := reflect.New(t) + instance.Set(val) + } + instance = instance.Elem() + } - if instance.Kind() == reflect.Ptr { - if instance.IsNil() { - t := instance.Type().Elem() - val := reflect.New(t) - instance.Set(val) + instance = reflect.Indirect(instance).Field(x) + if !instance.CanSet() { + // Cheat: writting to unexported fields + instance = reflect.NewAt(instance.Type(), unsafe.Pointer(instance.UnsafeAddr())).Elem() } - instance = instance.Elem() - } - instance = reflect.Indirect(instance).FieldByName(fieldname) - if !instance.CanSet() { - // Cheat: writting to unexported fields - instance = reflect.NewAt(instance.Type(), unsafe.Pointer(instance.UnsafeAddr())).Elem() } + return instance } } @@ -72,15 +71,12 @@ func (e *EntityProperty) Set(instance reflect.Value, value reflect.Value) bool { type getter func(instance reflect.Value) reflect.Value -func makeGetter(previous getter, fieldname string) getter { +func makeGetter(index []int) getter { return func(instance reflect.Value) reflect.Value { - if previous != nil { - instance = previous(instance) - } if instance.Kind() == reflect.Ptr { instance = instance.Elem() } - instance = reflect.Indirect(instance).FieldByName(fieldname) + instance = reflect.Indirect(instance).FieldByIndex(index) if !instance.CanSet() && instance.CanAddr() { // Cheat: writting to unexported fields instance = reflect.NewAt(instance.Type(), unsafe.Pointer(instance.UnsafeAddr())).Elem() @@ -93,20 +89,16 @@ func (e *EntityProperty) Get(instance reflect.Value) reflect.Value { return e.getter(instance) } -func PopulateMappingOf(prefix string, m interface{}, translator Translator) (map[string]*EntityProperty, error) { - return PopulateMapping(prefix, reflect.TypeOf(m), translator) -} - func PopulateMapping(prefix string, typ reflect.Type, translator Translator) (map[string]*EntityProperty, error) { // create an attribute data structure as a map of types keyed by a string. attrs := make(map[string]*EntityProperty) - err := walkTreeStruct(prefix, typ, attrs, translator, nil, nil) + err := walkTreeStruct(prefix, typ, attrs, translator, nil) return attrs, err } -func walkTreeStruct(prefix string, typ reflect.Type, attrs map[string]*EntityProperty, translator Translator, prevGetter getter, prevSetter setter) error { +func walkTreeStruct(prefix string, typ reflect.Type, attrs map[string]*EntityProperty, translator Translator, index []int) error { // if a pointer to a struct is passed, get the type of the dereferenced object if typ.Kind() == reflect.Ptr { typ = typ.Elem() @@ -119,7 +111,8 @@ func walkTreeStruct(prefix string, typ reflect.Type, attrs map[string]*EntityPro } // loop through the struct's fields and set the map - for i := 0; i < typ.NumField(); i++ { + num := typ.NumField() + for i := 0; i < num; i++ { p := typ.Field(i) var omit, embeded bool var converter Converter @@ -144,27 +137,27 @@ func walkTreeStruct(prefix string, typ reflect.Type, attrs map[string]*EntityPro } } } + x := append(index, i) if p.Anonymous { - if err := walkTreeStruct(prefix, p.Type, attrs, translator, prevGetter, prevSetter); err != nil { + if err := walkTreeStruct(prefix, p.Type, attrs, translator, x); err != nil { return err } } else if embeded { - nextGetter := makeGetter(prevGetter, p.Name) - nextSetter := makeSetter(prevSetter, p.Name) - if err := walkTreeStruct(prefix, p.Type, attrs, translator, nextGetter, nextSetter); err != nil { + if err := walkTreeStruct(prefix, p.Type, attrs, translator, x); err != nil { return err } } else { ep := &EntityProperty{} - ep.getter = makeGetter(prevGetter, p.Name) - ep.setter = makeSetter(prevSetter, p.Name) + ep.getter = makeGetter(x) + ep.setter = makeSetter(x) - key := strings.ToUpper(p.Name[:1]) + p.Name[1:] + var key strings.Builder if prefix != "" { - key = prefix + key + key.WriteString(prefix) } - attrs[key] = ep - ep.FieldName = p.Name + key.WriteString(strings.ToUpper(p.Name[:1])) + key.WriteString(p.Name[1:]) + attrs[key.String()] = ep ep.Omit = omit ep.converter = converter // we want pointers. only pointer are addressable diff --git a/db/insert.go b/db/insert.go index 9ad9a7a..3da429a 100644 --- a/db/insert.go +++ b/db/insert.go @@ -1,8 +1,6 @@ package db import ( - "fmt" - "github.com/quintans/faults" coll "github.com/quintans/toolkit/collections" @@ -161,7 +159,6 @@ func (i *Insert) Submit(instance interface{}) (int64, error) { var version int64 = 1 for e := i.table.GetColumns().Enumerator(); e.HasNext(); { column := e.Next().(*Column) - fmt.Println("===>", column.name) if column.IsVersion() { i.Set(column, version) } else {