chore: update deps and vendoring
This commit is contained in:
parent
8af2fb6cec
commit
b51f7992cd
2
go.mod
2
go.mod
|
@ -12,7 +12,7 @@ require (
|
|||
github.com/go-acme/lego/v3 v3.7.0
|
||||
github.com/go-chi/chi v4.1.1+incompatible
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/jmoiron/sqlx v1.2.1-0.20190826204134-d7d95172beb5
|
||||
github.com/jmoiron/sqlx v1.3.4
|
||||
github.com/joho/godotenv v1.3.0
|
||||
github.com/judwhite/go-svc v1.1.2
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
|
|
11
go.sum
11
go.sum
|
@ -99,7 +99,6 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2
|
|||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
|
@ -174,8 +173,8 @@ github.com/jcmturner/rpc/v2 v2.0.2 h1:gMB4IwRXYsWw4Bc6o/az2HJgFUA1ffSh90i26ZJ6Xl
|
|||
github.com/jcmturner/rpc/v2 v2.0.2/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
|
||||
github.com/jmoiron/sqlx v1.2.1-0.20190826204134-d7d95172beb5 h1:lrdPtrORjGv1HbbEvKWDUAy97mPpFm4B8hp77tcCUJY=
|
||||
github.com/jmoiron/sqlx v1.2.1-0.20190826204134-d7d95172beb5/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||
github.com/jmoiron/sqlx v1.3.4 h1:wv+0IJZfL5z0uZoUjlpKgHkgaFSYD+r9CfrXjEXsO7w=
|
||||
github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
|
@ -201,7 +200,7 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
|||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA=
|
||||
github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.6.0 h1:I5DPxhYJChW9KYc66se+oKFFQX6VuQrKiprsX6ivRZc=
|
||||
github.com/lib/pq v1.6.0/go.mod h1:4vXEAYvW1fRQ2/FhZ78H73A60MHw1geSm145z2mdY1g=
|
||||
github.com/libdns/libdns v0.1.0 h1:0ctCOrVJsVzj53mop1angHp/pE3hmAhP7KiHvR0HD04=
|
||||
|
@ -211,8 +210,8 @@ github.com/liquidweb/liquidweb-go v1.6.0/go.mod h1:UDcVnAMDkZxpw4Y7NOHkqoeiGacVL
|
|||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mholt/acmez v0.1.1 h1:KQODCqk+hBn3O7qfCRPj6L96uG65T5BSS95FKNEqtdA=
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# Folders
|
||||
_obj
|
||||
_test
|
||||
.idea
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
|
|
|
@ -18,9 +18,8 @@ before_install:
|
|||
|
||||
# go versions to test
|
||||
go:
|
||||
- "1.10.x"
|
||||
- "1.11.x"
|
||||
- "1.12.x"
|
||||
- "1.15.x"
|
||||
- "1.16.x"
|
||||
|
||||
# run tests w/ coverage
|
||||
script:
|
||||
|
|
|
@ -20,25 +20,29 @@ explains how to use `database/sql` along with sqlx.
|
|||
|
||||
## Recent Changes
|
||||
|
||||
* The [introduction](https://github.com/jmoiron/sqlx/pull/387) of `sql.ColumnType` sets the required minimum Go version to 1.8.
|
||||
1.3.0:
|
||||
|
||||
* sqlx/types.JsonText has been renamed to JSONText to follow Go naming conventions.
|
||||
* `sqlx.DB.Connx(context.Context) *sqlx.Conn`
|
||||
* `sqlx.BindDriver(driverName, bindType)`
|
||||
* support for `[]map[string]interface{}` to do "batch" insertions
|
||||
* allocation & perf improvements for `sqlx.In`
|
||||
|
||||
This breaks backwards compatibility, but it's in a way that is trivially fixable
|
||||
(`s/JsonText/JSONText/g`). The `types` package is both experimental and not in
|
||||
active development currently.
|
||||
DB.Connx returns an `sqlx.Conn`, which is an `sql.Conn`-alike consistent with
|
||||
sqlx's wrapping of other types.
|
||||
|
||||
* Using Go 1.6 and below with `types.JSONText` and `types.GzippedText` can be _potentially unsafe_, **especially** when used with common auto-scan sqlx idioms like `Select` and `Get`. See [golang bug #13905](https://github.com/golang/go/issues/13905).
|
||||
`BindDriver` allows users to control the bindvars that sqlx will use for drivers,
|
||||
and add new drivers at runtime. This results in a very slight performance hit
|
||||
when resolving the driver into a bind type (~40ns per call), but it allows users
|
||||
to specify what bindtype their driver uses even when sqlx has not been updated
|
||||
to know about it by default.
|
||||
|
||||
### Backwards Compatibility
|
||||
|
||||
There is no Go1-like promise of absolute stability, but I take the issue seriously
|
||||
and will maintain the library in a compatible state unless vital bugs prevent me
|
||||
from doing so. Since [#59](https://github.com/jmoiron/sqlx/issues/59) and
|
||||
[#60](https://github.com/jmoiron/sqlx/issues/60) necessitated breaking behavior,
|
||||
a wider API cleanup was done at the time of fixing. It's possible this will happen
|
||||
in future; if it does, a git tag will be provided for users requiring the old
|
||||
behavior to continue to use it until such a time as they can migrate.
|
||||
Compatibility with the most recent two versions of Go is a requirement for any
|
||||
new changes. Compatibility beyond that is not guaranteed.
|
||||
|
||||
Versioning is done with Go modules. Breaking changes (eg. removing deprecated API)
|
||||
will get major version number bumps.
|
||||
|
||||
## install
|
||||
|
||||
|
@ -102,7 +106,7 @@ type Place struct {
|
|||
}
|
||||
|
||||
func main() {
|
||||
// this Pings the database trying to connect, panics on error
|
||||
// this Pings the database trying to connect
|
||||
// use sqlx.Open() for sql.Open() semantics
|
||||
db, err := sqlx.Connect("postgres", "user=foo dbname=bar sslmode=disable")
|
||||
if err != nil {
|
||||
|
@ -182,6 +186,28 @@ func main() {
|
|||
// as the name -> db mapping, so struct fields are lowercased and the `db` tag
|
||||
// is taken into consideration.
|
||||
rows, err = db.NamedQuery(`SELECT * FROM person WHERE first_name=:first_name`, jason)
|
||||
|
||||
|
||||
// batch insert
|
||||
|
||||
// batch insert with structs
|
||||
personStructs := []Person{
|
||||
{FirstName: "Ardie", LastName: "Savea", Email: "asavea@ab.co.nz"},
|
||||
{FirstName: "Sonny Bill", LastName: "Williams", Email: "sbw@ab.co.nz"},
|
||||
{FirstName: "Ngani", LastName: "Laumape", Email: "nlaumape@ab.co.nz"},
|
||||
}
|
||||
|
||||
_, err = db.NamedExec(`INSERT INTO person (first_name, last_name, email)
|
||||
VALUES (:first_name, :last_name, :email)`, personStructs)
|
||||
|
||||
// batch insert with maps
|
||||
personMaps := []map[string]interface{}{
|
||||
{"first_name": "Ardie", "last_name": "Savea", "email": "asavea@ab.co.nz"},
|
||||
{"first_name": "Sonny Bill", "last_name": "Williams", "email": "sbw@ab.co.nz"},
|
||||
{"first_name": "Ngani", "last_name": "Laumape", "email": "nlaumape@ab.co.nz"},
|
||||
}
|
||||
|
||||
_, err = db.NamedExec(`INSERT INTO person (first_name, last_name, email)
|
||||
VALUES (:first_name, :last_name, :email)`, personMaps)
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/jmoiron/sqlx/reflectx"
|
||||
)
|
||||
|
@ -20,21 +21,36 @@ const (
|
|||
AT
|
||||
)
|
||||
|
||||
var defaultBinds = map[int][]string{
|
||||
DOLLAR: []string{"postgres", "pgx", "pq-timeouts", "cloudsqlpostgres", "ql", "nrpostgres", "cockroach"},
|
||||
QUESTION: []string{"mysql", "sqlite3", "nrmysql", "nrsqlite3"},
|
||||
NAMED: []string{"oci8", "ora", "goracle", "godror"},
|
||||
AT: []string{"sqlserver"},
|
||||
}
|
||||
|
||||
var binds sync.Map
|
||||
|
||||
func init() {
|
||||
for bind, drivers := range defaultBinds {
|
||||
for _, driver := range drivers {
|
||||
BindDriver(driver, bind)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// BindType returns the bindtype for a given database given a drivername.
|
||||
func BindType(driverName string) int {
|
||||
switch driverName {
|
||||
case "postgres", "pgx", "pq-timeouts", "cloudsqlpostgres", "ql":
|
||||
return DOLLAR
|
||||
case "mysql":
|
||||
return QUESTION
|
||||
case "sqlite3":
|
||||
return QUESTION
|
||||
case "oci8", "ora", "goracle":
|
||||
return NAMED
|
||||
case "sqlserver":
|
||||
return AT
|
||||
itype, ok := binds.Load(driverName)
|
||||
if !ok {
|
||||
return UNKNOWN
|
||||
}
|
||||
return UNKNOWN
|
||||
return itype.(int)
|
||||
}
|
||||
|
||||
// BindDriver sets the BindType for driverName to bindType.
|
||||
func BindDriver(driverName string, bindType int) {
|
||||
binds.Store(driverName, bindType)
|
||||
}
|
||||
|
||||
// FIXME: this should be able to be tolerant of escaped ?'s in queries without
|
||||
|
@ -98,6 +114,28 @@ func rebindBuff(bindType int, query string) string {
|
|||
return rqb.String()
|
||||
}
|
||||
|
||||
func asSliceForIn(i interface{}) (v reflect.Value, ok bool) {
|
||||
if i == nil {
|
||||
return reflect.Value{}, false
|
||||
}
|
||||
|
||||
v = reflect.ValueOf(i)
|
||||
t := reflectx.Deref(v.Type())
|
||||
|
||||
// Only expand slices
|
||||
if t.Kind() != reflect.Slice {
|
||||
return reflect.Value{}, false
|
||||
}
|
||||
|
||||
// []byte is a driver.Value type so it should not be expanded
|
||||
if t == reflect.TypeOf([]byte{}) {
|
||||
return reflect.Value{}, false
|
||||
|
||||
}
|
||||
|
||||
return v, true
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
@ -113,7 +151,14 @@ func In(query string, args ...interface{}) (string, []interface{}, error) {
|
|||
var flatArgsCount int
|
||||
var anySlices bool
|
||||
|
||||
meta := make([]argMeta, len(args))
|
||||
var stackMeta [32]argMeta
|
||||
|
||||
var meta []argMeta
|
||||
if len(args) <= len(stackMeta) {
|
||||
meta = stackMeta[:len(args)]
|
||||
} else {
|
||||
meta = make([]argMeta, len(args))
|
||||
}
|
||||
|
||||
for i, arg := range args {
|
||||
if a, ok := arg.(driver.Valuer); ok {
|
||||
|
@ -123,11 +168,8 @@ func In(query string, args ...interface{}) (string, []interface{}, error) {
|
|||
return "", nil, err
|
||||
}
|
||||
}
|
||||
v := reflect.ValueOf(arg)
|
||||
t := reflectx.Deref(v.Type())
|
||||
|
||||
// []byte is a driver.Value type so it should not be expanded
|
||||
if t.Kind() == reflect.Slice && t != reflect.TypeOf([]byte{}) {
|
||||
if v, ok := asSliceForIn(arg); ok {
|
||||
meta[i].length = v.Len()
|
||||
meta[i].v = v
|
||||
|
||||
|
@ -150,7 +192,9 @@ func In(query string, args ...interface{}) (string, []interface{}, error) {
|
|||
}
|
||||
|
||||
newArgs := make([]interface{}, 0, flatArgsCount)
|
||||
buf := make([]byte, 0, len(query)+len(", ?")*flatArgsCount)
|
||||
|
||||
var buf strings.Builder
|
||||
buf.Grow(len(query) + len(", ?")*flatArgsCount)
|
||||
|
||||
var arg, offset int
|
||||
|
||||
|
@ -176,10 +220,10 @@ func In(query string, args ...interface{}) (string, []interface{}, error) {
|
|||
}
|
||||
|
||||
// write everything up to and including our ? character
|
||||
buf = append(buf, query[:offset+i+1]...)
|
||||
buf.WriteString(query[:offset+i+1])
|
||||
|
||||
for si := 1; si < argMeta.length; si++ {
|
||||
buf = append(buf, ", ?"...)
|
||||
buf.WriteString(", ?")
|
||||
}
|
||||
|
||||
newArgs = appendReflectSlice(newArgs, argMeta.v, argMeta.length)
|
||||
|
@ -190,13 +234,13 @@ func In(query string, args ...interface{}) (string, []interface{}, error) {
|
|||
offset = 0
|
||||
}
|
||||
|
||||
buf = append(buf, query...)
|
||||
buf.WriteString(query)
|
||||
|
||||
if arg < len(meta) {
|
||||
return "", nil, errors.New("number of bindVars less than number arguments")
|
||||
}
|
||||
|
||||
return string(buf), newArgs, nil
|
||||
return buf.String(), newArgs, nil
|
||||
}
|
||||
|
||||
func appendReflectSlice(args []interface{}, v reflect.Value, vlen int) []interface{} {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
module github.com/jmoiron/sqlx
|
||||
|
||||
go 1.10
|
||||
|
||||
require (
|
||||
github.com/go-sql-driver/mysql v1.4.0
|
||||
github.com/lib/pq v1.0.0
|
||||
github.com/mattn/go-sqlite3 v1.9.0
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/lib/pq v1.2.0
|
||||
github.com/mattn/go-sqlite3 v1.14.6
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
|
|
|
@ -146,8 +146,22 @@ func prepareNamed(p namedPreparer, query string) (*NamedStmt, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// convertMapStringInterface attempts to convert v to map[string]interface{}.
|
||||
// Unlike v.(map[string]interface{}), this function works on named types that
|
||||
// are convertible to map[string]interface{} as well.
|
||||
func convertMapStringInterface(v interface{}) (map[string]interface{}, bool) {
|
||||
var m map[string]interface{}
|
||||
mtype := reflect.TypeOf(m)
|
||||
t := reflect.TypeOf(v)
|
||||
if !t.ConvertibleTo(mtype) {
|
||||
return nil, false
|
||||
}
|
||||
return reflect.ValueOf(v).Convert(mtype).Interface().(map[string]interface{}), true
|
||||
|
||||
}
|
||||
|
||||
func bindAnyArgs(names []string, arg interface{}, m *reflectx.Mapper) ([]interface{}, error) {
|
||||
if maparg, ok := arg.(map[string]interface{}); ok {
|
||||
if maparg, ok := convertMapStringInterface(arg); ok {
|
||||
return bindMapArgs(names, maparg)
|
||||
}
|
||||
return bindArgs(names, arg, m)
|
||||
|
@ -202,7 +216,7 @@ func bindStruct(bindType int, query string, arg interface{}, m *reflectx.Mapper)
|
|||
return "", []interface{}{}, err
|
||||
}
|
||||
|
||||
arglist, err := bindArgs(names, arg, m)
|
||||
arglist, err := bindAnyArgs(names, arg, m)
|
||||
if err != nil {
|
||||
return "", []interface{}{}, err
|
||||
}
|
||||
|
@ -210,21 +224,47 @@ func bindStruct(bindType int, query string, arg interface{}, m *reflectx.Mapper)
|
|||
return bound, arglist, nil
|
||||
}
|
||||
|
||||
var valueBracketReg = regexp.MustCompile(`\([^(]*\?+[^)]*\)`)
|
||||
var valuesReg = regexp.MustCompile(`\)\s*(?i)VALUES\s*\(`)
|
||||
|
||||
func findMatchingClosingBracketIndex(s string) int {
|
||||
count := 0
|
||||
for i, ch := range s {
|
||||
if ch == '(' {
|
||||
count++
|
||||
}
|
||||
if ch == ')' {
|
||||
count--
|
||||
if count == 0 {
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func fixBound(bound string, loop int) string {
|
||||
loc := valueBracketReg.FindStringIndex(bound)
|
||||
if len(loc) != 2 {
|
||||
loc := valuesReg.FindStringIndex(bound)
|
||||
// defensive guard when "VALUES (...)" not found
|
||||
if len(loc) < 2 {
|
||||
return bound
|
||||
}
|
||||
|
||||
openingBracketIndex := loc[1] - 1
|
||||
index := findMatchingClosingBracketIndex(bound[openingBracketIndex:])
|
||||
// defensive guard. must have closing bracket
|
||||
if index == 0 {
|
||||
return bound
|
||||
}
|
||||
closingBracketIndex := openingBracketIndex + index + 1
|
||||
|
||||
var buffer bytes.Buffer
|
||||
|
||||
buffer.WriteString(bound[0:loc[1]])
|
||||
buffer.WriteString(bound[0:closingBracketIndex])
|
||||
for i := 0; i < loop-1; i++ {
|
||||
buffer.WriteString(",")
|
||||
buffer.WriteString(bound[loc[0]:loc[1]])
|
||||
buffer.WriteString(bound[openingBracketIndex:closingBracketIndex])
|
||||
}
|
||||
buffer.WriteString(bound[loc[1]:])
|
||||
buffer.WriteString(bound[closingBracketIndex:])
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
|
@ -242,9 +282,9 @@ func bindArray(bindType int, query string, arg interface{}, m *reflectx.Mapper)
|
|||
if arrayLen == 0 {
|
||||
return "", []interface{}{}, fmt.Errorf("length of array is 0: %#v", arg)
|
||||
}
|
||||
var arglist []interface{}
|
||||
var arglist = make([]interface{}, 0, len(names)*arrayLen)
|
||||
for i := 0; i < arrayLen; i++ {
|
||||
elemArglist, err := bindArgs(names, arrayValue.Index(i).Interface(), m)
|
||||
elemArglist, err := bindAnyArgs(names, arrayValue.Index(i).Interface(), m)
|
||||
if err != nil {
|
||||
return "", []interface{}{}, err
|
||||
}
|
||||
|
@ -379,11 +419,16 @@ func Named(query string, arg interface{}) (string, []interface{}, error) {
|
|||
}
|
||||
|
||||
func bindNamedMapper(bindType int, query string, arg interface{}, m *reflectx.Mapper) (string, []interface{}, error) {
|
||||
if maparg, ok := arg.(map[string]interface{}); ok {
|
||||
return bindMap(bindType, query, maparg)
|
||||
}
|
||||
switch reflect.TypeOf(arg).Kind() {
|
||||
case reflect.Array, reflect.Slice:
|
||||
t := reflect.TypeOf(arg)
|
||||
k := t.Kind()
|
||||
switch {
|
||||
case k == reflect.Map && t.Key().Kind() == reflect.String:
|
||||
m, ok := convertMapStringInterface(arg)
|
||||
if !ok {
|
||||
return "", nil, fmt.Errorf("sqlx.bindNamedMapper: unsupported map type: %T", arg)
|
||||
}
|
||||
return bindMap(bindType, query, m)
|
||||
case k == reflect.Array || k == reflect.Slice:
|
||||
return bindArray(bindType, query, arg, m)
|
||||
default:
|
||||
return bindStruct(bindType, query, arg, m)
|
||||
|
|
|
@ -429,9 +429,14 @@ QueueLoop:
|
|||
|
||||
flds := &StructMap{Index: m, Tree: root, Paths: map[string]*FieldInfo{}, Names: map[string]*FieldInfo{}}
|
||||
for _, fi := range flds.Index {
|
||||
flds.Paths[fi.Path] = fi
|
||||
if fi.Name != "" && !fi.Embedded {
|
||||
flds.Names[fi.Path] = fi
|
||||
// check if nothing has already been pushed with the same path
|
||||
// sometimes you can choose to override a type using embedded struct
|
||||
fld, ok := flds.Paths[fi.Path]
|
||||
if !ok || fld.Embedded {
|
||||
flds.Paths[fi.Path] = fi
|
||||
if fi.Name != "" && !fi.Embedded {
|
||||
flds.Names[fi.Path] = fi
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -64,11 +64,7 @@ func isScannable(t reflect.Type) bool {
|
|||
|
||||
// it's not important that we use the right mapper for this particular object,
|
||||
// we're only concerned on how many exported fields this struct has
|
||||
m := mapper()
|
||||
if len(m.TypeMap(t).Index) == 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return len(mapper().TypeMap(t).Index) == 0
|
||||
}
|
||||
|
||||
// ColScanner is an interface used by MapScan and SliceScan
|
||||
|
@ -380,6 +376,14 @@ func (db *DB) PrepareNamed(query string) (*NamedStmt, error) {
|
|||
return prepareNamed(db, query)
|
||||
}
|
||||
|
||||
// Conn is a wrapper around sql.Conn with extra functionality
|
||||
type Conn struct {
|
||||
*sql.Conn
|
||||
driverName string
|
||||
unsafe bool
|
||||
Mapper *reflectx.Mapper
|
||||
}
|
||||
|
||||
// Tx is an sqlx wrapper around sql.Tx with extra functionality
|
||||
type Tx struct {
|
||||
*sql.Tx
|
||||
|
|
|
@ -208,6 +208,74 @@ func (db *DB) BeginTxx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
|
|||
return &Tx{Tx: tx, driverName: db.driverName, unsafe: db.unsafe, Mapper: db.Mapper}, err
|
||||
}
|
||||
|
||||
// Connx returns an *sqlx.Conn instead of an *sql.Conn.
|
||||
func (db *DB) Connx(ctx context.Context) (*Conn, error) {
|
||||
conn, err := db.DB.Conn(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Conn{Conn: conn, driverName: db.driverName, unsafe: db.unsafe, Mapper: db.Mapper}, nil
|
||||
}
|
||||
|
||||
// BeginTxx begins a transaction and returns an *sqlx.Tx instead of an
|
||||
// *sql.Tx.
|
||||
//
|
||||
// The provided context is used until the transaction is committed or rolled
|
||||
// back. If the context is canceled, the sql package will roll back the
|
||||
// transaction. Tx.Commit will return an error if the context provided to
|
||||
// BeginxContext is canceled.
|
||||
func (c *Conn) BeginTxx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
|
||||
tx, err := c.Conn.BeginTx(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Tx{Tx: tx, driverName: c.driverName, unsafe: c.unsafe, Mapper: c.Mapper}, err
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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 {
|
||||
return GetContext(ctx, c, dest, query, args...)
|
||||
}
|
||||
|
||||
// PreparexContext returns an sqlx.Stmt instead of a sql.Stmt.
|
||||
//
|
||||
// The provided context is used for the preparation of the statement, not for
|
||||
// the execution of the statement.
|
||||
func (c *Conn) PreparexContext(ctx context.Context, query string) (*Stmt, error) {
|
||||
return PreparexContext(ctx, c, query)
|
||||
}
|
||||
|
||||
// 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) {
|
||||
r, err := c.Conn.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Rows{Rows: r, unsafe: c.unsafe, Mapper: c.Mapper}, err
|
||||
}
|
||||
|
||||
// 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 {
|
||||
rows, err := c.Conn.QueryContext(ctx, query, args...)
|
||||
return &Row{rows: rows, err: err, unsafe: c.unsafe, Mapper: c.Mapper}
|
||||
}
|
||||
|
||||
// Rebind a query within a Conn's bindvar type.
|
||||
func (c *Conn) Rebind(query string) string {
|
||||
return Rebind(BindType(c.driverName), query)
|
||||
}
|
||||
|
||||
// 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{}) *Stmt {
|
||||
|
|
|
@ -89,7 +89,7 @@ github.com/jcmturner/gokrb5/v8/types
|
|||
# github.com/jcmturner/rpc/v2 v2.0.2
|
||||
github.com/jcmturner/rpc/v2/mstypes
|
||||
github.com/jcmturner/rpc/v2/ndr
|
||||
# github.com/jmoiron/sqlx v1.2.1-0.20190826204134-d7d95172beb5
|
||||
# github.com/jmoiron/sqlx v1.3.4
|
||||
## explicit
|
||||
github.com/jmoiron/sqlx
|
||||
github.com/jmoiron/sqlx/reflectx
|
||||
|
|
Loading…
Reference in New Issue