diff --git a/HISTORY.md b/HISTORY.md index 3168298f..b9707ac6 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,6 +1,10 @@ +## v8.2.2 + +* [FIX] Scanner errors on pointers to primitive values [#122](https://github.com/doug-martin/goqu/issues/122) + ## v8.2.1 -* [FIX] Return an error when an empty identifier is encountered [#115](https://github.com/doug-martin/goqu/issues/118) +* [FIX] Return an error when an empty identifier is encountered [#115](https://github.com/doug-martin/goqu/issues/115) ## v8.2.0 diff --git a/exec/scanner.go b/exec/scanner.go index e73f892a..8a2a4756 100644 --- a/exec/scanner.go +++ b/exec/scanner.go @@ -117,8 +117,6 @@ func (q *scanner) scanIntoRecord(columns []string, cm util.ColumnMap) (record ex switch { case !ok: return record, unableToFindFieldError(col) - case util.IsPointer(data.GoType.Kind()): - scans[i] = reflect.New(data.GoType.Elem()).Interface() default: scans[i] = reflect.New(data.GoType).Interface() } diff --git a/exec/scanner_test.go b/exec/scanner_test.go index febdbb43..58d45cfd 100644 --- a/exec/scanner_test.go +++ b/exec/scanner_test.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "testing" + "time" "github.com/DATA-DOG/go-sqlmock" "github.com/stretchr/testify/suite" @@ -103,24 +104,35 @@ func (cet *crudExecTest) TestScanStructs_withUntaggedFields() { func (cet *crudExecTest) TestScanStructs_withPointerFields() { type StructWithPointerFields struct { - Address *string - Name *string + Str *string + Time *time.Time + Bool *bool + Int *int64 + Float *float64 } db, mock, err := sqlmock.New() cet.NoError(err) - + now := time.Now() + str1, str2 := "str1", "str2" + t := true + var i1, i2 int64 = 1, 2 + var f1, f2 float64 = 1.1, 2.1 mock.ExpectQuery(`SELECT \* FROM "items"`). WithArgs(). - WillReturnRows(sqlmock.NewRows([]string{"address", "name"}). - FromCSVString("111 Test Addr,Test1\n211 Test Addr,Test2")) + WillReturnRows(sqlmock.NewRows([]string{"str", "time", "bool", "int", "float"}). + AddRow(str1, now, true, i1, f1). + AddRow(str2, now, true, i2, f2). + AddRow(nil, nil, nil, nil, nil), + ) e := newQueryExecutor(db, nil, `SELECT * FROM "items"`) var items []StructWithPointerFields cet.NoError(e.ScanStructs(&items)) cet.Equal([]StructWithPointerFields{ - {Address: &testAddr1, Name: &testName1}, - {Address: &testAddr2, Name: &testName2}, + {Str: &str1, Time: &now, Bool: &t, Int: &i1, Float: &f1}, + {Str: &str2, Time: &now, Bool: &t, Int: &i2, Float: &f2}, + {}, }, items) } diff --git a/internal/util/reflect.go b/internal/util/reflect.go index c726de11..3c2738e0 100644 --- a/internal/util/reflect.go +++ b/internal/util/reflect.go @@ -165,13 +165,9 @@ func assignRowData(row reflect.Value, rd rowData, cm ColumnMap) { for name, data := range cm { src, ok := rd[name] if ok { - srcVal := reflect.ValueOf(src) f := row.FieldByIndex(data.FieldIndex) - if f.Kind() == reflect.Ptr { - f.Set(srcVal) - } else { - f.Set(reflect.Indirect(srcVal)) - } + srcVal := reflect.ValueOf(src) + f.Set(reflect.Indirect(srcVal)) } } } diff --git a/internal/util/reflect_test.go b/internal/util/reflect_test.go index dbb50355..4ad3ea13 100644 --- a/internal/util/reflect_test.go +++ b/internal/util/reflect_test.go @@ -487,12 +487,13 @@ func (rt *reflectTest) TestAssignStructVals_withStructWithPointerVals() { var ts TestStruct cm, err := GetColumnMap(&ts) assert.NoError(t, err) + ns := &sql.NullString{String: "null_str1", Valid: true} data := []map[string]interface{}{ { "str": "string", "int": int64(10), "bool": true, - "valuer": &sql.NullString{String: "null_str", Valid: true}, + "valuer": &ns, }, } AssignStructVals(&ts, data, cm) @@ -500,7 +501,7 @@ func (rt *reflectTest) TestAssignStructVals_withStructWithPointerVals() { Str: "string", Int: 10, Bool: true, - Valuer: &sql.NullString{String: "null_str", Valid: true}, + Valuer: ns, }) } @@ -519,12 +520,13 @@ func (rt *reflectTest) TestAssignStructVals_withStructWithEmbeddedStruct() { var ts TestStruct cm, err := GetColumnMap(&ts) assert.NoError(t, err) + ns := &sql.NullString{String: "null_str1", Valid: true} data := []map[string]interface{}{ { "str": "string", "int": int64(10), "bool": true, - "valuer": &sql.NullString{String: "null_str", Valid: true}, + "valuer": &ns, }, } AssignStructVals(&ts, data, cm) @@ -532,7 +534,7 @@ func (rt *reflectTest) TestAssignStructVals_withStructWithEmbeddedStruct() { EmbeddedStruct: EmbeddedStruct{Str: "string"}, Int: 10, Bool: true, - Valuer: &sql.NullString{String: "null_str", Valid: true}, + Valuer: ns, }) } @@ -551,12 +553,13 @@ func (rt *reflectTest) TestAssignStructVals_withStructWithEmbeddedStructPointer( var ts TestStruct cm, err := GetColumnMap(&ts) assert.NoError(t, err) + ns := &sql.NullString{String: "null_str1", Valid: true} data := []map[string]interface{}{ { "str": "string", "int": int64(10), "bool": true, - "valuer": &sql.NullString{String: "null_str", Valid: true}, + "valuer": &ns, }, } AssignStructVals(&ts, data, cm) @@ -564,7 +567,7 @@ func (rt *reflectTest) TestAssignStructVals_withStructWithEmbeddedStructPointer( EmbeddedStruct: &EmbeddedStruct{Str: "string"}, Int: 10, Bool: true, - Valuer: &sql.NullString{String: "null_str", Valid: true}, + Valuer: ns, }) } @@ -666,18 +669,20 @@ func (rt *reflectTest) TestAssignStructVals_withSliceOfStructsWithPointerVals() var ts []TestStruct cm, err := GetColumnMap(&ts) assert.NoError(t, err) + ns1 := &sql.NullString{String: "null_str1", Valid: true} + ns2 := &sql.NullString{String: "null_str2", Valid: true} data := []map[string]interface{}{ { "str": "string1", "int": int64(10), "bool": true, - "valuer": &sql.NullString{String: "null_str1", Valid: true}, + "valuer": &ns1, }, { "str": "string2", "int": int64(20), "bool": false, - "valuer": &sql.NullString{String: "null_str2", Valid: true}, + "valuer": &ns2, }, } AssignStructVals(&ts, data, cm) @@ -686,13 +691,13 @@ func (rt *reflectTest) TestAssignStructVals_withSliceOfStructsWithPointerVals() Str: "string1", Int: 10, Bool: true, - Valuer: &sql.NullString{String: "null_str1", Valid: true}, + Valuer: ns1, }, { Str: "string2", Int: 20, Bool: false, - Valuer: &sql.NullString{String: "null_str2", Valid: true}, + Valuer: ns2, }, }) } @@ -712,18 +717,20 @@ func (rt *reflectTest) TestAssignStructVals_withSliceofStructsWithEmbeddedStruct var ts []TestStruct cm, err := GetColumnMap(&ts) assert.NoError(t, err) + ns1 := &sql.NullString{String: "null_str1", Valid: true} + ns2 := &sql.NullString{String: "null_str2", Valid: true} data := []map[string]interface{}{ { "str": "string1", "int": int64(10), "bool": true, - "valuer": &sql.NullString{String: "null_str1", Valid: true}, + "valuer": &ns1, }, { "str": "string2", "int": int64(20), "bool": false, - "valuer": &sql.NullString{String: "null_str2", Valid: true}, + "valuer": &ns2, }, } AssignStructVals(&ts, data, cm) @@ -732,13 +739,13 @@ func (rt *reflectTest) TestAssignStructVals_withSliceofStructsWithEmbeddedStruct EmbeddedStruct: EmbeddedStruct{Str: "string1"}, Int: 10, Bool: true, - Valuer: &sql.NullString{String: "null_str1", Valid: true}, + Valuer: ns1, }, { EmbeddedStruct: EmbeddedStruct{Str: "string2"}, Int: 20, Bool: false, - Valuer: &sql.NullString{String: "null_str2", Valid: true}, + Valuer: ns2, }, }) } @@ -758,18 +765,20 @@ func (rt *reflectTest) TestAssignStructVals_withSliceofStructsWithEmbeddedStruct var ts []TestStruct cm, err := GetColumnMap(&ts) assert.NoError(t, err) + ns1 := &sql.NullString{String: "null_str1", Valid: true} + ns2 := &sql.NullString{String: "null_str2", Valid: true} data := []map[string]interface{}{ { "str": "string1", "int": int64(10), "bool": true, - "valuer": &sql.NullString{String: "null_str1", Valid: true}, + "valuer": &ns1, }, { "str": "string2", "int": int64(20), "bool": false, - "valuer": &sql.NullString{String: "null_str2", Valid: true}, + "valuer": &ns2, }, } AssignStructVals(&ts, data, cm) @@ -778,13 +787,13 @@ func (rt *reflectTest) TestAssignStructVals_withSliceofStructsWithEmbeddedStruct EmbeddedStruct: &EmbeddedStruct{Str: "string1"}, Int: 10, Bool: true, - Valuer: &sql.NullString{String: "null_str1", Valid: true}, + Valuer: ns1, }, { EmbeddedStruct: &EmbeddedStruct{Str: "string2"}, Int: 20, Bool: false, - Valuer: &sql.NullString{String: "null_str2", Valid: true}, + Valuer: ns2, }, }) }