Skip to content

Commit

Permalink
Implement nested structs (#29)
Browse files Browse the repository at this point in the history
Shout out to @schmath for the [implementation](#16 (comment))
  • Loading branch information
blockloop committed May 30, 2021
1 parent a11a5fa commit 0ae25e1
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 34 deletions.
40 changes: 15 additions & 25 deletions fakes_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 13 additions & 9 deletions scanner.go
Expand Up @@ -132,22 +132,26 @@ func rows(v interface{}, r RowsScanner, strict bool) (outerr error) {
}

// Initialization the tags from struct.
func initFieldTag(v reflect.Value, len int) map[string]reflect.Value {
fieldTagMap := make(map[string]reflect.Value, len)
typ := v.Type()
for i := 0; i < v.NumField(); i++ {
func initFieldTag(sliceItem reflect.Value, fieldTagMap *map[string]reflect.Value) {
typ := sliceItem.Type()
for i := 0; i < sliceItem.NumField(); i++ {
if typ.Field(i).Anonymous || typ.Field(i).Type.Kind() == reflect.Struct {
// found an embedded struct
sliceItemOfAnonymous := sliceItem.Field(i)
initFieldTag(sliceItemOfAnonymous, fieldTagMap)
}
tag, ok := typ.Field(i).Tag.Lookup("db")
if ok && tag != "" {
fieldTagMap[tag] = v.Field(i)
(*fieldTagMap)[tag] = sliceItem.Field(i)
}
}
return fieldTagMap
}

func structPointers(stct reflect.Value, cols []string, strict bool) []interface{} {
func structPointers(sliceItem reflect.Value, cols []string, strict bool) []interface{} {
pointers := make([]interface{}, 0, len(cols))
fieldTag := make(map[string]reflect.Value, len(cols))
initFieldTag(sliceItem, &fieldTag)

fieldTag := initFieldTag(stct, len(cols))
for _, colName := range cols {
var fieldVal reflect.Value
if v, ok := fieldTag[colName]; ok {
Expand All @@ -156,7 +160,7 @@ func structPointers(stct reflect.Value, cols []string, strict bool) []interface{
if strict {
fieldVal = reflect.ValueOf(nil)
} else {
fieldVal = stct.FieldByName(strings.Title(colName))
fieldVal = sliceItem.FieldByName(strings.Title(colName))
}
}
if !fieldVal.IsValid() || !fieldVal.CanSet() {
Expand Down
33 changes: 33 additions & 0 deletions scanner_test.go
Expand Up @@ -278,6 +278,39 @@ func TestRowStrictIgnoresFieldsWithoutDBTag(t *testing.T) {
assert.Equal(t, "", item.Last)
}

func TestRowScansNestedFields(t *testing.T) {
rows := fakeRowsWithRecords(t, []string{"p.First", "p.Last"},
[]interface{}{"Brett", "Jones"},
)

var res struct {
Item struct {
First string `db:"p.First"`
Last string `db:"p.Last"`
}
}

require.NoError(t, scan.Row(&res, rows))
assert.Equal(t, "Brett", res.Item.First)
assert.Equal(t, "Jones", res.Item.Last)
}

func TestRowStrictScansNestedFields(t *testing.T) {
rows := fakeRowsWithRecords(t, []string{"p.First", "p.Last"},
[]interface{}{"Brett", "Jones"},
)

var res struct {
Item struct {
First string `db:"p.First"`
Last string `db:"p.Last"`
}
}

require.NoError(t, scan.RowStrict(&res, rows))
assert.Equal(t, "Brett", res.Item.First)
assert.Equal(t, "Jones", res.Item.Last)
}
func TestRowsStrictIgnoresFieldsWithoutDBTag(t *testing.T) {
rows := fakeRowsWithRecords(t, []string{"First", "Last"},
[]interface{}{"Brett", "Jones"},
Expand Down

0 comments on commit 0ae25e1

Please sign in to comment.