good morning!!!!

Skip to content
Snippets Groups Projects
Commit 274deced authored by José Carlos Nieto's avatar José Carlos Nieto
Browse files

Adding support for struct tags.

parent 94a1cfea
Branches
No related tags found
No related merge requests found
......@@ -2,11 +2,11 @@ package mysql
import (
"fmt"
"github.com/kr/pretty"
"math/rand"
"menteslibres.net/gosexy/db"
"menteslibres.net/gosexy/dig"
"menteslibres.net/gosexy/to"
"github.com/kr/pretty"
"math/rand"
"reflect"
"testing"
"time"
......@@ -184,7 +184,14 @@ func TestAppend(t *testing.T) {
people.Truncate()
for _, name := range names {
people.Append(struct{ Name string }{name})
people.Append(struct {
ignoreMe string
LastName string `ignorenil:"true"`
// Must ignore OtherName and use "name" as column.
OtherName string `field:"name",ignorenil:"true"`
// Should not get inserted.
nothing string
}{"nuff said", "", name, "nothing"})
}
total, _ = people.Count()
......@@ -242,7 +249,11 @@ func TestFind(t *testing.T) {
}
// Fetch into struct slice.
dst2 := []struct{ Name string }{}
dst2 := []struct {
foo string
PersonName string `field:"name"`
none string
}{}
res, err = people.Query(db.Cond{"name": "José"})
......@@ -260,7 +271,7 @@ func TestFind(t *testing.T) {
t.Fatalf("Could not find a recently appended item.")
}
if dst2[0].Name != "José" {
if dst2[0].PersonName != "José" {
t.Fatalf("Could not find a recently appended item.")
}
......@@ -305,7 +316,9 @@ func TestFind(t *testing.T) {
t.Fatalf(err.Error())
}
dst5 := struct{ Name string }{}
dst5 := struct {
PersonName string `field:"name"`
}{}
found := false
for {
......@@ -313,7 +326,7 @@ func TestFind(t *testing.T) {
if err != nil {
break
}
if dst5.Name == "José" {
if dst5.PersonName == "José" {
found = true
}
}
......
No preview for this file type
......@@ -68,13 +68,58 @@ func (self *C) RelationCollection(name string, terms db.On) (db.Collection, erro
return col, nil
}
func columnCompare(s string) string {
return strings.ToLower(columnCompareExclude.ReplaceAllString(s, ""))
}
/*
Returns the most appropriate struct field index for a given column name.
If no column matches returns -1.
*/
func MatchStructField(s reflect.Type, columnName string) int {
n := s.NumField()
columnNameLower := columnCompare(columnName)
for i := 0; i < n; i++ {
field := s.Field(i)
// Field is exported.
if field.PkgPath == "" {
tag := field.Tag
// Tag: field:"columnName"
fieldName := tag.Get("field")
if fieldName != "" {
if fieldName == columnName {
return i
}
}
// Matching column to name.
fieldNameLower := columnCompare(field.Name)
if fieldNameLower == columnNameLower {
return i
}
}
}
// No match.
return -1
}
/*
Returns true if a table column looks like a struct field.
*/
func CompareColumnToField(s, c string) bool {
s = columnCompareExclude.ReplaceAllString(s, "")
c = columnCompareExclude.ReplaceAllString(c, "")
return strings.ToLower(s) == strings.ToLower(c)
return columnCompare(s) == columnCompare(c)
}
/*
......@@ -105,14 +150,16 @@ func Fetch(dst interface{}, item db.Item) error {
switch el.Kind() {
case reflect.Struct:
for column, _ := range item {
f := func(s string) bool {
return CompareColumnToField(s, column)
}
v := dstv.Elem().FieldByNameFunc(f)
fi := MatchStructField(dstv.Type(), column)
if fi < 0 {
continue
} else {
v := dstv.Elem().Field(fi)
if v.IsValid() {
v.Set(reflect.ValueOf(item[column]))
}
}
}
case reflect.Map:
dstv.Elem().Set(reflect.ValueOf(item))
default:
......@@ -144,10 +191,12 @@ func fetchItemRelations(itemv reflect.Value, relations []db.Relation, convertFn
var val reflect.Value
switch itemk {
case reflect.Struct:
f := func(s string) bool {
return CompareColumnToField(s, extkey)
fi := MatchStructField(itemv.Type(), extkey)
if fi < 0 {
continue
} else {
val = itemv.Field(fi)
}
val = itemv.FieldByNameFunc(f)
case reflect.Map:
val = itemv.MapIndex(reflect.ValueOf(extkey))
}
......@@ -167,12 +216,15 @@ func fetchItemRelations(itemv reflect.Value, relations []db.Relation, convertFn
switch itemk {
case reflect.Struct:
var val reflect.Value
f := func(s string) bool {
return CompareColumnToField(s, relation.Name)
}
fi := MatchStructField(itemv.Type(), relation.Name)
val := itemv.FieldByNameFunc(f)
if fi < 0 {
continue
} else {
val = itemv.Field(fi)
}
if val.IsValid() {
var res db.Result
......
......@@ -93,8 +93,11 @@ func (self *T) fetchResult(itemt reflect.Type, rows *sql.Rows, columns []string)
// Range over row values.
for i, value := range values {
if value != nil {
// Real column name
column := columns[i]
// Value as string.
svalue := string(*value)
var cv reflect.Value
......@@ -121,12 +124,16 @@ func (self *T) fetchResult(itemt reflect.Type, rows *sql.Rows, columns []string)
}
// Destionation is a struct.
case reflect.Struct:
// Get appropriate column.
f := func(s string) bool {
return util.CompareColumnToField(s, column)
}
fi := util.MatchStructField(itemt, column)
if fi < 0 {
continue
} else {
// Destination field.
destf := item.Elem().FieldByNameFunc(f)
destf := item.Elem().Field(fi)
if destf.IsValid() {
if cv.Type().Kind() != destf.Type().Kind() {
if destf.Type().Kind() != reflect.Interface {
......@@ -139,6 +146,8 @@ func (self *T) fetchResult(itemt reflect.Type, rows *sql.Rows, columns []string)
destf.Set(cv)
}
}
}
}
}
}
......@@ -246,24 +255,56 @@ func (self *T) FieldValues(item interface{}, convertFn func(interface{}) string)
itemt := itemv.Type()
switch itemt.Kind() {
case reflect.Struct:
nfields := itemv.NumField()
values = make([]string, nfields)
fields = make([]string, nfields)
values = make([]string, 0, nfields)
fields = make([]string, 0, nfields)
for i := 0; i < nfields; i++ {
fields[i] = self.ColumnLike(itemt.Field(i).Name)
values[i] = convertFn(itemv.Field(i).Interface())
field := itemt.Field(i)
if field.PkgPath == "" {
value := itemv.Field(i).Interface()
// Struct tags
tag := field.Tag
// omitempty:bool
ignoreNil := tag.Get("ignorenil")
if ignoreNil == "true" {
if value == nil || value == "" {
continue
}
}
// field:string
fieldName := tag.Get("field")
if fieldName == "" {
fieldName = self.ColumnLike(field.Name)
}
fields = append(fields, fieldName)
values = append(values, convertFn(value))
}
}
case reflect.Map:
nfields := itemv.Len()
values = make([]string, nfields)
fields = make([]string, nfields)
mkeys := itemv.MapKeys()
for i, keyv := range mkeys {
valv := itemv.MapIndex(keyv)
fields[i] = self.ColumnLike(to.String(keyv.Interface()))
values[i] = convertFn(valv.Interface())
}
default:
return nil, nil, fmt.Errorf("Expecting Struct or Map, received %v.", itemt.Kind())
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment