diff --git a/bind.go b/bind.go index 266e14e..c89c489 100644 --- a/bind.go +++ b/bind.go @@ -105,7 +105,7 @@ func Rebind(bindType int, query string) string { return string(rqb) } -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 } @@ -119,7 +119,7 @@ func asSliceForIn(i interface{}) (v reflect.Value, ok bool) { } // []byte is a driver.Value type so it should not be expanded - if t == reflect.TypeOf([]byte{}) { + if t == reflect.TypeFor[[]byte]() { return reflect.Value{}, false } @@ -129,12 +129,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 } @@ -181,7 +181,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) @@ -240,9 +240,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 { @@ -253,7 +253,7 @@ func appendReflectSlice(args []interface{}, v reflect.Value, vlen int) []interfa args = append(args, val[i]) } default: - for si := 0; si < vlen; si++ { + for si := range vlen { args = append(args, v.Index(si).Interface()) } } @@ -276,7 +276,7 @@ func appendReflectSlice(args []interface{}, v reflect.Value, vlen int) []interfa func callValuerValue(vr driver.Valuer) (v driver.Value, err error) { if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Pointer && rv.IsNil() && - rv.Type().Elem().Implements(reflect.TypeOf((*driver.Valuer)(nil)).Elem()) { + rv.Type().Elem().Implements(reflect.TypeFor[driver.Valuer]()) { return nil, nil } return vr.Value() diff --git a/convert.go b/convert.go index 3964a91..ea16ddc 100644 --- a/convert.go +++ b/convert.go @@ -5,4 +5,4 @@ import ( ) //go:linkname convertAssign database/sql.convertAssign -func convertAssign(dest, src interface{}) error +func convertAssign(dest, src any) error diff --git a/named.go b/named.go index 1cc0ba9..37e526e 100644 --- a/named.go +++ b/named.go @@ -45,7 +45,7 @@ func (n *GenericNamedStmt[T]) Close() error { // Exec executes a named statement using the struct passed. // Any named placeholder parameters are replaced with fields from arg. -func (n *GenericNamedStmt[T]) Exec(arg interface{}) (sql.Result, error) { +func (n *GenericNamedStmt[T]) Exec(arg any) (sql.Result, error) { args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper) if err != nil { return *new(sql.Result), err @@ -55,7 +55,7 @@ func (n *GenericNamedStmt[T]) 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 *GenericNamedStmt[T]) Query(arg interface{}) (*sql.Rows, error) { +func (n *GenericNamedStmt[T]) Query(arg any) (*sql.Rows, error) { args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper) if err != nil { return nil, err @@ -67,7 +67,7 @@ func (n *GenericNamedStmt[T]) 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 *GenericNamedStmt[T]) QueryRow(arg interface{}) *Row { +func (n *GenericNamedStmt[T]) QueryRow(arg any) *Row { args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper) if err != nil { return &Row{err: err} @@ -77,7 +77,7 @@ func (n *GenericNamedStmt[T]) QueryRow(arg interface{}) *Row { // MustExec execs a NamedStmt, panicing on error // Any named placeholder parameters are replaced with fields from arg. -func (n *GenericNamedStmt[T]) MustExec(arg interface{}) sql.Result { +func (n *GenericNamedStmt[T]) MustExec(arg any) sql.Result { res, err := n.Exec(arg) if err != nil { panic(err) @@ -87,7 +87,7 @@ func (n *GenericNamedStmt[T]) MustExec(arg interface{}) sql.Result { // Queryx using this NamedStmt // Any named placeholder parameters are replaced with fields from arg. -func (n *GenericNamedStmt[T]) Queryx(arg interface{}) (*Rows, error) { +func (n *GenericNamedStmt[T]) Queryx(arg any) (*Rows, error) { r, err := n.Query(arg) if err != nil { return nil, err @@ -98,13 +98,13 @@ func (n *GenericNamedStmt[T]) 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 *GenericNamedStmt[T]) QueryRowx(arg interface{}) *Row { +func (n *GenericNamedStmt[T]) QueryRowx(arg any) *Row { return n.QueryRow(arg) } // Select using this NamedStmt // Any named placeholder parameters are replaced with fields from arg. -func (n *GenericNamedStmt[T]) Select(dest interface{}, arg interface{}) error { +func (n *GenericNamedStmt[T]) Select(dest any, arg any) error { rows, err := n.Queryx(arg) if err != nil { return err @@ -115,7 +115,7 @@ func (n *GenericNamedStmt[T]) Select(dest interface{}, arg interface{}) error { } // List performs a query using the statement and returns all rows as a slice of T. -func (n *GenericNamedStmt[T]) List(arg interface{}) ([]T, error) { +func (n *GenericNamedStmt[T]) List(arg any) ([]T, error) { var dests []T err := n.Select(&dests, arg) return dests, err @@ -123,14 +123,14 @@ func (n *GenericNamedStmt[T]) List(arg interface{}) ([]T, error) { // Get using this NamedStmt // Any named placeholder parameters are replaced with fields from arg. -func (n *GenericNamedStmt[T]) Get(dest interface{}, arg interface{}) error { +func (n *GenericNamedStmt[T]) Get(dest any, arg any) error { r := n.QueryRowx(arg) return r.scanAny(dest, false) } // One get a single row using this NamedStmt // Any named placeholder parameters are replaced with fields from arg. -func (n *GenericNamedStmt[T]) One(arg interface{}) (T, error) { +func (n *GenericNamedStmt[T]) One(arg any) (T, error) { r := n.QueryRowx(arg) var dest T err := r.scanAny(&dest, false) @@ -138,7 +138,7 @@ func (n *GenericNamedStmt[T]) One(arg interface{}) (T, error) { } // All performs a query using the GenericNamedStmt and returns all rows for use with range. -func (n *GenericNamedStmt[T]) All(arg interface{}) iter.Seq2[T, error] { +func (n *GenericNamedStmt[T]) All(arg any) iter.Seq2[T, error] { rows, err := n.Queryx(arg) if err != nil { panic(err) @@ -219,17 +219,17 @@ func PrepareNamed[T any](p namedPreparer, query string) (*GenericNamedStmt[T], e // 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{} +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) } @@ -239,8 +239,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 var v reflect.Value @@ -263,8 +263,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] @@ -279,15 +279,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) { compiled, err := compileNamedQuery([]byte(query), bindType) if err != nil { - return "", []interface{}{}, err + return "", []any{}, err } arglist, err := bindAnyArgs(compiled.names, arg, m) if err != nil { - return "", []interface{}{}, err + return "", []any{}, err } return compiled.query, arglist, nil @@ -314,23 +314,23 @@ func fixBound(cq *compiledQueryResult, loop int) { // 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. compiled, 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) } - arglist := make([]interface{}, 0, len(compiled.names)*arrayLen) - for i := 0; i < arrayLen; i++ { + arglist := make([]any, 0, len(compiled.names)*arrayLen) + for i := range arrayLen { elemArglist, err := bindAnyArgs(compiled.names, arrayValue.Index(i).Interface(), m) if err != nil { - return "", []interface{}{}, err + return "", []any{}, err } arglist = append(arglist, elemArglist...) } @@ -346,10 +346,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) { compiled, err := compileNamedQuery([]byte(query), bindType) if err != nil { - return "", []interface{}{}, err + return "", []any{}, err } arglist, err := bindMapArgs(compiled.names, args) @@ -483,18 +483,18 @@ func compileNamedQuery(qs []byte, bindType int) (compiledQueryResult, error) { // 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 { @@ -514,7 +514,7 @@ 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) { +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 @@ -525,7 +525,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 diff --git a/named_context.go b/named_context.go index a64099e..58b0018 100644 --- a/named_context.go +++ b/named_context.go @@ -62,7 +62,7 @@ func (n *GenericNamedStmt[T]) PrepareContext(ctx context.Context, ndb Queryable) // ExecContext executes a named statement using the struct passed. // Any named placeholder parameters are replaced with fields from arg. -func (n *GenericNamedStmt[T]) ExecContext(ctx context.Context, arg interface{}) (sql.Result, error) { +func (n *GenericNamedStmt[T]) ExecContext(ctx context.Context, arg any) (sql.Result, error) { args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper) if err != nil { return *new(sql.Result), err @@ -72,7 +72,7 @@ func (n *GenericNamedStmt[T]) ExecContext(ctx context.Context, arg interface{}) // QueryContext executes a named statement using the struct argument, returning rows. // Any named placeholder parameters are replaced with fields from arg. -func (n *GenericNamedStmt[T]) QueryContext(ctx context.Context, arg interface{}) (*sql.Rows, error) { +func (n *GenericNamedStmt[T]) QueryContext(ctx context.Context, arg any) (*sql.Rows, error) { args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper) if err != nil { return nil, err @@ -84,7 +84,7 @@ func (n *GenericNamedStmt[T]) QueryContext(ctx context.Context, arg interface{}) // 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 *GenericNamedStmt[T]) QueryRowContext(ctx context.Context, arg interface{}) *Row { +func (n *GenericNamedStmt[T]) QueryRowContext(ctx context.Context, arg any) *Row { args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper) if err != nil { return &Row{err: err} @@ -94,7 +94,7 @@ func (n *GenericNamedStmt[T]) QueryRowContext(ctx context.Context, arg interface // MustExecContext execs a NamedStmt, panicing on error // Any named placeholder parameters are replaced with fields from arg. -func (n *GenericNamedStmt[T]) MustExecContext(ctx context.Context, arg interface{}) sql.Result { +func (n *GenericNamedStmt[T]) MustExecContext(ctx context.Context, arg any) sql.Result { res, err := n.ExecContext(ctx, arg) if err != nil { panic(err) @@ -104,7 +104,7 @@ func (n *GenericNamedStmt[T]) MustExecContext(ctx context.Context, arg interface // QueryxContext using this NamedStmt // Any named placeholder parameters are replaced with fields from arg. -func (n *GenericNamedStmt[T]) QueryxContext(ctx context.Context, arg interface{}) (*Rows, error) { +func (n *GenericNamedStmt[T]) QueryxContext(ctx context.Context, arg any) (*Rows, error) { r, err := n.QueryContext(ctx, arg) if err != nil { return nil, err @@ -115,13 +115,13 @@ func (n *GenericNamedStmt[T]) QueryxContext(ctx context.Context, arg interface{} // QueryRowxContext 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 *GenericNamedStmt[T]) QueryRowxContext(ctx context.Context, arg interface{}) *Row { +func (n *GenericNamedStmt[T]) QueryRowxContext(ctx context.Context, arg any) *Row { return n.QueryRowContext(ctx, arg) } // SelectContext using this NamedStmt // Any named placeholder parameters are replaced with fields from arg. -func (n *GenericNamedStmt[T]) SelectContext(ctx context.Context, dest interface{}, arg interface{}) error { +func (n *GenericNamedStmt[T]) SelectContext(ctx context.Context, dest any, arg any) error { rows, err := n.QueryxContext(ctx, arg) if err != nil { return err @@ -133,14 +133,14 @@ func (n *GenericNamedStmt[T]) SelectContext(ctx context.Context, dest interface{ // GetContext using this NamedStmt // Any named placeholder parameters are replaced with fields from arg. -func (n *GenericNamedStmt[T]) GetContext(ctx context.Context, dest interface{}, arg interface{}) error { +func (n *GenericNamedStmt[T]) GetContext(ctx context.Context, dest any, arg any) error { r := n.QueryRowxContext(ctx, arg) return r.scanAny(dest, false) } // OneContext get a single row using this NamedStmt // Any named placeholder parameters are replaced with fields from arg. -func (n *GenericNamedStmt[T]) OneContext(ctx context.Context, arg interface{}) (T, error) { +func (n *GenericNamedStmt[T]) OneContext(ctx context.Context, arg any) (T, error) { r := n.QueryRowxContext(ctx, arg) var dest T err := r.scanAny(&dest, false) @@ -148,7 +148,7 @@ func (n *GenericNamedStmt[T]) OneContext(ctx context.Context, arg interface{}) ( } // AllContext performs a query using the NamedStmt and returns all rows for use with range. -func (n *GenericNamedStmt[T]) AllContext(ctx context.Context, arg interface{}) iter.Seq2[T, error] { +func (n *GenericNamedStmt[T]) AllContext(ctx context.Context, arg any) iter.Seq2[T, error] { rows, err := n.QueryxContext(ctx, arg) if err != nil { panic(err) @@ -174,7 +174,7 @@ func (n *GenericNamedStmt[T]) AllContext(ctx context.Context, arg interface{}) i // NamedQueryContext 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 NamedQueryContext(ctx context.Context, e ExtContext, query string, arg interface{}) (*Rows, error) { +func NamedQueryContext(ctx context.Context, e ExtContext, query string, arg any) (*Rows, error) { q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e)) if err != nil { return nil, err @@ -185,7 +185,7 @@ func NamedQueryContext(ctx context.Context, e ExtContext, query string, arg inte // NamedExecContext 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 NamedExecContext(ctx context.Context, e ExtContext, query string, arg interface{}) (sql.Result, error) { +func NamedExecContext(ctx context.Context, e ExtContext, query string, arg any) (sql.Result, error) { q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e)) if err != nil { return nil, err diff --git a/named_test.go b/named_test.go index 95e275d..6e9512c 100644 --- a/named_test.go +++ b/named_test.go @@ -77,7 +77,6 @@ func TestCompileQuery(t *testing.T) { } for _, test := range table { - test := test n := test.d if n == "" { n = test.Q @@ -125,7 +124,7 @@ type Test struct { t *testing.T } -func (t Test) Error(err error, msg ...interface{}) { +func (t Test) Error(err error, msg ...any) { t.t.Helper() if err != nil { if len(msg) == 0 { @@ -136,7 +135,7 @@ func (t Test) Error(err error, msg ...interface{}) { } } -func (t Test) Errorf(err error, format string, args ...interface{}) { +func (t Test) Errorf(err error, format string, args ...any) { t.t.Helper() if err != nil { t.t.Errorf(format, args...) @@ -256,7 +255,7 @@ func TestNamedQueries(t *testing.T) { test.Error(err) // test map batch inserts - slsMap := []map[string]interface{}{ + slsMap := []map[string]any{ {"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"}, @@ -266,7 +265,7 @@ func TestNamedQueries(t *testing.T) { VALUES (:first_name, :last_name, :email) ;--`, slsMap) test.Error(err) - type A map[string]interface{} + type A map[string]any typedMap := []A{ {"first_name": "Ardie", "last_name": "Savea", "email": "asavea@ab.co.nz"}, diff --git a/reflectx/reflect_test.go b/reflectx/reflect_test.go index bfdfb15..bf46fd0 100644 --- a/reflectx/reflect_test.go +++ b/reflectx/reflect_test.go @@ -62,7 +62,7 @@ func TestBasicEmbedded(t *testing.T) { z.Bar.Foo.A = 3 zv := reflect.ValueOf(z) - fields := m.TypeMap(reflect.TypeOf(z)) + fields := m.TypeMap(reflect.TypeFor[Baz]()) if len(fields.Index) != 5 { t.Errorf("Expecting 5 fields") @@ -103,10 +103,9 @@ func TestEmbeddedSimple(t *testing.T) { type Item struct { ID MyID } - z := Item{} m := NewMapper("db") - m.TypeMap(reflect.TypeOf(z)) + m.TypeMap(reflect.TypeFor[Item]()) } func TestBasicEmbeddedWithTags(t *testing.T) { @@ -132,7 +131,7 @@ func TestBasicEmbeddedWithTags(t *testing.T) { z.Bar.Foo.A = 3 zv := reflect.ValueOf(z) - fields := m.TypeMap(reflect.TypeOf(z)) + fields := m.TypeMap(reflect.TypeFor[Baz]()) if len(fields.Index) != 5 { t.Errorf("Expecting 5 fields") @@ -171,7 +170,7 @@ func TestBasicEmbeddedWithSameName(t *testing.T) { z.Foo.Foo = 3 zv := reflect.ValueOf(z) - fields := m.TypeMap(reflect.TypeOf(z)) + fields := m.TypeMap(reflect.TypeFor[FooExt]()) if len(fields.Index) != 4 { t.Errorf("Expecting 3 fields, found %d", len(fields.Index)) @@ -273,7 +272,7 @@ func TestInlineStruct(t *testing.T) { em := person{Employee: Employee{Name: "Joe", ID: 2}, Boss: Boss{Name: "Dick", ID: 1}} ev := reflect.ValueOf(em) - fields := m.TypeMap(reflect.TypeOf(em)) + fields := m.TypeMap(reflect.TypeFor[person]()) if len(fields.Index) != 6 { t.Errorf("Expecting 6 fields") } @@ -293,8 +292,7 @@ func TestRecursiveStruct(t *testing.T) { Parent *Person } m := NewMapperFunc("db", strings.ToLower) - var p *Person - m.TypeMap(reflect.TypeOf(p)) + m.TypeMap(reflect.TypeFor[*Person]()) } func TestFieldsEmbedded(t *testing.T) { @@ -321,7 +319,7 @@ func TestFieldsEmbedded(t *testing.T) { pp.Place.Name = "Toronto" pp.Article.Title = "Best city ever" - fields := m.TypeMap(reflect.TypeOf(pp)) + fields := m.TypeMap(reflect.TypeFor[PP]()) // for i, f := range fields { // log.Println(i, f) // } @@ -381,7 +379,7 @@ func TestFieldsEmbedded(t *testing.T) { t.Errorf("Expecting required option to be set") } - trs := m.TraversalsByName(reflect.TypeOf(pp), []string{"person.name", "name", "title"}) + trs := m.TraversalsByName(reflect.TypeFor[PP](), []string{"person.name", "name", "title"}) if !reflect.DeepEqual(trs, [][]int{{0, 0}, {1, 0}, {2, 0}}) { t.Errorf("Expecting traversal: %v", trs) } @@ -407,13 +405,6 @@ func TestFieldsNested(t *testing.T) { Reviewer Person } - pp := PP{ - Author: Person{Name: "Peter"}, - Place: Place{Name: "Toronto"}, - Article: Article{Title: "Best city ever"}, - Reviewer: Person{Name: "Reviewer Name"}, - } - testCases := []struct { name string traversalNames []string @@ -444,7 +435,7 @@ func TestFieldsNested(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - trs := m.TraversalsByName(reflect.TypeOf(pp), tc.traversalNames) + trs := m.TraversalsByName(reflect.TypeFor[PP](), tc.traversalNames) assert.Equal(t, tc.expected, trs) assert.Equal(t, tc.expected, trs) }) @@ -464,7 +455,7 @@ func TestPtrFields(t *testing.T) { post := &Post{Author: "Joe", Asset: &Asset{Title: "Hiyo"}} pv := reflect.ValueOf(post) - fields := m.TypeMap(reflect.TypeOf(post)) + fields := m.TypeMap(reflect.TypeFor[*Post]()) if len(fields.Index) != 3 { t.Errorf("Expecting 3 fields") } @@ -501,7 +492,7 @@ func TestNamedPtrFields(t *testing.T) { post := &Post{Author: "Joe", Asset1: &Asset{Title: "Hiyo", Owner: &User{"Username"}}} // Let Asset2 be nil pv := reflect.ValueOf(post) - fields := m.TypeMap(reflect.TypeOf(post)) + fields := m.TypeMap(reflect.TypeFor[*Post]()) if len(fields.Index) != 9 { t.Errorf("Expecting 9 fields") } @@ -566,8 +557,7 @@ func TestTagNameMapping(t *testing.T) { } return value }) - strategy := Strategy{"1", "Alpah"} - mapping := m.TypeMap(reflect.TypeOf(strategy)) + mapping := m.TypeMap(reflect.TypeFor[Strategy]()) for _, key := range []string{"strategy_id", "STRATEGYNAME"} { if fi := mapping.GetByPath(key); fi == nil { @@ -584,8 +574,7 @@ func TestMapping(t *testing.T) { } m := NewMapperFunc("db", strings.ToLower) - p := Person{1, "Jason", true} - mapping := m.TypeMap(reflect.TypeOf(p)) + mapping := m.TypeMap(reflect.TypeFor[Person]()) for _, key := range []string{"id", "name", "wears_glasses"} { if fi := mapping.GetByPath(key); fi == nil { @@ -598,8 +587,7 @@ func TestMapping(t *testing.T) { Age int Person } - s := SportsPerson{Weight: 100, Age: 30, Person: p} - mapping = m.TypeMap(reflect.TypeOf(s)) + mapping = m.TypeMap(reflect.TypeFor[SportsPerson]()) for _, key := range []string{"id", "name", "wears_glasses", "weight", "age"} { if fi := mapping.GetByPath(key); fi == nil { t.Errorf("Expecting to find key %s in mapping but did not.", key) @@ -612,8 +600,7 @@ func TestMapping(t *testing.T) { IsAllBlack bool `db:"-"` SportsPerson } - r := RugbyPlayer{12, true, false, s} - mapping = m.TypeMap(reflect.TypeOf(r)) + mapping = m.TypeMap(reflect.TypeFor[RugbyPlayer]()) for _, key := range []string{"id", "name", "wears_glasses", "weight", "age", "position", "is_intense"} { if fi := mapping.GetByPath(key); fi == nil { t.Errorf("Expecting to find key %s in mapping but did not.", key) @@ -671,7 +658,7 @@ func TestGetByTraversal(t *testing.T) { } m := NewMapperFunc("db", func(n string) string { return n }) - tm := m.TypeMap(reflect.TypeOf(A{})) + tm := m.TypeMap(reflect.TypeFor[A]()) for i, tc := range testCases { fi := tm.GetByTraversal(tc.Index) @@ -727,7 +714,7 @@ func TestMapperMethodsByName(t *testing.T) { testCases := []struct { Name string ExpectInvalid bool - ExpectedValue interface{} + ExpectedValue any ExpectedIndexes []int }{ { @@ -855,9 +842,9 @@ func TestFieldByIndexes(t *testing.T) { A2 *B } testCases := []struct { - value interface{} + value any indexes []int - expectedValue interface{} + expectedValue any readOnly bool }{ { @@ -904,7 +891,7 @@ func TestFieldByIndexes(t *testing.T) { } func TestMustBe(t *testing.T) { - typ := reflect.TypeOf(E1{}) + typ := reflect.TypeFor[E1]() mustBe(typ, reflect.Struct) defer func() { @@ -925,7 +912,7 @@ func TestMustBe(t *testing.T) { } }() - typ = reflect.TypeOf("string") + typ = reflect.TypeFor[string]() mustBe(typ, reflect.Struct) t.Fatal("got here, didn't expect to") } @@ -1026,7 +1013,7 @@ func BenchmarkTraversalsByName(b *testing.B) { } m := NewMapper("") - t := reflect.TypeOf(D{}) + t := reflect.TypeFor[D]() names := []string{"C", "B", "A", "Value"} b.ResetTimer() @@ -1056,7 +1043,7 @@ func BenchmarkTraversalsByNameFunc(b *testing.B) { } m := NewMapper("") - t := reflect.TypeOf(D{}) + t := reflect.TypeFor[D]() names := []string{"C", "B", "A", "Z", "Y"} b.ResetTimer() diff --git a/sqlx.go b/sqlx.go index e3de36c..50824b6 100644 --- a/sqlx.go +++ b/sqlx.go @@ -77,27 +77,27 @@ func isScannable(t reflect.Type) bool { // ColScanner is an interface used by MapScan and SliceScan type ColScanner interface { Columns() ([]string, error) - Scan(dest ...interface{}) error + Scan(dest ...any) error Err() error } // Queryer is an interface used by Get and Select type Queryer interface { - Query(query string, args ...interface{}) (*sql.Rows, error) - Queryx(query string, args ...interface{}) (*Rows, error) - QueryRowx(query string, args ...interface{}) *Row + Query(query string, args ...any) (*sql.Rows, error) + Queryx(query string, args ...any) (*Rows, error) + QueryRowx(query string, args ...any) *Row } // Execer is an interface used by MustExec and LoadFile type Execer interface { - Exec(query string, args ...interface{}) (sql.Result, error) + Exec(query string, args ...any) (sql.Result, error) } // Binder is an interface for something which can bind queries (Tx, DB) type binder interface { DriverName() string Rebind(string) string - BindNamed(string, interface{}) (string, []interface{}, error) + BindNamed(string, any) (string, []any, error) } // Ext is a union interface which can bind, query, and exec, used by @@ -119,7 +119,7 @@ type optionalContainer interface { } // getOptions get options for the interface -func getOptions(i interface{}) *dbOptions { +func getOptions(i any) *dbOptions { switch v := i.(type) { case DB: return v.options @@ -148,7 +148,7 @@ func getOptions(i interface{}) *dbOptions { } } -func mapperFor(i interface{}) *reflectx.Mapper { +func mapperFor(i any) *reflectx.Mapper { switch i := i.(type) { case DB: return i.Mapper @@ -163,10 +163,10 @@ func mapperFor(i interface{}) *reflectx.Mapper { } } -var _scannerInterface = reflect.TypeOf((*sql.Scanner)(nil)).Elem() +var _scannerInterface = reflect.TypeFor[sql.Scanner]() //lint:ignore U1000 ignoring this for now -var _valuerInterface = reflect.TypeOf((*driver.Valuer)(nil)).Elem() +var _valuerInterface = reflect.TypeFor[driver.Valuer]() // Row is a reimplementation of sql.Row in order to gain access to the underlying // sql.Rows.Columns() data, necessary for StructScan. @@ -180,7 +180,7 @@ type Row struct { // Scan is a fixed implementation of sql.Row.Scan, which does not discard the // underlying error from the internal rows object if it exists. // Returns ErrMultiRows if the result set contains more than one row. -func (r *Row) Scan(dest ...interface{}) error { +func (r *Row) Scan(dest ...any) error { if r.err != nil { return r.err } @@ -251,21 +251,21 @@ type Queryable interface { QueryerContext Preparer - GetContext(context.Context, interface{}, string, ...interface{}) error - SelectContext(context.Context, interface{}, string, ...interface{}) error - Get(interface{}, string, ...interface{}) error - MustExecContext(context.Context, string, ...interface{}) sql.Result + GetContext(context.Context, any, string, ...any) error + SelectContext(context.Context, any, string, ...any) error + Get(any, string, ...any) error + MustExecContext(context.Context, string, ...any) sql.Result PreparexContext(context.Context, string) (*Stmt, error) - QueryRowContext(context.Context, string, ...interface{}) *sql.Row - Select(interface{}, string, ...interface{}) error - QueryRow(string, ...interface{}) *sql.Row + QueryRowContext(context.Context, string, ...any) *sql.Row + Select(any, string, ...any) error + QueryRow(string, ...any) *sql.Row PrepareNamedContext(context.Context, string) (*NamedStmt, error) PrepareNamed(string) (*NamedStmt, error) Preparex(string) (*Stmt, error) - NamedExec(string, interface{}) (sql.Result, error) - NamedExecContext(context.Context, string, interface{}) (sql.Result, error) - MustExec(string, ...interface{}) sql.Result - NamedQuery(string, interface{}) (*Rows, error) + NamedExec(string, any) (sql.Result, error) + NamedExecContext(context.Context, string, any) (sql.Result, error) + MustExec(string, ...any) sql.Result + NamedQuery(string, any) (*Rows, error) } var _ Queryable = (*DB)(nil) @@ -378,32 +378,32 @@ func (db *DB) Unsafe() *DB { } // BindNamed binds a query using the DB driver's bindvar type. -func (db *DB) BindNamed(query string, arg interface{}) (string, []interface{}, error) { +func (db *DB) BindNamed(query string, arg any) (string, []any, error) { return bindNamedMapper(BindType(db.driverName), query, arg, db.Mapper) } // NamedQuery using this DB. // Any named placeholder parameters are replaced with fields from arg. -func (db *DB) NamedQuery(query string, arg interface{}) (*Rows, error) { +func (db *DB) NamedQuery(query string, arg any) (*Rows, error) { return NamedQuery(db, query, arg) } // NamedExec using this DB. // Any named placeholder parameters are replaced with fields from arg. -func (db *DB) NamedExec(query string, arg interface{}) (sql.Result, error) { +func (db *DB) NamedExec(query string, arg any) (sql.Result, error) { return NamedExec(db, query, arg) } // Select using this DB. // Any placeholder parameters are replaced with supplied args. -func (db *DB) Select(dest interface{}, query string, args ...interface{}) error { +func (db *DB) Select(dest any, query string, args ...any) error { return Select(db, dest, query, args...) } // Get using this DB. // Any placeholder parameters are replaced with supplied args. // An error is returned if the result set is empty or contains more than one row. -func (db *DB) Get(dest interface{}, query string, args ...interface{}) error { +func (db *DB) Get(dest any, query string, args ...any) error { return Get(db, dest, query, args...) } @@ -428,7 +428,7 @@ func (db *DB) Beginx() (*Tx, error) { // Queryx queries the database and returns an *sqlx.Rows. // Any placeholder parameters are replaced with supplied args. -func (db *DB) Queryx(query string, args ...interface{}) (*Rows, error) { +func (db *DB) Queryx(query string, args ...any) (*Rows, error) { r, err := db.DB.Query(query, args...) if err != nil { return nil, err @@ -438,14 +438,14 @@ func (db *DB) Queryx(query string, args ...interface{}) (*Rows, error) { // QueryRowx queries the database and returns an *sqlx.Row. // Any placeholder parameters are replaced with supplied args. -func (db *DB) QueryRowx(query string, args ...interface{}) *Row { +func (db *DB) QueryRowx(query string, args ...any) *Row { rows, err := db.DB.Query(query, args...) return &Row{rows: rows, err: err, options: db.options, Mapper: db.Mapper} } // MustExec (panic) runs MustExec using this database. // Any placeholder parameters are replaced with supplied args. -func (db *DB) MustExec(query string, args ...interface{}) sql.Result { +func (db *DB) MustExec(query string, args ...any) sql.Result { return MustExec(db, query, args...) } @@ -494,31 +494,31 @@ func (tx *Tx) Unsafe() *Tx { } // BindNamed binds a query within a transaction's bindvar type. -func (tx *Tx) BindNamed(query string, arg interface{}) (string, []interface{}, error) { +func (tx *Tx) BindNamed(query string, arg any) (string, []any, error) { return bindNamedMapper(BindType(tx.driverName), query, arg, tx.Mapper) } // NamedQuery within a transaction. // Any named placeholder parameters are replaced with fields from arg. -func (tx *Tx) NamedQuery(query string, arg interface{}) (*Rows, error) { +func (tx *Tx) NamedQuery(query string, arg any) (*Rows, error) { return NamedQuery(tx, query, arg) } // NamedExec a named query within a transaction. // Any named placeholder parameters are replaced with fields from arg. -func (tx *Tx) NamedExec(query string, arg interface{}) (sql.Result, error) { +func (tx *Tx) NamedExec(query string, arg any) (sql.Result, error) { return NamedExec(tx, query, arg) } // Select within a transaction. // Any placeholder parameters are replaced with supplied args. -func (tx *Tx) Select(dest interface{}, query string, args ...interface{}) error { +func (tx *Tx) Select(dest any, query string, args ...any) error { return Select(tx, dest, query, args...) } // Queryx within a transaction. // Any placeholder parameters are replaced with supplied args. -func (tx *Tx) Queryx(query string, args ...interface{}) (*Rows, error) { +func (tx *Tx) Queryx(query string, args ...any) (*Rows, error) { r, err := tx.Tx.Query(query, args...) if err != nil { return nil, err @@ -528,7 +528,7 @@ func (tx *Tx) Queryx(query string, args ...interface{}) (*Rows, error) { // QueryRowx within a transaction. // Any placeholder parameters are replaced with supplied args. -func (tx *Tx) QueryRowx(query string, args ...interface{}) *Row { +func (tx *Tx) QueryRowx(query string, args ...any) *Row { rows, err := tx.Tx.Query(query, args...) return &Row{rows: rows, err: err, options: tx.options, Mapper: tx.Mapper} } @@ -536,13 +536,13 @@ func (tx *Tx) QueryRowx(query string, args ...interface{}) *Row { // Get within a transaction. // Any placeholder parameters are replaced with supplied args. // An error is returned if the result set is empty or contains more than one row. -func (tx *Tx) Get(dest interface{}, query string, args ...interface{}) error { +func (tx *Tx) Get(dest any, query string, args ...any) error { return Get(tx, dest, query, args...) } // MustExec runs MustExec within a transaction. // Any placeholder parameters are replaced with supplied args. -func (tx *Tx) MustExec(query string, args ...interface{}) sql.Result { +func (tx *Tx) MustExec(query string, args ...any) sql.Result { return MustExec(tx, query, args...) } @@ -553,7 +553,7 @@ func (tx *Tx) Preparex(query string) (*Stmt, error) { // Stmtx returns a version of the prepared statement which runs within a transaction. Provided // stmt can be either *sql.Stmt or *sqlx.Stmt. -func (tx *Tx) Stmtx(stmt interface{}) *GenericStmt[any] { +func (tx *Tx) Stmtx(stmt any) *GenericStmt[any] { var s *sql.Stmt switch v := stmt.(type) { case Stmt: @@ -601,34 +601,34 @@ func (s *GenericStmt[T]) Unsafe() *GenericStmt[T] { // Select using the prepared statement. // Any placeholder parameters are replaced with supplied args. -func (s *GenericStmt[T]) Select(dest interface{}, args ...interface{}) error { +func (s *GenericStmt[T]) Select(dest any, args ...any) error { return Select(&qStmt[T]{s}, dest, "", args...) } // Get using the prepared statement. // Any placeholder parameters are replaced with supplied args. // An error is returned if the result set is empty or contains more than one row. -func (s *GenericStmt[T]) Get(dest interface{}, args ...interface{}) error { +func (s *GenericStmt[T]) Get(dest any, args ...any) error { return Get(&qStmt[T]{s}, dest, "", args...) } // MustExec (panic) using this statement. Note that the query portion of the error // output will be blank, as Stmt does not expose its query. // Any placeholder parameters are replaced with supplied args. -func (s *GenericStmt[T]) MustExec(args ...interface{}) sql.Result { +func (s *GenericStmt[T]) MustExec(args ...any) sql.Result { return MustExec(&qStmt[T]{s}, "", args...) } // QueryRowx using this statement. // Any placeholder parameters are replaced with supplied args. -func (s *GenericStmt[T]) QueryRowx(args ...interface{}) *Row { +func (s *GenericStmt[T]) QueryRowx(args ...any) *Row { qs := &qStmt[T]{s} return qs.QueryRowx("", args...) } // Queryx using this statement. // Any placeholder parameters are replaced with supplied args. -func (s *GenericStmt[T]) Queryx(args ...interface{}) (*Rows, error) { +func (s *GenericStmt[T]) Queryx(args ...any) (*Rows, error) { qs := &qStmt[T]{s} return qs.Queryx("", args...) } @@ -636,14 +636,14 @@ func (s *GenericStmt[T]) Queryx(args ...interface{}) (*Rows, error) { // One get one row using the prepared statement. // Any placeholder parameters are replaced with supplied args. // An error is returned if the result set is empty or contains more than one row. -func (s *GenericStmt[T]) One(args ...interface{}) (T, error) { +func (s *GenericStmt[T]) One(args ...any) (T, error) { var dest T err := Get(&qStmt[T]{s}, &dest, "", args...) return dest, err } // All performs a query using the NamedStmt and returns all rows for use with range. -func (s *GenericStmt[T]) All(args ...interface{}) iter.Seq2[T, error] { +func (s *GenericStmt[T]) All(args ...any) iter.Seq2[T, error] { rows, err := s.Queryx(args...) if err != nil { panic(err) @@ -664,7 +664,7 @@ func (s *GenericStmt[T]) All(args ...interface{}) iter.Seq2[T, error] { } // List performs a query using the statement and returns all rows as a slice of T. -func (s *GenericStmt[T]) List(args ...interface{}) ([]T, error) { +func (s *GenericStmt[T]) List(args ...any) ([]T, error) { var dests []T err := s.Select(&dests, args...) return dests, err @@ -698,11 +698,11 @@ func (q *qStmt[T]) getOptions() *dbOptions { return q.Stmt.options } -func (q *qStmt[T]) Query(query string, args ...interface{}) (*sql.Rows, error) { +func (q *qStmt[T]) Query(query string, args ...any) (*sql.Rows, error) { return q.Stmt.Query(args...) } -func (q *qStmt[T]) Queryx(query string, args ...interface{}) (*Rows, error) { +func (q *qStmt[T]) Queryx(query string, args ...any) (*Rows, error) { r, err := q.Stmt.Query(args...) if err != nil { return nil, err @@ -710,12 +710,12 @@ func (q *qStmt[T]) Queryx(query string, args ...interface{}) (*Rows, error) { return &Rows{Rows: r, options: q.Stmt.options, Mapper: q.Stmt.Mapper}, err } -func (q *qStmt[T]) QueryRowx(query string, args ...interface{}) *Row { +func (q *qStmt[T]) QueryRowx(query string, args ...any) *Row { rows, err := q.Stmt.Query(args...) return &Row{rows: rows, err: err, options: q.Stmt.options, Mapper: q.Stmt.Mapper} } -func (q *qStmt[T]) Exec(query string, args ...interface{}) (sql.Result, error) { +func (q *qStmt[T]) Exec(query string, args ...any) (sql.Result, error) { return q.Stmt.Exec(args...) } @@ -728,16 +728,16 @@ type Rows struct { // these fields cache memory use for a rows during iteration w/ structScan started bool fields [][]int - values []interface{} + values []any } // SliceScan using this Rows. -func (r *Rows) SliceScan() ([]interface{}, error) { +func (r *Rows) SliceScan() ([]any, error) { return SliceScan(r) } // MapScan using this Rows. -func (r *Rows) MapScan(dest map[string]interface{}) error { +func (r *Rows) MapScan(dest map[string]any) error { return MapScan(r, dest) } @@ -746,7 +746,7 @@ func (r *Rows) MapScan(dest map[string]interface{}) error { // prohibitive. *Rows.StructScan caches the reflect work of matching up column // positions to fields to avoid that overhead per scan, which means it is not safe // to run StructScan on the same Rows instance with different struct types. -func (r *Rows) StructScan(dest interface{}) error { +func (r *Rows) StructScan(dest any) error { v := reflect.ValueOf(dest) if v.Kind() != reflect.Ptr { @@ -769,7 +769,7 @@ func (r *Rows) StructScan(dest interface{}) error { return fmt.Errorf("missing destination name %s in %T", columns[f], dest) } } - r.values = make([]interface{}, len(columns)) + r.values = make([]any, len(columns)) r.started = true } @@ -858,7 +858,7 @@ func preparexStmt(p Preparer, query string) (*Stmt, error) { // the result set must have only one column. Otherwise, StructScan is used. // The *sql.Rows are closed automatically. // Any placeholder parameters are replaced with supplied args. -func Select(q Queryer, dest interface{}, query string, args ...interface{}) error { +func Select(q Queryer, dest any, query string, args ...any) error { rows, err := q.Queryx(query, args...) if err != nil { return err @@ -873,7 +873,7 @@ func Select(q Queryer, dest interface{}, query string, args ...interface{}) erro // StructScan is used. Get will return sql.ErrNoRows like row.Scan would. // Any placeholder parameters are replaced with supplied args. // An error is returned if the result set is empty or contains more than one row. -func Get(q Queryer, dest interface{}, query string, args ...interface{}) error { +func Get(q Queryer, dest any, query string, args ...any) error { r := q.QueryRowx(query, args...) return r.scanAny(dest, false) } @@ -883,7 +883,7 @@ func Get(q Queryer, dest interface{}, query string, args ...interface{}) error { // StructScan is used. Get will return sql.ErrNoRows like row.Scan would. // Any placeholder parameters are replaced with supplied args. // An error is returned if the result set is empty or contains more than one row. -func One[T any](q Queryer, query string, args ...interface{}) (T, error) { +func One[T any](q Queryer, query string, args ...any) (T, error) { r := q.QueryRowx(query, args...) var dest T err := r.scanAny(&dest, false) @@ -891,7 +891,7 @@ func One[T any](q Queryer, query string, args ...interface{}) (T, error) { } // List executes a query using the provided Queryer, and returns a slice of T for each row. -func List[T any](q Queryer, query string, args ...interface{}) ([]T, error) { +func List[T any](q Queryer, query string, args ...any) ([]T, error) { var dest []T err := Select(q, &dest, query, args...) return dest, err @@ -923,7 +923,7 @@ func LoadFile(e Execer, path string) (*sql.Result, error) { // MustExec execs the query using e and panics if there was an error. // Any placeholder parameters are replaced with supplied args. -func MustExec(e Execer, query string, args ...interface{}) sql.Result { +func MustExec(e Execer, query string, args ...any) sql.Result { res, err := e.Exec(query, args...) if err != nil { panic(err) @@ -932,16 +932,16 @@ func MustExec(e Execer, query string, args ...interface{}) sql.Result { } // SliceScan using this Rows. -func (r *Row) SliceScan() ([]interface{}, error) { +func (r *Row) SliceScan() ([]any, error) { return SliceScan(r) } // MapScan using this Rows. -func (r *Row) MapScan(dest map[string]interface{}) error { +func (r *Row) MapScan(dest map[string]any) error { return MapScan(r, dest) } -func (r *Row) scanAny(dest interface{}, structOnly bool) error { +func (r *Row) scanAny(dest any, structOnly bool) error { if r.err != nil { return r.err } @@ -988,7 +988,7 @@ func (r *Row) scanAny(dest interface{}, structOnly bool) error { return fmt.Errorf("missing destination name %s in %T", columns[f], dest) } } - values := make([]interface{}, len(columns)) + values := make([]any, len(columns)) err = fieldsByTraversal(v, fields, values) if err != nil { @@ -999,7 +999,7 @@ func (r *Row) scanAny(dest interface{}, structOnly bool) error { } // StructScan a single Row into dest. -func (r *Row) StructScan(dest interface{}) error { +func (r *Row) StructScan(dest any) error { return r.scanAny(dest, true) } @@ -1008,16 +1008,16 @@ func (r *Row) StructScan(dest interface{}) error { // is not known. Because you can pass an []interface{} directly to Scan, // it's recommended that you do that as it will not have to allocate new // slices per row. -func SliceScan(r ColScanner) ([]interface{}, error) { +func SliceScan(r ColScanner) ([]any, error) { // ignore r.started, since we needn't use reflect for anything. columns, err := r.Columns() if err != nil { - return []interface{}{}, err + return []any{}, err } - values := make([]interface{}, len(columns)) + values := make([]any, len(columns)) for i := range values { - values[i] = new(interface{}) + values[i] = new(any) } err = r.Scan(values...) @@ -1027,7 +1027,7 @@ func SliceScan(r ColScanner) ([]interface{}, error) { } for i := range columns { - values[i] = *(values[i].(*interface{})) + values[i] = *(values[i].(*any)) } return values, r.Err() @@ -1040,16 +1040,16 @@ func SliceScan(r ColScanner) ([]interface{}, error) { // This will modify the map sent to it in place, so reuse the same map with // care. Columns which occur more than once in the result will overwrite // each other! -func MapScan(r ColScanner, dest map[string]interface{}) error { +func MapScan(r ColScanner, dest map[string]any) error { // ignore r.started, since we needn't use reflect for anything. columns, err := r.Columns() if err != nil { return err } - values := make([]interface{}, len(columns)) + values := make([]any, len(columns)) for i := range values { - values[i] = new(interface{}) + values[i] = new(any) } err = r.Scan(values...) @@ -1058,7 +1058,7 @@ func MapScan(r ColScanner, dest map[string]interface{}) error { } for i, column := range columns { - dest[column] = *(values[i].(*interface{})) + dest[column] = *(values[i].(*any)) } return r.Err() @@ -1069,7 +1069,7 @@ type rowsi interface { Columns() ([]string, error) Err() error Next() bool - Scan(...interface{}) error + Scan(...any) error } // structOnlyError returns an error appropriate for type when a non-scannable @@ -1102,7 +1102,7 @@ func structOnlyError(t reflect.Type) error { // to `Get` and `Select`. The reason that this has been implemented like this is // this is the only way to not duplicate reflect work in the new API while // maintaining backwards compatibility. -func scanAll(rows rowsi, dest interface{}, structOnly bool) error { +func scanAll(rows rowsi, dest any, structOnly bool) error { var v, vp reflect.Value value := reflect.ValueOf(dest) @@ -1141,7 +1141,7 @@ func scanAll(rows rowsi, dest interface{}, structOnly bool) error { } if !scannable { - var values []interface{} + var values []any var m *reflectx.Mapper switch rows := rows.(type) { @@ -1158,7 +1158,7 @@ func scanAll(rows rowsi, dest interface{}, structOnly bool) error { return fmt.Errorf("missing destination name %s in %T", columns[f], dest) } } - values = make([]interface{}, len(columns)) + values = make([]any, len(columns)) for rows.Next() { // create a new struct type (which returns PtrTo) and indirect it @@ -1210,7 +1210,7 @@ func scanAll(rows rowsi, dest interface{}, structOnly bool) error { // StructScan will scan in the entire rows result, so if you do not want to // allocate structs for the entire result, use Queryx and see sqlx.Rows.StructScan. // If rows is sqlx.Rows, it will use its mapper, otherwise it will use the default. -func StructScan(rows rowsi, dest interface{}) error { +func StructScan(rows rowsi, dest any) error { return scanAll(rows, dest, true) } @@ -1231,7 +1231,7 @@ func baseType(t reflect.Type, expected reflect.Kind) (reflect.Type, error) { // when iterating over many rows. Empty traversals will get an interface pointer. // Because of the necessity of requesting ptrs or values, it's considered a bit too // specialized for inclusion in reflectx itself. -func fieldsByTraversal(v reflect.Value, traversals [][]int, values []interface{}) error { +func fieldsByTraversal(v reflect.Value, traversals [][]int, values []any) error { v = reflect.Indirect(v) if v.Kind() != reflect.Struct { return errors.New("argument not a struct") @@ -1239,14 +1239,14 @@ func fieldsByTraversal(v reflect.Value, traversals [][]int, values []interface{} for i, traversal := range traversals { if len(traversal) == 0 { - values[i] = new(interface{}) + values[i] = new(any) } else if len(traversal) == 1 { values[i] = reflectx.FieldByIndexes(v, traversal).Addr().Interface() } else { // reflectx.FieldByIndexes initializes pointer fields, including pointers to nested structs. // Use optDest to delay it until the first non-NULL value is scanned into a field of a nested struct. // That way we can support LEFT JOINs with optional nested structs. - values[i] = optDest(func() interface{} { + values[i] = optDest(func() any { return reflectx.FieldByIndexes(v, traversal).Addr().Interface() }) } @@ -1265,10 +1265,10 @@ func missingFields(traversals [][]int) (field int, err error) { // optDest will only forward the Scan to the nested value if // the database value is not nil. -type optDest func() interface{} +type optDest func() any // Scan implements sql.Scanner. -func (dest optDest) Scan(src interface{}) error { +func (dest optDest) Scan(src any) error { if src == nil { return nil } diff --git a/sqlx_context.go b/sqlx_context.go index 4358e75..7d80cfa 100644 --- a/sqlx_context.go +++ b/sqlx_context.go @@ -21,9 +21,9 @@ func ConnectContext(ctx context.Context, driverName, dataSourceName string) (*DB // QueryerContext is an interface used by GetContext and SelectContext type QueryerContext interface { - QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) - QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) - QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row + QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error) + QueryxContext(ctx context.Context, query string, args ...any) (*Rows, error) + QueryRowxContext(ctx context.Context, query string, args ...any) *Row } // PreparerContext is an interface used by PreparexContext. @@ -33,7 +33,7 @@ type PreparerContext interface { // ExecerContext is an interface used by MustExecContext and LoadFileContext type ExecerContext interface { - ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) + ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error) } // ExtContext is a union interface which can bind, query, and exec, with Context @@ -49,7 +49,7 @@ type ExtContext interface { // scannable, then the result set must have only one column. Otherwise, // StructScan is used. The *sql.Rows are closed automatically. // Any placeholder parameters are replaced with supplied args. -func SelectContext(ctx context.Context, q QueryerContext, dest interface{}, query string, args ...interface{}) error { +func SelectContext(ctx context.Context, q QueryerContext, dest any, query string, args ...any) error { rows, err := q.QueryxContext(ctx, query, args...) if err != nil { return err @@ -85,7 +85,7 @@ func preparexContextStmt(ctx context.Context, p PreparerContext, query string) ( // column. Otherwise, StructScan is used. Get will return sql.ErrNoRows like // row.Scan would. Any placeholder parameters are replaced with supplied args. // An error is returned if the result set is empty. -func GetContext(ctx context.Context, q QueryerContext, dest interface{}, query string, args ...interface{}) error { +func GetContext(ctx context.Context, q QueryerContext, dest any, query string, args ...any) error { r := q.QueryRowxContext(ctx, query, args...) return r.scanAny(dest, false) } @@ -95,7 +95,7 @@ func GetContext(ctx context.Context, q QueryerContext, dest interface{}, query s // column. Otherwise, StructScan is used. Get will return sql.ErrNoRows like // row.Scan would. Any placeholder parameters are replaced with supplied args. // An error is returned if the result set is empty. -func OneContext[T any](ctx context.Context, q QueryerContext, query string, args ...interface{}) (T, error) { +func OneContext[T any](ctx context.Context, q QueryerContext, query string, args ...any) (T, error) { var dest T r := q.QueryRowxContext(ctx, query, args...) err := r.scanAny(&dest, false) @@ -103,7 +103,7 @@ func OneContext[T any](ctx context.Context, q QueryerContext, query string, args } // ListContext executes a query using the provided Queryer, and returns a slice of T for each row. -func ListContext[T any](ctx context.Context, q QueryerContext, query string, args ...interface{}) ([]T, error) { +func ListContext[T any](ctx context.Context, q QueryerContext, query string, args ...any) ([]T, error) { var dest []T err := SelectContext(ctx, q, &dest, query, args...) return dest, err @@ -135,7 +135,7 @@ func LoadFileContext(ctx context.Context, e ExecerContext, path string) (*sql.Re // MustExecContext execs the query using e and panics if there was an error. // Any placeholder parameters are replaced with supplied args. -func MustExecContext(ctx context.Context, e ExecerContext, query string, args ...interface{}) sql.Result { +func MustExecContext(ctx context.Context, e ExecerContext, query string, args ...any) sql.Result { res, err := e.ExecContext(ctx, query, args...) if err != nil { panic(err) @@ -150,26 +150,26 @@ func (db *DB) PrepareNamedContext(ctx context.Context, query string) (*NamedStmt // NamedQueryContext using this DB. // Any named placeholder parameters are replaced with fields from arg. -func (db *DB) NamedQueryContext(ctx context.Context, query string, arg interface{}) (*Rows, error) { +func (db *DB) NamedQueryContext(ctx context.Context, query string, arg any) (*Rows, error) { return NamedQueryContext(ctx, db, query, arg) } // NamedExecContext using this DB. // Any named placeholder parameters are replaced with fields from arg. -func (db *DB) NamedExecContext(ctx context.Context, query string, arg interface{}) (sql.Result, error) { +func (db *DB) NamedExecContext(ctx context.Context, query string, arg any) (sql.Result, error) { return NamedExecContext(ctx, db, query, arg) } // SelectContext using this DB. // Any placeholder parameters are replaced with supplied args. -func (db *DB) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error { +func (db *DB) SelectContext(ctx context.Context, dest any, query string, args ...any) error { return SelectContext(ctx, db, dest, query, args...) } // GetContext using this DB. // Any placeholder parameters are replaced with supplied args. // An error is returned if the result set is empty. -func (db *DB) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error { +func (db *DB) GetContext(ctx context.Context, dest any, query string, args ...any) error { return GetContext(ctx, db, dest, query, args...) } @@ -183,7 +183,7 @@ func (db *DB) PreparexContext(ctx context.Context, query string) (*Stmt, error) // QueryxContext queries the database and returns an *sqlx.Rows. // Any placeholder parameters are replaced with supplied args. -func (db *DB) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) { +func (db *DB) QueryxContext(ctx context.Context, query string, args ...any) (*Rows, error) { r, err := db.DB.QueryContext(ctx, query, args...) if err != nil { return nil, err @@ -193,7 +193,7 @@ func (db *DB) QueryxContext(ctx context.Context, query string, args ...interface // QueryRowxContext queries the database and returns an *sqlx.Row. // Any placeholder parameters are replaced with supplied args. -func (db *DB) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row { +func (db *DB) QueryRowxContext(ctx context.Context, query string, args ...any) *Row { rows, err := db.DB.QueryContext(ctx, query, args...) return &Row{rows: rows, err: err, options: db.options, Mapper: db.Mapper} } @@ -215,7 +215,7 @@ func (db *DB) MustBeginTx(ctx context.Context, opts *sql.TxOptions) *Tx { // MustExecContext (panic) runs MustExec using this database. // Any placeholder parameters are replaced with supplied args. -func (db *DB) MustExecContext(ctx context.Context, query string, args ...interface{}) sql.Result { +func (db *DB) MustExecContext(ctx context.Context, query string, args ...any) sql.Result { return MustExecContext(ctx, db, query, args...) } @@ -261,14 +261,14 @@ func (c *Conn) BeginTxx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) { // SelectContext using this Conn. // Any placeholder parameters are replaced with supplied args. -func (c *Conn) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error { +func (c *Conn) SelectContext(ctx context.Context, dest any, query string, args ...any) error { return SelectContext(ctx, c, dest, query, args...) } // GetContext using this Conn. // Any placeholder parameters are replaced with supplied args. // An error is returned if the result set is empty. -func (c *Conn) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error { +func (c *Conn) GetContext(ctx context.Context, dest any, query string, args ...any) error { return GetContext(ctx, c, dest, query, args...) } @@ -282,7 +282,7 @@ func (c *Conn) PreparexContext(ctx context.Context, query string) (*Stmt, error) // QueryxContext queries the database and returns an *sqlx.Rows. // Any placeholder parameters are replaced with supplied args. -func (c *Conn) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) { +func (c *Conn) QueryxContext(ctx context.Context, query string, args ...any) (*Rows, error) { r, err := c.Conn.QueryContext(ctx, query, args...) if err != nil { return nil, err @@ -292,7 +292,7 @@ func (c *Conn) QueryxContext(ctx context.Context, query string, args ...interfac // QueryRowxContext queries the database and returns an *sqlx.Row. // Any placeholder parameters are replaced with supplied args. -func (c *Conn) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row { +func (c *Conn) QueryRowxContext(ctx context.Context, query string, args ...any) *Row { rows, err := c.Conn.QueryContext(ctx, query, args...) return &Row{rows: rows, err: err, options: c.options, Mapper: c.Mapper} } @@ -304,7 +304,7 @@ func (c *Conn) Rebind(query string) string { // StmtxContext returns a version of the prepared statement which runs within a // transaction. Provided stmt can be either *sql.Stmt or *sqlx.Stmt. -func (tx *Tx) StmtxContext(ctx context.Context, stmt interface{}) *GenericStmt[any] { +func (tx *Tx) StmtxContext(ctx context.Context, stmt any) *GenericStmt[any] { var s *sql.Stmt switch v := stmt.(type) { case Stmt: @@ -344,13 +344,13 @@ func (tx *Tx) PrepareNamedContext(ctx context.Context, query string) (*NamedStmt // MustExecContext runs MustExecContext within a transaction. // Any placeholder parameters are replaced with supplied args. -func (tx *Tx) MustExecContext(ctx context.Context, query string, args ...interface{}) sql.Result { +func (tx *Tx) MustExecContext(ctx context.Context, query string, args ...any) sql.Result { return MustExecContext(ctx, tx, query, args...) } // QueryxContext within a transaction and context. // Any placeholder parameters are replaced with supplied args. -func (tx *Tx) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) { +func (tx *Tx) QueryxContext(ctx context.Context, query string, args ...any) (*Rows, error) { r, err := tx.Tx.QueryContext(ctx, query, args...) if err != nil { return nil, err @@ -360,69 +360,69 @@ func (tx *Tx) QueryxContext(ctx context.Context, query string, args ...interface // SelectContext within a transaction and context. // Any placeholder parameters are replaced with supplied args. -func (tx *Tx) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error { +func (tx *Tx) SelectContext(ctx context.Context, dest any, query string, args ...any) error { return SelectContext(ctx, tx, dest, query, args...) } // GetContext within a transaction and context. // Any placeholder parameters are replaced with supplied args. // An error is returned if the result set is empty. -func (tx *Tx) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error { +func (tx *Tx) GetContext(ctx context.Context, dest any, query string, args ...any) error { return GetContext(ctx, tx, dest, query, args...) } // QueryRowxContext within a transaction and context. // Any placeholder parameters are replaced with supplied args. -func (tx *Tx) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row { +func (tx *Tx) QueryRowxContext(ctx context.Context, query string, args ...any) *Row { rows, err := tx.Tx.QueryContext(ctx, query, args...) return &Row{rows: rows, err: err, options: tx.options, Mapper: tx.Mapper} } // NamedExecContext using this Tx. // Any named placeholder parameters are replaced with fields from arg. -func (tx *Tx) NamedExecContext(ctx context.Context, query string, arg interface{}) (sql.Result, error) { +func (tx *Tx) NamedExecContext(ctx context.Context, query string, arg any) (sql.Result, error) { return NamedExecContext(ctx, tx, query, arg) } // SelectContext using the prepared statement. // Any placeholder parameters are replaced with supplied args. -func (s *GenericStmt[T]) SelectContext(ctx context.Context, dest interface{}, args ...interface{}) error { +func (s *GenericStmt[T]) SelectContext(ctx context.Context, dest any, args ...any) error { return SelectContext(ctx, &qStmt[T]{s}, dest, "", args...) } // GetContext using the prepared statement. // Any placeholder parameters are replaced with supplied args. // An error is returned if the result set is empty. -func (s *GenericStmt[T]) GetContext(ctx context.Context, dest interface{}, args ...interface{}) error { +func (s *GenericStmt[T]) GetContext(ctx context.Context, dest any, args ...any) error { return GetContext(ctx, &qStmt[T]{s}, dest, "", args...) } // MustExecContext (panic) using this statement. Note that the query portion of // the error output will be blank, as Stmt does not expose its query. // Any placeholder parameters are replaced with supplied args. -func (s *GenericStmt[T]) MustExecContext(ctx context.Context, args ...interface{}) sql.Result { +func (s *GenericStmt[T]) MustExecContext(ctx context.Context, args ...any) sql.Result { return MustExecContext(ctx, &qStmt[T]{s}, "", args...) } // QueryRowxContext using this statement. // Any placeholder parameters are replaced with supplied args. -func (s *GenericStmt[T]) QueryRowxContext(ctx context.Context, args ...interface{}) *Row { +func (s *GenericStmt[T]) QueryRowxContext(ctx context.Context, args ...any) *Row { qs := &qStmt[T]{s} return qs.QueryRowxContext(ctx, "", args...) } // QueryxContext using this statement. // Any placeholder parameters are replaced with supplied args. -func (s *GenericStmt[T]) QueryxContext(ctx context.Context, args ...interface{}) (*Rows, error) { +func (s *GenericStmt[T]) QueryxContext(ctx context.Context, args ...any) (*Rows, error) { qs := &qStmt[T]{s} return qs.QueryxContext(ctx, "", args...) } -func (q *qStmt[T]) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) { +func (q *qStmt[T]) QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error) { return q.Stmt.QueryContext(ctx, args...) } -func (q *qStmt[T]) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) { +func (q *qStmt[T]) QueryxContext(ctx context.Context, query string, args ...any) (*Rows, error) { r, err := q.Stmt.QueryContext(ctx, args...) if err != nil { return nil, err @@ -430,11 +430,11 @@ func (q *qStmt[T]) QueryxContext(ctx context.Context, query string, args ...inte return &Rows{Rows: r, options: q.Stmt.options, Mapper: q.Stmt.Mapper}, err } -func (q *qStmt[T]) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row { +func (q *qStmt[T]) QueryRowxContext(ctx context.Context, query string, args ...any) *Row { rows, err := q.Stmt.QueryContext(ctx, args...) return &Row{rows: rows, err: err, options: q.Stmt.options, Mapper: q.Stmt.Mapper} } -func (q *qStmt[T]) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) { +func (q *qStmt[T]) ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error) { return q.Stmt.ExecContext(ctx, args...) } diff --git a/sqlx_context_test.go b/sqlx_context_test.go index c0762cc..c60b654 100644 --- a/sqlx_context_test.go +++ b/sqlx_context_test.go @@ -176,7 +176,7 @@ func TestMissingNamesContextContext(t *testing.T) { t.Error("expected NamedStmt to be unsafe but its underlying stmt did not inherit safety") } pps := []PersonPlus{} - err = nstmt.Select(&pps, map[string]interface{}{"name": "Jason"}) + err = nstmt.Select(&pps, map[string]any{"name": "Jason"}) require.NoError(t, err) if len(pps) != 1 { t.Errorf("Expected 1 person back, got %d", len(pps)) @@ -196,7 +196,7 @@ func TestMissingNamesContextContext(t *testing.T) { t.Error("expected newly unsafed NamedStmt to be unsafe") } pps := []PersonPlus{} - err = nstmt.Select(&pps, map[string]interface{}{"name": "Jason"}) + err = nstmt.Select(&pps, map[string]any{"name": "Jason"}) require.NoError(t, err) if len(pps) != 1 { t.Errorf("Expected 1 person back, got %d", len(pps)) @@ -229,7 +229,7 @@ func TestMissingNamesContextContext(t *testing.T) { if !getOptions(ps).allowMissingFields() { t.Error("NamedStmt did not inherit unsafe") } - pps, err := ps.List(map[string]interface{}{"name": "Jason"}) + pps, err := ps.List(map[string]any{"name": "Jason"}) require.NoError(t, err) if len(pps) != 1 { t.Errorf("Expected 1 person back, got %d", len(pps)) @@ -425,7 +425,7 @@ func TestSelectSliceMapTimeContext(t *testing.T) { t.Fatal(err) } for rows.Next() { - m := map[string]interface{}{} + m := map[string]any{} err := rows.MapScan(m) if err != nil { t.Error(err) @@ -1070,7 +1070,7 @@ func TestUsageContext(t *testing.T) { if err != nil { t.Fatal(err) } - m := map[string]interface{}{} + m := map[string]any{} for rows.Next() { err = rows.MapScan(m) if err != nil { @@ -1098,7 +1098,7 @@ func TestUsageContext(t *testing.T) { // test advanced querying // test that NamedExec works with a map as well as a struct - _, err = db.NamedExecContext(ctx, "INSERT INTO person (first_name, last_name, email) VALUES (:first, :last, :email)", map[string]interface{}{ + _, err = db.NamedExecContext(ctx, "INSERT INTO person (first_name, last_name, email) VALUES (:first, :last, :email)", map[string]any{ "first": "Bin", "last": "Smuth", "email": "bensmith@ex.co", @@ -1109,7 +1109,7 @@ func TestUsageContext(t *testing.T) { // ensure that if the named param happens right at the end it still works // ensure that NamedQuery works with a map[string]interface{} - rows, err = db.NamedQueryContext(ctx, "SELECT * FROM person WHERE first_name=:first", map[string]interface{}{"first": "Bin"}) + rows, err = db.NamedQueryContext(ctx, "SELECT * FROM person WHERE first_name=:first", map[string]any{"first": "Bin"}) if err != nil { t.Fatal(err) } @@ -1354,7 +1354,7 @@ func TestInContext(t *testing.T) { name string q string expected string - args []interface{} + args []any flatCount int wantErr bool err string @@ -1364,14 +1364,14 @@ func TestInContext(t *testing.T) { name: "additional arguments", q: "SELECT * FROM foo WHERE x = ? AND v in (?) AND y = ?", expected: "SELECT * FROM foo WHERE x = ? AND v in (?, ?, ?, ?, ?) AND y = ?", - args: []interface{}{"foo", []int{0, 5, 7, 2, 9}, "bar"}, + args: []any{"foo", []int{0, 5, 7, 2, 9}, "bar"}, flatCount: 7, }, { name: "a single list", q: "SELECT * FROM foo WHERE x in (?)", expected: "SELECT * FROM foo WHERE x in (?, ?, ?, ?, ?, ?, ?, ?)", - args: []interface{}{[]int{1, 2, 3, 4, 5, 6, 7, 8}}, + args: []any{[]int{1, 2, 3, 4, 5, 6, 7, 8}}, flatCount: 8, }, { @@ -1382,21 +1382,21 @@ FROM foo WHERE x in (?)`, expected: `SELECT * -- comment in question? FROM foo WHERE x in (?)`, - args: []interface{}{[]int{1}}, + args: []any{[]int{1}}, flatCount: 1, }, { name: "question mark in value", q: `SELECT *, 'something?' as something FROM foo WHERE x in (?)`, expected: `SELECT *, 'something?' as something FROM foo WHERE x in (?)`, - args: []interface{}{[]int{1}}, + args: []any{[]int{1}}, flatCount: 1, }, { name: "literal values", q: `SELECT *, 'something?' as something FROM foo WHERE x in ('123?', ?)`, expected: `SELECT *, 'something?' as something FROM foo WHERE x in ('123?', ?, ?)`, - args: []interface{}{[]int{1, 2}}, + args: []any{[]int{1, 2}}, flatCount: 2, }, { @@ -1406,28 +1406,28 @@ FROM foo WHERE x in (?)`, name: "too many bindVars but no slices", q: "SELECT * FROM foo WHERE x = ? AND y = ?", expected: `SELECT * FROM foo WHERE x = ? AND y = ?`, - args: []interface{}{"foo", "bar", "baz"}, + args: []any{"foo", "bar", "baz"}, flatCount: 3, }, { name: "too many bindvars", q: "SELECT * FROM foo WHERE x = ? and y = ?", // "SELECT * FROM foo WHERE x = ? and y = ?", - args: []interface{}{"foo", []int{1, 2, 3}, "bar"}, + args: []any{"foo", []int{1, 2, 3}, "bar"}, wantErr: true, err: "number of bindVars less than number arguments", }, { name: "empty slice, should return error before parse", q: "SELECT * FROM foo WHERE x = ?", - args: []interface{}{[]int{}}, + args: []any{[]int{}}, wantErr: true, err: "empty slice passed to 'in' query", }, { name: "too few bindvars, should return an error", q: "SELECT * FROM foo WHERE x = ? AND y in (?)", - args: []interface{}{[]int{1, 2, 3}}, + args: []any{[]int{1, 2, 3}}, wantErr: true, err: "number of bindVars exceeds arguments", }, diff --git a/sqlx_test.go b/sqlx_test.go index ad4c2c4..5133bb3 100644 --- a/sqlx_test.go +++ b/sqlx_test.go @@ -15,6 +15,7 @@ import ( "encoding/json" "fmt" "log" + "maps" "os" "reflect" "strings" @@ -384,7 +385,7 @@ func TestMissingNames(t *testing.T) { t.Error("expected NamedStmt to be unsafe but its underlying stmt did not inherit safety") } pps := []PersonPlus{} - err = nstmt.Select(&pps, map[string]interface{}{"name": "Jason"}) + err = nstmt.Select(&pps, map[string]any{"name": "Jason"}) require.NoError(t, err) if len(pps) != 1 { t.Errorf("Expected 1 person back, got %d", len(pps)) @@ -404,7 +405,7 @@ func TestMissingNames(t *testing.T) { t.Error("expected newly unsafed NamedStmt to be unsafe") } pps := []PersonPlus{} - err = nstmt.Select(&pps, map[string]interface{}{"name": "Jason"}) + err = nstmt.Select(&pps, map[string]any{"name": "Jason"}) require.NoError(t, err) if len(pps) != 1 { t.Errorf("Expected 1 person back, got %d", len(pps)) @@ -437,7 +438,7 @@ func TestMissingNames(t *testing.T) { if !getOptions(ps).allowMissingFields() { t.Error("NamedStmt did not inherit unsafe") } - pps, err := ps.List(map[string]interface{}{"name": "Jason"}) + pps, err := ps.List(map[string]any{"name": "Jason"}) require.NoError(t, err) if len(pps) != 1 { t.Errorf("Expected 1 person back, got %d", len(pps)) @@ -671,7 +672,7 @@ func TestSelectSliceMapTime(t *testing.T) { t.Fatal(err) } for rows.Next() { - m := map[string]interface{}{} + m := map[string]any{} err := rows.MapScan(m) if err != nil { t.Error(err) @@ -1187,7 +1188,7 @@ func TestUsage(t *testing.T) { if err != nil { t.Fatal(err) } - m := map[string]interface{}{} + m := map[string]any{} for rows.Next() { err = rows.MapScan(m) if err != nil { @@ -1215,7 +1216,7 @@ func TestUsage(t *testing.T) { // test advanced querying // test that NamedExec works with a map as well as a struct - _, err = db.NamedExec("INSERT INTO person (first_name, last_name, email) VALUES (:first, :last, :email)", map[string]interface{}{ + _, err = db.NamedExec("INSERT INTO person (first_name, last_name, email) VALUES (:first, :last, :email)", map[string]any{ "first": "Bin", "last": "Smuth", "email": "bensmith@ex.co", @@ -1226,7 +1227,7 @@ func TestUsage(t *testing.T) { // ensure that if the named param happens right at the end it still works // ensure that NamedQuery works with a map[string]interface{} - rows, err = db.NamedQuery("SELECT * FROM person WHERE first_name=:first", map[string]interface{}{"first": "Bin"}) + rows, err = db.NamedQuery("SELECT * FROM person WHERE first_name=:first", map[string]any{"first": "Bin"}) if err != nil { t.Fatal(err) } @@ -1475,7 +1476,7 @@ func TestRebind(t *testing.T) { func TestBindMap(t *testing.T) { // Test that it works.. q1 := `INSERT INTO foo (a, b, c, d) VALUES (:name, :age, :first, :last)` - am := map[string]interface{}{ + am := map[string]any{ "name": "Jason Moiron", "age": 30, "first": "Jason", @@ -1522,7 +1523,7 @@ func (p PropertyMap) Value() (driver.Value, error) { return json.Marshal(p) } -func (p PropertyMap) Scan(src interface{}) error { +func (p PropertyMap) Scan(src any) error { v := reflect.ValueOf(src) if !v.IsValid() || v.CanAddr() && v.IsNil() { return nil @@ -1591,28 +1592,28 @@ func TestIn(t *testing.T) { // some quite normal situations type tr struct { q string - args []interface{} + args []any c int } tests := []tr{ { "SELECT * FROM foo WHERE x = ? AND v in (?) AND y = ?", - []interface{}{"foo", []int{0, 5, 7, 2, 9}, "bar"}, + []any{"foo", []int{0, 5, 7, 2, 9}, "bar"}, 7, }, { "SELECT * FROM foo WHERE x in (?)", - []interface{}{[]int{1, 2, 3, 4, 5, 6, 7, 8}}, + []any{[]int{1, 2, 3, 4, 5, 6, 7, 8}}, 8, }, { "SELECT * FROM foo WHERE x = ? AND y in (?)", - []interface{}{[]byte("foo"), []int{0, 5, 3}}, + []any{[]byte("foo"), []int{0, 5, 3}}, 4, }, { "SELECT * FROM foo WHERE x = ? AND y IN (?)", - []interface{}{sql.NullString{Valid: false}, []string{"a", "b"}}, + []any{sql.NullString{Valid: false}, []string{"a", "b"}}, 3, }, } @@ -1634,7 +1635,7 @@ func TestIn(t *testing.T) { query := `SELECT * FROM foo WHERE x = ? or y IN (?)` _, _, err := In(query, (*Valuer)(nil), // a non-inited pointer to valuer - []interface{}{ + []any{ "a", // a usual value nil, // a nil value Valuer{Val: "foo"}, // a Valuer @@ -1668,19 +1669,19 @@ func TestIn(t *testing.T) { // too many bindvars; slice present so should return error during parse { "SELECT * FROM foo WHERE x = ? and y = ?", - []interface{}{"foo", []int{1, 2, 3}, "bar"}, + []any{"foo", []int{1, 2, 3}, "bar"}, 0, }, // empty slice, should return error before parse { "SELECT * FROM foo WHERE x = ?", - []interface{}{[]int{}}, + []any{[]int{}}, 0, }, // too *few* bindvars, should return an error { "SELECT * FROM foo WHERE x = ? AND y in (?)", - []interface{}{[]int{1, 2, 3}}, + []any{[]int{1, 2, 3}}, 0, }, } @@ -1978,7 +1979,7 @@ func BenchmarkBindStruct(b *testing.B) { } func TestBindNamedMapper(t *testing.T) { - type A map[string]interface{} + type A map[string]any m := reflectx.NewMapperFunc("db", NameMapper) query, args, err := bindNamedMapper(DOLLAR, `select :x`, A{ "x": "X!", @@ -2007,7 +2008,7 @@ func TestBindNamedMapper(t *testing.T) { func BenchmarkBindMap(b *testing.B) { b.StopTimer() q1 := `INSERT INTO foo (a, b, c, d) VALUES (:name, :age, :first, :last)` - am := map[string]interface{}{ + am := map[string]any{ "name": "Jason Moiron", "age": 30, "first": "Jason", @@ -2023,17 +2024,17 @@ func BenchmarkIn(b *testing.B) { q := `SELECT * FROM foo WHERE x = ? AND v in (?) AND y = ?` for i := 0; i < b.N; i++ { - _, _, _ = In(q, []interface{}{"foo", []int{0, 5, 7, 2, 9}, "bar"}...) + _, _, _ = In(q, []any{"foo", []int{0, 5, 7, 2, 9}, "bar"}...) } } func BenchmarkIn1k(b *testing.B) { q := `SELECT * FROM foo WHERE x = ? AND v in (?) AND y = ?` - var vals [1000]interface{} + var vals [1000]any for i := 0; i < b.N; i++ { - _, _, _ = In(q, []interface{}{"foo", vals[:], "bar"}...) + _, _, _ = In(q, []any{"foo", vals[:], "bar"}...) } } @@ -2043,7 +2044,7 @@ func BenchmarkIn1kInt(b *testing.B) { var vals [1000]int for i := 0; i < b.N; i++ { - _, _, _ = In(q, []interface{}{"foo", vals[:], "bar"}...) + _, _, _ = In(q, []any{"foo", vals[:], "bar"}...) } } @@ -2053,7 +2054,7 @@ func BenchmarkIn1kString(b *testing.B) { var vals [1000]string for i := 0; i < b.N; i++ { - _, _, _ = In(q, []interface{}{"foo", vals[:], "bar"}...) + _, _, _ = In(q, []any{"foo", vals[:], "bar"}...) } } @@ -2071,7 +2072,7 @@ func BenchmarkRebind(b *testing.B) { func TestIn130Regression(t *testing.T) { t.Run("[]interface{}{}", func(t *testing.T) { - q, args, err := In("SELECT * FROM people WHERE name IN (?)", []interface{}{[]string{"gopher"}}...) + q, args, err := In("SELECT * FROM people WHERE name IN (?)", []any{[]string{"gopher"}}...) if err != nil { t.Fatal(err) } @@ -2248,20 +2249,16 @@ func TestSelectReset(t *testing.T) { } func TestQueryable(t *testing.T) { - sqlDBType := reflect.TypeOf(&sql.DB{}) - dbType := reflect.TypeOf(&DB{}) - sqlTxType := reflect.TypeOf(&sql.Tx{}) - txType := reflect.TypeOf(&Tx{}) + sqlDBType := reflect.TypeFor[*sql.DB]() + dbType := reflect.TypeFor[*DB]() + sqlTxType := reflect.TypeFor[*sql.Tx]() + txType := reflect.TypeFor[*Tx]() dbMethods := exportableMethods(sqlDBType) - for k, v := range exportableMethods(dbType) { - dbMethods[k] = v - } + maps.Copy(dbMethods, exportableMethods(dbType)) txMethods := exportableMethods(sqlTxType) - for k, v := range exportableMethods(txType) { - txMethods[k] = v - } + maps.Copy(txMethods, exportableMethods(txType)) sharedMethods := make([]string, 0) @@ -2273,7 +2270,7 @@ func TestQueryable(t *testing.T) { } } - queryableType := reflect.TypeOf((*Queryable)(nil)).Elem() + queryableType := reflect.TypeFor[Queryable]() queryableMethods := exportableMethods(queryableType) for _, sharedMethodName := range sharedMethods { diff --git a/transact_test.go b/transact_test.go index 001e695..c263af2 100644 --- a/transact_test.go +++ b/transact_test.go @@ -142,7 +142,7 @@ func TestTransact(t *testing.T) { txFunc: func(ctx context.Context, db Queryable) error { // to use in the transaction it must be prepared in the transaction txstmt := nstmtx.Prepare(db) - _, err := txstmt.ExecContext(ctx, map[string]interface{}{"name": "aaron"}) + _, err := txstmt.ExecContext(ctx, map[string]any{"name": "aaron"}) // txstmt.Close() is not needed, it will be closed when the transaction is committed or rolled back require.NoError(t, err) return nil diff --git a/types/types.go b/types/types.go index ea37482..4a03417 100644 --- a/types/types.go +++ b/types/types.go @@ -27,7 +27,7 @@ func (g GzippedText) Value() (driver.Value, error) { // Scan implements the sql.Scanner interface, ungzipping the value coming off // the wire and storing the raw result in the GzippedText. -func (g *GzippedText) Scan(src interface{}) error { +func (g *GzippedText) Scan(src any) error { var source []byte switch src := src.(type) { case string: @@ -88,7 +88,7 @@ func (j JSONText) Value() (driver.Value, error) { } // Scan stores the src in *j. No validation is done. -func (j *JSONText) Scan(src interface{}) error { +func (j *JSONText) Scan(src any) error { var source []byte switch t := src.(type) { case string: @@ -110,7 +110,7 @@ func (j *JSONText) Scan(src interface{}) error { } // Unmarshal unmarshal's the json in j to v, as in json.Unmarshal. -func (j *JSONText) Unmarshal(v interface{}) error { +func (j *JSONText) Unmarshal(v any) error { if len(*j) == 0 { *j = emptyJSON } @@ -131,7 +131,7 @@ type NullJSONText struct { } // Scan implements the Scanner interface. -func (n *NullJSONText) Scan(value interface{}) error { +func (n *NullJSONText) Scan(value any) error { if value == nil { n.JSONText, n.Valid = emptyJSON, false return nil @@ -163,7 +163,7 @@ func (b BitBool) Value() (driver.Value, error) { // Scan implements the sql.Scanner interface, // and turns the bitfield incoming from MySQL into a BitBool -func (b *BitBool) Scan(src interface{}) error { +func (b *BitBool) Scan(src any) error { v, ok := src.([]byte) if !ok { return errors.New("bad []byte type assertion") diff --git a/types/types_test.go b/types/types_test.go index 721d35e..83a7455 100644 --- a/types/types_test.go +++ b/types/types_test.go @@ -27,7 +27,7 @@ func TestJSONText(t *testing.T) { if err != nil { t.Errorf("Was not expecting an error") } - m := map[string]interface{}{} + m := map[string]any{} j.Unmarshal(&m) if m["foo"].(float64) != 1 || m["bar"].(float64) != 2 { @@ -77,7 +77,7 @@ func TestNullJSONText(t *testing.T) { if err != nil { t.Errorf("Was not expecting an error") } - m := map[string]interface{}{} + m := map[string]any{} j.Unmarshal(&m) if m["foo"].(float64) != 1 || m["bar"].(float64) != 2 {