diff --git a/bun.go b/bun.go index 2a788c4c1..923be3116 100644 --- a/bun.go +++ b/bun.go @@ -2,8 +2,6 @@ package bun import ( "context" - "fmt" - "reflect" "github.com/uptrace/bun/internal" "github.com/uptrace/bun/schema" @@ -81,53 +79,6 @@ func SetLogger(logger internal.Logging) { internal.Logger = logger } -//------------------------------------------------------------------------------ - -type InValues struct { - slice reflect.Value - err error -} - -var _ schema.QueryAppender = InValues{} - -func In(slice interface{}) InValues { - v := reflect.ValueOf(slice) - if v.Kind() != reflect.Slice { - return InValues{ - err: fmt.Errorf("bun: In(non-slice %T)", slice), - } - } - return InValues{ - slice: v, - } -} - -func (in InValues) AppendQuery(fmter schema.Formatter, b []byte) (_ []byte, err error) { - if in.err != nil { - return nil, in.err - } - return appendIn(fmter, b, in.slice), nil -} - -func appendIn(fmter schema.Formatter, b []byte, slice reflect.Value) []byte { - sliceLen := slice.Len() - for i := 0; i < sliceLen; i++ { - if i > 0 { - b = append(b, ", "...) - } - - elem := slice.Index(i) - if elem.Kind() == reflect.Interface { - elem = elem.Elem() - } - - if elem.Kind() == reflect.Slice { - b = append(b, '(') - b = appendIn(fmter, b, elem) - b = append(b, ')') - } else { - b = fmter.AppendValue(b, elem) - } - } - return b +func In(slice interface{}) schema.QueryAppender { + return schema.In(slice) } diff --git a/example/opentelemetry/README.md b/example/opentelemetry/README.md index cc219368b..cbec3a40c 100644 --- a/example/opentelemetry/README.md +++ b/example/opentelemetry/README.md @@ -16,7 +16,7 @@ go run . OTEL_EXPORTER_JAEGER_ENDPOINT=http://localhost:14268/api/traces go run . ``` -**Uptrace** exporter: +[Uptrace](https://github.com/uptrace/uptrace) exporter: ```shell UPTRACE_DSN="https://@uptrace.dev/" go run . @@ -25,4 +25,4 @@ UPTRACE_DSN="https://@uptrace.dev/" go run . ## Links - [Find instrumentations](https://opentelemetry.uptrace.dev/instrumentations/?lang=go) -- [OpenTelemetry Tracing API](https://opentelemetry.uptrace.dev/guide/go-tracing.html) +- [OpenTelemetry Go Tracing API](https://opentelemetry.uptrace.dev/guide/go-tracing.html) diff --git a/example/opentelemetry/main.go b/example/opentelemetry/main.go index be62e0afb..1ef117664 100644 --- a/example/opentelemetry/main.go +++ b/example/opentelemetry/main.go @@ -14,7 +14,7 @@ import ( "go.opentelemetry.io/otel/codes" ) -var tracer = otel.Tracer("bunexample") +var tracer = otel.Tracer("github.com/uptrace/bun/example/opentelemetry") func main() { ctx := context.Background() @@ -32,7 +32,7 @@ func main() { db.AddQueryHook(bunotel.NewQueryHook()) // db.AddQueryHook(bundebug.NewQueryHook(bundebug.WithVerbose(true))) - if _, err := db.NewCreateTable().Model((*TestModel)(nil)).Exec(ctx); err != nil { + if err := db.ResetModel(ctx, (*TestModel)(nil)); err != nil { panic(err) } diff --git a/internal/dbtest/query_test.go b/internal/dbtest/query_test.go index 7a905af0d..4ae03857b 100644 --- a/internal/dbtest/query_test.go +++ b/internal/dbtest/query_test.go @@ -695,6 +695,13 @@ func TestQuery(t *testing.T) { tm := time.Unix(0, 0) return db.NewInsert().Model(&Model{Time: &tm}) }, + func(db *bun.DB) schema.QueryAppender { + values := [][]byte{ + []byte("foo"), + []byte("bar"), + } + return db.NewSelect().Where("x IN (?)", bun.In(values)) + }, } timeRE := regexp.MustCompile(`'2\d{3}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(\.\d+)?(\+\d{2}:\d{2})?'`) diff --git a/internal/dbtest/testdata/snapshots/TestQuery-mariadb-111 b/internal/dbtest/testdata/snapshots/TestQuery-mariadb-111 new file mode 100644 index 000000000..fde921cc2 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-mariadb-111 @@ -0,0 +1 @@ +SELECT * WHERE (x IN (X'666f6f', X'626172')) diff --git a/internal/dbtest/testdata/snapshots/TestQuery-mssql2019-111 b/internal/dbtest/testdata/snapshots/TestQuery-mssql2019-111 new file mode 100644 index 000000000..18e1b90ca --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-mssql2019-111 @@ -0,0 +1 @@ +SELECT * WHERE (x IN (0x666f6f, 0x626172)) diff --git a/internal/dbtest/testdata/snapshots/TestQuery-mysql5-111 b/internal/dbtest/testdata/snapshots/TestQuery-mysql5-111 new file mode 100644 index 000000000..fde921cc2 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-mysql5-111 @@ -0,0 +1 @@ +SELECT * WHERE (x IN (X'666f6f', X'626172')) diff --git a/internal/dbtest/testdata/snapshots/TestQuery-mysql8-111 b/internal/dbtest/testdata/snapshots/TestQuery-mysql8-111 new file mode 100644 index 000000000..fde921cc2 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-mysql8-111 @@ -0,0 +1 @@ +SELECT * WHERE (x IN (X'666f6f', X'626172')) diff --git a/internal/dbtest/testdata/snapshots/TestQuery-pg-111 b/internal/dbtest/testdata/snapshots/TestQuery-pg-111 new file mode 100644 index 000000000..539050a16 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-pg-111 @@ -0,0 +1 @@ +SELECT * WHERE (x IN ('\x666f6f', '\x626172')) diff --git a/internal/dbtest/testdata/snapshots/TestQuery-pgx-111 b/internal/dbtest/testdata/snapshots/TestQuery-pgx-111 new file mode 100644 index 000000000..539050a16 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-pgx-111 @@ -0,0 +1 @@ +SELECT * WHERE (x IN ('\x666f6f', '\x626172')) diff --git a/internal/dbtest/testdata/snapshots/TestQuery-sqlite-111 b/internal/dbtest/testdata/snapshots/TestQuery-sqlite-111 new file mode 100644 index 000000000..fde921cc2 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-sqlite-111 @@ -0,0 +1 @@ +SELECT * WHERE (x IN (X'666f6f', X'626172')) diff --git a/schema/append.go b/schema/append.go index d19f40d50..04538c036 100644 --- a/schema/append.go +++ b/schema/append.go @@ -1,6 +1,7 @@ package schema import ( + "fmt" "reflect" "strconv" "time" @@ -47,3 +48,54 @@ func Append(fmter Formatter, b []byte, v interface{}) []byte { return appender(fmter, b, vv) } } + +//------------------------------------------------------------------------------ + +func In(slice interface{}) QueryAppender { + v := reflect.ValueOf(slice) + if v.Kind() != reflect.Slice { + return &inValues{ + err: fmt.Errorf("bun: In(non-slice %T)", slice), + } + } + return &inValues{ + slice: v, + } +} + +type inValues struct { + slice reflect.Value + err error +} + +var _ QueryAppender = (*inValues)(nil) + +func (in *inValues) AppendQuery(fmter Formatter, b []byte) (_ []byte, err error) { + if in.err != nil { + return nil, in.err + } + return appendIn(fmter, b, in.slice), nil +} + +func appendIn(fmter Formatter, b []byte, slice reflect.Value) []byte { + sliceLen := slice.Len() + for i := 0; i < sliceLen; i++ { + if i > 0 { + b = append(b, ", "...) + } + + elem := slice.Index(i) + if elem.Kind() == reflect.Interface { + elem = elem.Elem() + } + + if elem.Kind() == reflect.Slice && elem.Type() != bytesType { + b = append(b, '(') + b = appendIn(fmter, b, elem) + b = append(b, ')') + } else { + b = fmter.AppendValue(b, elem) + } + } + return b +}