Skip to content

Commit

Permalink
extract map[string]interface{} conversion for convertible named types…
Browse files Browse the repository at this point in the history
… and combine with change to bindAnyArgs test
  • Loading branch information
jmoiron committed Jan 24, 2021
1 parent ba0e7e7 commit b42561b
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 5 deletions.
22 changes: 17 additions & 5 deletions named.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,22 @@ func prepareNamed(p namedPreparer, query string) (*NamedStmt, error) {
}, nil
}

// convertMapStringInterface attempts to convert v to map[string]interface{}.
// Unlike v.(map[string]interface{}), this function works on named types that
// are convertible to map[string]interface{} as well.
func convertMapStringInterface(v interface{}) (map[string]interface{}, bool) {
var m map[string]interface{}
mtype := reflect.TypeOf(m)
t := reflect.TypeOf(v)
if !t.ConvertibleTo(mtype) {
return nil, false
}
return reflect.ValueOf(v).Convert(mtype).Interface().(map[string]interface{}), true

}

func bindAnyArgs(names []string, arg interface{}, m *reflectx.Mapper) ([]interface{}, error) {
if maparg, ok := arg.(map[string]interface{}); ok {
if maparg, ok := convertMapStringInterface(arg); ok {
return bindMapArgs(names, maparg)
}
return bindArgs(names, arg, m)
Expand Down Expand Up @@ -383,12 +397,10 @@ func bindNamedMapper(bindType int, query string, arg interface{}, m *reflectx.Ma
k := t.Kind()
switch {
case k == reflect.Map && t.Key().Kind() == reflect.String:
var m map[string]interface{}
if !t.ConvertibleTo(reflect.TypeOf(m)) {
m, ok := convertMapStringInterface(arg)
if !ok {
return "", nil, fmt.Errorf("sqlx.bindNamedMapper: unsupported map type: %T", arg)
}

m = reflect.ValueOf(arg).Convert(reflect.TypeOf(m)).Interface().(map[string]interface{})
return bindMap(bindType, query, m)
case k == reflect.Array || k == reflect.Slice:
return bindArray(bindType, query, arg, m)
Expand Down
12 changes: 12 additions & 0 deletions named_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,18 @@ func TestNamedQueries(t *testing.T) {
VALUES (:first_name, :last_name, :email)`, slsMap)
test.Error(err)

type A map[string]interface{}

typedMap := []A{
{"first_name": "Ardie", "last_name": "Savea", "email": "asavea@ab.co.nz"},
{"first_name": "Sonny Bill", "last_name": "Williams", "email": "sbw@ab.co.nz"},
{"first_name": "Ngani", "last_name": "Laumape", "email": "nlaumape@ab.co.nz"},
}

_, err = db.NamedExec(`INSERT INTO person (first_name, last_name, email)
VALUES (:first_name, :last_name, :email)`, typedMap)
test.Error(err)

for _, p := range sls {
dest := Person{}
err = db.Get(&dest, db.Rebind("SELECT * FROM person WHERE email=?"), p.Email)
Expand Down

0 comments on commit b42561b

Please sign in to comment.