From f0c6c11ddc10adc57ea43d9d6e3993b4391534d4 Mon Sep 17 00:00:00 2001 From: Stephen Afam-Osemene Date: Tue, 2 Jan 2024 21:51:43 +0000 Subject: [PATCH] Fix panic with nil pointers in structs to bind --- queries/reflect.go | 48 +++++++++++++++++++++-------------------- queries/reflect_test.go | 14 ++++++------ 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/queries/reflect.go b/queries/reflect.go index 3ac81964a..3836325e8 100644 --- a/queries/reflect.go +++ b/queries/reflect.go @@ -83,27 +83,27 @@ func (q *Query) BindG(ctx context.Context, obj interface{}) error { // // Example usage: // -// type JoinStruct struct { -// // User1 can have it's struct fields bound to since it specifies -// // ,bind in the struct tag, it will look specifically for -// // fields that are prefixed with "user." returning from the query. -// // For example "user.id" column name will bind to User1.ID -// User1 *models.User `boil:"user,bind"` -// // User2 will follow the same rules as noted above except it will use -// // "friend." as the prefix it's looking for. -// User2 *models.User `boil:"friend,bind"` -// // RandomData will not be recursed into to look for fields to -// // bind and will not be bound to because of the - for the name. -// RandomData myStruct `boil:"-"` -// // Date will not be recursed into to look for fields to bind because -// // it does not specify ,bind in the struct tag. But it can be bound to -// // as it does not specify a - for the name. -// Date time.Time -// } +// type JoinStruct struct { +// // User1 can have it's struct fields bound to since it specifies +// // ,bind in the struct tag, it will look specifically for +// // fields that are prefixed with "user." returning from the query. +// // For example "user.id" column name will bind to User1.ID +// User1 *models.User `boil:"user,bind"` +// // User2 will follow the same rules as noted above except it will use +// // "friend." as the prefix it's looking for. +// User2 *models.User `boil:"friend,bind"` +// // RandomData will not be recursed into to look for fields to +// // bind and will not be bound to because of the - for the name. +// RandomData myStruct `boil:"-"` +// // Date will not be recursed into to look for fields to bind because +// // it does not specify ,bind in the struct tag. But it can be bound to +// // as it does not specify a - for the name. +// Date time.Time +// } // -// models.Users( -// qm.InnerJoin("users as friend on users.friend_id = friend.id") -// ).Bind(&joinStruct) +// models.Users( +// qm.InnerJoin("users as friend on users.friend_id = friend.id") +// ).Bind(&joinStruct) // // For custom objects that want to use eager loading, please see the // loadRelationships function. @@ -368,6 +368,9 @@ func ptrFromMapping(val reflect.Value, mapping uint64, addressOf bool) reflect.V val = val.Field(int(v)) if val.Kind() == reflect.Ptr { + if val.IsNil() { + val = reflect.New(val.Type().Elem()) + } val = reflect.Indirect(val) } } @@ -606,8 +609,7 @@ func parseNumeric(s string, t reflect.Type) interface{} { reflect.Uint32, reflect.Uint64: res, err = strconv.ParseUint(s, 0, t.Bits()) - case reflect.Float32, - reflect.Float64: + case reflect.Float32, reflect.Float64: res, err = strconv.ParseFloat(s, t.Bits()) } if err != nil { @@ -803,7 +805,7 @@ var specialWordReplacer = strings.NewReplacer( // unTitleCase attempts to undo a title-cased string. // -// DO NOT USE THIS METHOD IF YOU CAN AVOID IT +// # DO NOT USE THIS METHOD IF YOU CAN AVOID IT // // Normally this would be easy but we have to deal with uppercased words // of varying lengths. We almost never use this function so it diff --git a/queries/reflect_test.go b/queries/reflect_test.go index e0267310b..9e6e82adc 100644 --- a/queries/reflect_test.go +++ b/queries/reflect_test.go @@ -12,8 +12,8 @@ import ( "testing" "time" - "github.com/volatiletech/sqlboiler/v4/drivers" "github.com/volatiletech/null/v8" + "github.com/volatiletech/sqlboiler/v4/drivers" "github.com/DATA-DOG/go-sqlmock" ) @@ -193,7 +193,7 @@ func testMakeMapping(byt ...byte) uint64 { func TestMakeStructMapping(t *testing.T) { t.Parallel() - var testStruct = struct { + testStruct := struct { LastName string `boil:"different"` AwesomeName string `boil:"awesome_name"` Face string `boil:"-"` @@ -249,8 +249,7 @@ func TestPtrFromMapping(t *testing.T) { Int: 5, IntP: new(int), NestedPtrsP: &NestedPtrs{ - Int: 6, - IntP: new(int), + Int: 6, }, } @@ -399,10 +398,9 @@ func TestGetBoilTag(t *testing.T) { func TestBindChecks(t *testing.T) { t.Parallel() - type useless struct { - } + type useless struct{} - var tests = []struct { + tests := []struct { BKind bindKind Fail bool Obj interface{} @@ -623,7 +621,7 @@ func TestAssignBytes(t *testing.T) { t.Parallel() var dst []byte - var src = []byte("hello") + src := []byte("hello") Assign(&dst, src) if !bytes.Equal(dst, src) {