Skip to content

Commit

Permalink
Merge pull request #2 from bitbus/pr-use-any
Browse files Browse the repository at this point in the history
convert all interface{} type to any type
  • Loading branch information
alimy committed Aug 19, 2023
2 parents 1b0a74a + 15b90b7 commit f7daf07
Show file tree
Hide file tree
Showing 12 changed files with 220 additions and 220 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ explains how to use `database/sql` along with sqlx.

* `sqlx.DB.Connx(context.Context) *sqlx.Conn`
* `sqlx.BindDriver(driverName, bindType)`
* support for `[]map[string]interface{}` to do "batch" insertions
* support for `[]map[string]any` to do "batch" insertions
* allocation & perf improvements for `sqlx.In`

DB.Connx returns an `sqlx.Conn`, which is an `sql.Conn`-alike consistent with
Expand Down Expand Up @@ -127,7 +127,7 @@ func main() {
tx.NamedExec("INSERT INTO person (first_name, last_name, email) VALUES (:first_name, :last_name, :email)", &Person{"Jane", "Citizen", "[email protected]"})
tx.Commit()

// Query the database, storing results in a []Person (wrapped in []interface{})
// Query the database, storing results in a []Person (wrapped in []any)
people := []Person{}
db.Select(&people, "SELECT * FROM person ORDER BY first_name ASC")
jason, john := people[0], people[1]
Expand Down Expand Up @@ -173,14 +173,14 @@ func main() {
// Named queries, using `:name` as the bindvar. Automatic bindvar support
// which takes into account the dbtype based on the driverName on sqlx.Open/Connect
_, err = db.NamedExec(`INSERT INTO person (first_name,last_name,email) VALUES (:first,:last,:email)`,
map[string]interface{}{
map[string]any{
"first": "Bin",
"last": "Smuth",
"email": "[email protected]",
})

// Selects Mr. Smith from the database
rows, err = db.NamedQuery(`SELECT * FROM person WHERE first_name=:fn`, map[string]interface{}{"fn": "Bin"})
rows, err = db.NamedQuery(`SELECT * FROM person WHERE first_name=:fn`, map[string]any{"fn": "Bin"})

// Named queries can also use structs. Their bind names follow the same rules
// as the name -> db mapping, so struct fields are lowercased and the `db` tag
Expand All @@ -201,7 +201,7 @@ func main() {
VALUES (:first_name, :last_name, :email)`, personStructs)

// batch insert with maps
personMaps := []map[string]interface{}{
personMaps := []map[string]any{
{"first_name": "Ardie", "last_name": "Savea", "email": "[email protected]"},
{"first_name": "Sonny Bill", "last_name": "Williams", "email": "[email protected]"},
{"first_name": "Ngani", "last_name": "Laumape", "email": "[email protected]"},
Expand Down
12 changes: 6 additions & 6 deletions bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func rebindBuff(bindType int, query string) string {
return rqb.String()
}

func asSliceForIn(i interface{}) (v reflect.Value, ok bool) {
func asSliceForIn(i any) (v reflect.Value, ok bool) {
if i == nil {
return reflect.Value{}, false
}
Expand All @@ -139,12 +139,12 @@ func asSliceForIn(i interface{}) (v reflect.Value, ok bool) {
// In expands slice values in args, returning the modified query string
// and a new arg list that can be executed by a database. The `query` should
// use the `?` bindVar. The return value uses the `?` bindVar.
func In(query string, args ...interface{}) (string, []interface{}, error) {
func In(query string, args ...any) (string, []any, error) {
// argMeta stores reflect.Value and length for slices and
// the value itself for non-slice arguments
type argMeta struct {
v reflect.Value
i interface{}
i any
length int
}

Expand Down Expand Up @@ -191,7 +191,7 @@ func In(query string, args ...interface{}) (string, []interface{}, error) {
return query, args, nil
}

newArgs := make([]interface{}, 0, flatArgsCount)
newArgs := make([]any, 0, flatArgsCount)

var buf strings.Builder
buf.Grow(len(query) + len(", ?")*flatArgsCount)
Expand Down Expand Up @@ -243,9 +243,9 @@ func In(query string, args ...interface{}) (string, []interface{}, error) {
return buf.String(), newArgs, nil
}

func appendReflectSlice(args []interface{}, v reflect.Value, vlen int) []interface{} {
func appendReflectSlice(args []any, v reflect.Value, vlen int) []any {
switch val := v.Interface().(type) {
case []interface{}:
case []any:
args = append(args, val...)
case []int:
for i := range val {
Expand Down
70 changes: 35 additions & 35 deletions named.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func (n *NamedStmt) Close() error {

// Exec executes a named statement using the struct passed.
// Any named placeholder parameters are replaced with fields from arg.
func (n *NamedStmt) Exec(arg interface{}) (sql.Result, error) {
func (n *NamedStmt) Exec(arg any) (sql.Result, error) {
args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper)
if err != nil {
return *new(sql.Result), err
Expand All @@ -49,7 +49,7 @@ func (n *NamedStmt) Exec(arg interface{}) (sql.Result, error) {

// Query executes a named statement using the struct argument, returning rows.
// Any named placeholder parameters are replaced with fields from arg.
func (n *NamedStmt) Query(arg interface{}) (*sql.Rows, error) {
func (n *NamedStmt) Query(arg any) (*sql.Rows, error) {
args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper)
if err != nil {
return nil, err
Expand All @@ -61,7 +61,7 @@ func (n *NamedStmt) Query(arg interface{}) (*sql.Rows, error) {
// create a *sql.Row with an error condition pre-set for binding errors, sqlx
// returns a *sqlx.Row instead.
// Any named placeholder parameters are replaced with fields from arg.
func (n *NamedStmt) QueryRow(arg interface{}) *Row {
func (n *NamedStmt) QueryRow(arg any) *Row {
args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper)
if err != nil {
return &Row{err: err}
Expand All @@ -71,7 +71,7 @@ func (n *NamedStmt) QueryRow(arg interface{}) *Row {

// MustExec execs a NamedStmt, panicing on error
// Any named placeholder parameters are replaced with fields from arg.
func (n *NamedStmt) MustExec(arg interface{}) sql.Result {
func (n *NamedStmt) MustExec(arg any) sql.Result {
res, err := n.Exec(arg)
if err != nil {
panic(err)
Expand All @@ -81,7 +81,7 @@ func (n *NamedStmt) MustExec(arg interface{}) sql.Result {

// Queryx using this NamedStmt
// Any named placeholder parameters are replaced with fields from arg.
func (n *NamedStmt) Queryx(arg interface{}) (*Rows, error) {
func (n *NamedStmt) Queryx(arg any) (*Rows, error) {
r, err := n.Query(arg)
if err != nil {
return nil, err
Expand All @@ -92,13 +92,13 @@ func (n *NamedStmt) Queryx(arg interface{}) (*Rows, error) {
// QueryRowx this NamedStmt. Because of limitations with QueryRow, this is
// an alias for QueryRow.
// Any named placeholder parameters are replaced with fields from arg.
func (n *NamedStmt) QueryRowx(arg interface{}) *Row {
func (n *NamedStmt) QueryRowx(arg any) *Row {
return n.QueryRow(arg)
}

// Select using this NamedStmt
// Any named placeholder parameters are replaced with fields from arg.
func (n *NamedStmt) Select(dest interface{}, arg interface{}) error {
func (n *NamedStmt) Select(dest any, arg any) error {
rows, err := n.Queryx(arg)
if err != nil {
return err
Expand All @@ -110,7 +110,7 @@ func (n *NamedStmt) Select(dest interface{}, arg interface{}) error {

// Get using this NamedStmt
// Any named placeholder parameters are replaced with fields from arg.
func (n *NamedStmt) Get(dest interface{}, arg interface{}) error {
func (n *NamedStmt) Get(dest any, arg any) error {
r := n.QueryRowx(arg)
return r.scanAny(dest, false)
}
Expand Down Expand Up @@ -146,21 +146,21 @@ 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{}
// convertMapStringInterface attempts to convert v to map[string]any.
// Unlike v.(map[string]any), this function works on named types that
// are convertible to map[string]any as well.
func convertMapStringInterface(v any) (map[string]any, bool) {
var m map[string]any
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
return reflect.ValueOf(v).Convert(mtype).Interface().(map[string]any), true

}

func bindAnyArgs(names []string, arg interface{}, m *reflectx.Mapper) ([]interface{}, error) {
func bindAnyArgs(names []string, arg any, m *reflectx.Mapper) ([]any, error) {
if maparg, ok := convertMapStringInterface(arg); ok {
return bindMapArgs(names, maparg)
}
Expand All @@ -170,8 +170,8 @@ func bindAnyArgs(names []string, arg interface{}, m *reflectx.Mapper) ([]interfa
// private interface to generate a list of interfaces from a given struct
// type, given a list of names to pull out of the struct. Used by public
// BindStruct interface.
func bindArgs(names []string, arg interface{}, m *reflectx.Mapper) ([]interface{}, error) {
arglist := make([]interface{}, 0, len(names))
func bindArgs(names []string, arg any, m *reflectx.Mapper) ([]any, error) {
arglist := make([]any, 0, len(names))

// grab the indirected value of arg
v := reflect.ValueOf(arg)
Expand All @@ -194,8 +194,8 @@ func bindArgs(names []string, arg interface{}, m *reflectx.Mapper) ([]interface{
}

// like bindArgs, but for maps.
func bindMapArgs(names []string, arg map[string]interface{}) ([]interface{}, error) {
arglist := make([]interface{}, 0, len(names))
func bindMapArgs(names []string, arg map[string]any) ([]any, error) {
arglist := make([]any, 0, len(names))

for _, name := range names {
val, ok := arg[name]
Expand All @@ -210,15 +210,15 @@ func bindMapArgs(names []string, arg map[string]interface{}) ([]interface{}, err
// bindStruct binds a named parameter query with fields from a struct argument.
// The rules for binding field names to parameter names follow the same
// conventions as for StructScan, including obeying the `db` struct tags.
func bindStruct(bindType int, query string, arg interface{}, m *reflectx.Mapper) (string, []interface{}, error) {
func bindStruct(bindType int, query string, arg any, m *reflectx.Mapper) (string, []any, error) {
bound, names, err := compileNamedQuery([]byte(query), bindType)
if err != nil {
return "", []interface{}{}, err
return "", []any{}, err
}

arglist, err := bindAnyArgs(names, arg, m)
if err != nil {
return "", []interface{}{}, err
return "", []any{}, err
}

return bound, arglist, nil
Expand Down Expand Up @@ -270,23 +270,23 @@ func fixBound(bound string, loop int) string {

// bindArray binds a named parameter query with fields from an array or slice of
// structs argument.
func bindArray(bindType int, query string, arg interface{}, m *reflectx.Mapper) (string, []interface{}, error) {
func bindArray(bindType int, query string, arg any, m *reflectx.Mapper) (string, []any, error) {
// do the initial binding with QUESTION; if bindType is not question,
// we can rebind it at the end.
bound, names, err := compileNamedQuery([]byte(query), QUESTION)
if err != nil {
return "", []interface{}{}, err
return "", []any{}, err
}
arrayValue := reflect.ValueOf(arg)
arrayLen := arrayValue.Len()
if arrayLen == 0 {
return "", []interface{}{}, fmt.Errorf("length of array is 0: %#v", arg)
return "", []any{}, fmt.Errorf("length of array is 0: %#v", arg)
}
var arglist = make([]interface{}, 0, len(names)*arrayLen)
var arglist = make([]any, 0, len(names)*arrayLen)
for i := 0; i < arrayLen; i++ {
elemArglist, err := bindAnyArgs(names, arrayValue.Index(i).Interface(), m)
if err != nil {
return "", []interface{}{}, err
return "", []any{}, err
}
arglist = append(arglist, elemArglist...)
}
Expand All @@ -301,10 +301,10 @@ func bindArray(bindType int, query string, arg interface{}, m *reflectx.Mapper)
}

// bindMap binds a named parameter query with a map of arguments.
func bindMap(bindType int, query string, args map[string]interface{}) (string, []interface{}, error) {
func bindMap(bindType int, query string, args map[string]any) (string, []any, error) {
bound, names, err := compileNamedQuery([]byte(query), bindType)
if err != nil {
return "", []interface{}{}, err
return "", []any{}, err
}

arglist, err := bindMapArgs(names, args)
Expand Down Expand Up @@ -407,18 +407,18 @@ func compileNamedQuery(qs []byte, bindType int) (query string, names []string, e

// BindNamed binds a struct or a map to a query with named parameters.
// DEPRECATED: use sqlx.Named` instead of this, it may be removed in future.
func BindNamed(bindType int, query string, arg interface{}) (string, []interface{}, error) {
func BindNamed(bindType int, query string, arg any) (string, []any, error) {
return bindNamedMapper(bindType, query, arg, mapper())
}

// Named takes a query using named parameters and an argument and
// returns a new query with a list of args that can be executed by
// a database. The return value uses the `?` bindvar.
func Named(query string, arg interface{}) (string, []interface{}, error) {
func Named(query string, arg any) (string, []any, error) {
return bindNamedMapper(QUESTION, query, arg, mapper())
}

func bindNamedMapper(bindType int, query string, arg interface{}, m *reflectx.Mapper) (string, []interface{}, error) {
func bindNamedMapper(bindType int, query string, arg any, m *reflectx.Mapper) (string, []any, error) {
t := reflect.TypeOf(arg)
k := t.Kind()
switch {
Expand All @@ -437,8 +437,8 @@ func bindNamedMapper(bindType int, query string, arg interface{}, m *reflectx.Ma

// NamedQuery binds a named query and then runs Query on the result using the
// provided Ext (sqlx.Tx, sqlx.Db). It works with both structs and with
// map[string]interface{} types.
func NamedQuery(e Ext, query string, arg interface{}) (*Rows, error) {
// map[string]any types.
func NamedQuery(e Ext, query string, arg any) (*Rows, error) {
q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e))
if err != nil {
return nil, err
Expand All @@ -449,7 +449,7 @@ func NamedQuery(e Ext, query string, arg interface{}) (*Rows, error) {
// NamedExec uses BindStruct to get a query executable by the driver and
// then runs Exec on the result. Returns an error from the binding
// or the query execution itself.
func NamedExec(e Ext, query string, arg interface{}) (sql.Result, error) {
func NamedExec(e Ext, query string, arg any) (sql.Result, error) {
q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e))
if err != nil {
return nil, err
Expand Down
Loading

0 comments on commit f7daf07

Please sign in to comment.