Skip to content

Commit

Permalink
support nested pointers
Browse files Browse the repository at this point in the history
  • Loading branch information
NoBypass committed May 18, 2024
1 parent 9f5ac8a commit f39273e
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 4 deletions.
21 changes: 17 additions & 4 deletions scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,21 @@ func parseSlice(srcVal reflect.Value, destVal reflect.Value) error {
}

func parseMap(srcVal reflect.Value, destVal reflect.Value) error {
if destVal.Kind() != reflect.Struct {
return fmt.Errorf("cannot assign map to %s", destVal.Type())
}

destKind := destVal.Kind()
destType := destVal.Type()

if destKind == reflect.Ptr {
if destVal.IsNil() {
newDest := reflect.New(destType.Elem())
destVal.Set(newDest)
}

destVal = destVal.Elem()
destType = destVal.Type()
} else if destKind != reflect.Struct {
return fmt.Errorf("cannot assign map to %s", destType)
}

for i := 0; i < destType.NumField(); i++ {
field := destType.Field(i)
tag := field.Tag.Get("db")
Expand Down Expand Up @@ -78,6 +87,10 @@ func parseMap(srcVal reflect.Value, destVal reflect.Value) error {
}

func parseValue(srcVal reflect.Value, destVal reflect.Value) error {
if !srcVal.IsValid() {
return nil
}

if !srcVal.Type().AssignableTo(destVal.Type()) {
if destVal.Kind() == reflect.Int && srcVal.Kind() == reflect.Float64 {
destVal.SetInt(int64(srcVal.Float()))
Expand Down
81 changes: 81 additions & 0 deletions scan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ type nestedTestStruct struct {
Test testStruct
}

type nestedTestStructPtr struct {
Title string
Test *testStruct
}

func Test_scan(t *testing.T) {
t.Run("scan single map to struct", func(t *testing.T) {
m := map[string]any{
Expand Down Expand Up @@ -165,4 +170,80 @@ func Test_scan(t *testing.T) {
},
}, s)
})
t.Run("scan single map to nested struct with pointer", func(t *testing.T) {
m := map[string]any{
"title": "hello",
"test": map[string]any{
"text": "world",
},
}

var s nestedTestStructPtr
err := scan(m, &s)
assert.NoError(t, err)
assert.Equal(t, nestedTestStructPtr{
Title: "hello",
Test: &testStruct{
Text: "world",
},
}, s)
})
t.Run("scan multiple maps to nested with pointer", func(t *testing.T) {
m := []map[string]any{
{
"title": "hello",
},
{
"test": map[string]any{
"text": "world",
},
},
}

var s []nestedTestStructPtr
err := scan(m, &s)
assert.NoError(t, err)
assert.Equal(t, []nestedTestStructPtr{
{
Title: "hello",
},
{
Test: &testStruct{
Text: "world",
},
},
}, s)
})
t.Run("scan single map to nested struct with tag and pointer", func(t *testing.T) {
m := map[string]any{
"title": "hello",
"test": map[string]any{
"created_at": 123,
},
}

var s nestedTestStructPtr
err := scan(m, &s)
assert.NoError(t, err)
assert.Equal(t, nestedTestStructPtr{
Title: "hello",
Test: &testStruct{
CreatedAt: 123,
},
}, s)
})
t.Run("scan nested nil struct to pointer", func(t *testing.T) {
m := map[string]any{
"title": "hello",
"test": nil,
}

var s nestedTestStructPtr
err := scan(m, &s)
assert.NoError(t, err)
assert.Equal(t, nestedTestStructPtr{
Title: "hello",
Test: nil,
}, s)
})
}

0 comments on commit f39273e

Please sign in to comment.