[chore] bump db dependencies (#1366)

This commit is contained in:
tobi 2023-01-22 12:26:47 +01:00 committed by GitHub
commit 0ceacd7b1d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
78 changed files with 141878 additions and 126068 deletions

View file

@ -1,3 +1,29 @@
## [1.1.10](https://github.com/uptrace/bun/compare/v1.1.9...v1.1.10) (2023-01-16)
### Bug Fixes
* allow QueryEvent to better detect operations in raw queries ([8e44735](https://github.com/uptrace/bun/commit/8e4473538364bae6562055d35e94c3e9c0b77691))
* append default VARCHAR length instead of hardcoding it in the type definition ([e5079c7](https://github.com/uptrace/bun/commit/e5079c70343ba8c8b410aed23ac1d1ae5a2c9ff6))
* prevent panic when use pg array with custom database type ([67e4412](https://github.com/uptrace/bun/commit/67e4412a972a9ed5f3a1d07c66957beedbc8a8a3))
* properly return sql.ErrNoRows when scanning []byte ([996fead](https://github.com/uptrace/bun/commit/996fead2595fbcaff4878b77befe6709a54b3a4d))
### Features
* mssql output support for update or delete query ([#718](https://github.com/uptrace/bun/issues/718)) ([08876b4](https://github.com/uptrace/bun/commit/08876b4d420e761cbfa658aa6bb89b3f7c62c240))
* add Err method to query builder ([c722c90](https://github.com/uptrace/bun/commit/c722c90f3dce2642ca4f4c2ab3f9a35cd496b557))
* add support for time.Time array in Postgres ([3dd6f3b](https://github.com/uptrace/bun/commit/3dd6f3b2ac1bfbcda08240dc1676647b61715a9c))
* mssql and pg merge query ([#723](https://github.com/uptrace/bun/issues/723)) ([deea764](https://github.com/uptrace/bun/commit/deea764d9380b16aad34228aa32717d10f2a4bab))
* setError on attempt to set non-positive .Varchar() ([3335e0b](https://github.com/uptrace/bun/commit/3335e0b9d6d3f424145e1f715223a0fffe773d9a))
### Reverts
* go 1.18 ([67a4488](https://github.com/uptrace/bun/commit/67a448897eaaf1ebc54d629dfd3b2509b35da352))
## [1.1.9](https://github.com/uptrace/bun/compare/v1.1.8...v1.1.9) (2022-11-23)

View file

@ -28,7 +28,7 @@
- [Migrations](https://bun.uptrace.dev/guide/migrations.html).
- [Soft deletes](https://bun.uptrace.dev/guide/soft-deletes.html).
Resources:
### Resources
- [**Get started**](https://bun.uptrace.dev/guide/golang-orm.html)
- [Examples](https://github.com/uptrace/bun/tree/master/example)
@ -37,7 +37,11 @@ Resources:
- [Reference](https://pkg.go.dev/github.com/uptrace/bun)
- [Starter kit](https://github.com/go-bun/bun-starter-kit)
Featured projects using Bun:
### Tutorials
Wrote a tutorial for Bun? Create a PR to add here and on [Bun](https://bun.uptrace.dev/) site.
### Featured projects using Bun
- [uptrace](https://github.com/uptrace/uptrace) - Distributed tracing and metrics.
- [paralus](https://github.com/paralus/paralus) - All-in-one Kubernetes access manager.
@ -129,9 +133,11 @@ See [**Getting started**](https://bun.uptrace.dev/guide/golang-orm.html) guide a
- [Golang ClickHouse ORM](https://github.com/uptrace/go-clickhouse)
- [Golang msgpack](https://github.com/vmihailenco/msgpack)
## Contributors
## Contributing
Thanks to all the people who already contributed!
See [CONTRIBUTING.md](CONTRIBUTING.md) for some hints.
And thanks to all the people who already contributed!
<a href="https://github.com/uptrace/bun/graphs/contributors">
<img src="https://contributors-img.web.app/image?repo=uptrace/bun" />

12
vendor/github.com/uptrace/bun/db.go generated vendored
View file

@ -82,6 +82,10 @@ func (db *DB) NewValues(model interface{}) *ValuesQuery {
return NewValuesQuery(db, model)
}
func (db *DB) NewMerge() *MergeQuery {
return NewMergeQuery(db)
}
func (db *DB) NewSelect() *SelectQuery {
return NewSelectQuery(db)
}
@ -330,6 +334,10 @@ func (c Conn) NewValues(model interface{}) *ValuesQuery {
return NewValuesQuery(c.db, model).Conn(c)
}
func (c Conn) NewMerge() *MergeQuery {
return NewMergeQuery(c.db).Conn(c)
}
func (c Conn) NewSelect() *SelectQuery {
return NewSelectQuery(c.db).Conn(c)
}
@ -640,6 +648,10 @@ func (tx Tx) NewValues(model interface{}) *ValuesQuery {
return NewValuesQuery(tx.db, model).Conn(tx)
}
func (tx Tx) NewMerge() *MergeQuery {
return NewMergeQuery(tx.db).Conn(tx)
}
func (tx Tx) NewSelect() *SelectQuery {
return NewSelectQuery(tx.db).Conn(tx)
}

View file

@ -27,6 +27,9 @@ var (
float64Type = reflect.TypeOf((*float64)(nil)).Elem()
sliceFloat64Type = reflect.TypeOf([]float64(nil))
timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
sliceTimeType = reflect.TypeOf([]time.Time(nil))
)
func arrayAppend(fmter schema.Formatter, b []byte, v interface{}) []byte {
@ -93,6 +96,8 @@ func (d *Dialect) arrayAppender(typ reflect.Type) schema.AppenderFunc {
return appendInt64SliceValue
case float64Type:
return appendFloat64SliceValue
case timeType:
return appendTimeSliceValue
}
}
@ -308,6 +313,32 @@ func arrayAppendString(b []byte, s string) []byte {
return b
}
func appendTimeSliceValue(fmter schema.Formatter, b []byte, v reflect.Value) []byte {
ts := v.Convert(sliceTimeType).Interface().([]time.Time)
return appendTimeSlice(fmter, b, ts)
}
func appendTimeSlice(fmter schema.Formatter, b []byte, ts []time.Time) []byte {
if ts == nil {
return dialect.AppendNull(b)
}
b = append(b, '\'')
b = append(b, '{')
for _, t := range ts {
b = append(b, '"')
b = t.UTC().AppendFormat(b, "2006-01-02 15:04:05.999999-07:00")
b = append(b, '"')
b = append(b, ',')
}
if len(ts) > 0 {
b[len(b)-1] = '}' // Replace trailing comma.
} else {
b = append(b, '}')
}
b = append(b, '\'')
return b
}
//------------------------------------------------------------------------------
var mapStringStringType = reflect.TypeOf(map[string]string(nil))

View file

@ -45,6 +45,10 @@ var (
jsonRawMessageType = reflect.TypeOf((*json.RawMessage)(nil)).Elem()
)
func (d *Dialect) DefaultVarcharLen() int {
return 0
}
func fieldSQLType(field *schema.Field) string {
if field.UserSQLType != "" {
return field.UserSQLType

View file

@ -2,5 +2,5 @@ package pgdialect
// Version is the current release version.
func Version() string {
return "1.1.9"
return "1.1.10"
}

View file

@ -87,6 +87,10 @@ func (d *Dialect) AppendBytes(b []byte, bs []byte) []byte {
return b
}
func (d *Dialect) DefaultVarcharLen() int {
return 0
}
func fieldSQLType(field *schema.Field) string {
switch field.DiscoveredSQLType {
case sqltype.SmallInt, sqltype.BigInt:

View file

@ -2,5 +2,5 @@ package sqlitedialect
// Version is the current release version.
func Version() string {
return "1.1.9"
return "1.1.10"
}

View file

@ -6,6 +6,7 @@ import (
"strings"
"sync/atomic"
"time"
"unicode"
"github.com/uptrace/bun/schema"
)
@ -35,13 +36,15 @@ func (e *QueryEvent) Operation() string {
}
func queryOperation(query string) string {
if idx := strings.IndexByte(query, ' '); idx > 0 {
query = query[:idx]
queryOp := strings.TrimLeftFunc(query, unicode.IsSpace)
if idx := strings.IndexByte(queryOp, ' '); idx > 0 {
queryOp = queryOp[:idx]
}
if len(query) > 16 {
query = query[:16]
if len(queryOp) > 16 {
queryOp = queryOp[:16]
}
return query
return queryOp
}
type QueryHook interface {

View file

@ -25,12 +25,12 @@ func MakeSliceNextElemFunc(v reflect.Value) func() reflect.Value {
if elem.IsNil() {
elem.Set(reflect.New(elemType))
}
return elem.Elem()
return elem
}
elem := reflect.New(elemType)
v.Set(reflect.Append(v, elem))
return elem.Elem()
return elem
}
}

View file

@ -13,7 +13,10 @@ import (
var errNilModel = errors.New("bun: Model(nil)")
var timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
var (
timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
bytesType = reflect.TypeOf((*[]byte)(nil)).Elem()
)
type Model = schema.Model
@ -102,19 +105,22 @@ func _newModel(db *DB, dest interface{}, scan bool) (Model, error) {
}
v = v.Elem()
typ := v.Type()
switch typ {
case timeType, bytesType:
return newScanModel(db, []interface{}{dest}), nil
}
switch v.Kind() {
case reflect.Map:
typ := v.Type()
if err := validMap(typ); err != nil {
return nil, err
}
mapPtr := v.Addr().Interface().(*map[string]interface{})
return newMapModel(db, mapPtr), nil
case reflect.Struct:
if v.Type() != timeType {
return newStructTableModelValue(db, dest, v), nil
}
return newStructTableModelValue(db, dest, v), nil
case reflect.Slice:
switch elemType := sliceElemType(v); elemType.Kind() {
case reflect.Struct:

View file

@ -6,6 +6,7 @@ import (
"reflect"
"time"
"github.com/uptrace/bun/internal"
"github.com/uptrace/bun/schema"
)
@ -33,7 +34,7 @@ func newSliceTableModel(
slice: slice,
sliceLen: slice.Len(),
nextElem: makeSliceNextElemFunc(slice),
nextElem: internal.MakeSliceNextElemFunc(slice),
}
m.init(slice.Type())
return m

View file

@ -1,6 +1,6 @@
{
"name": "gobun",
"version": "1.1.9",
"version": "1.1.10",
"main": "index.js",
"repository": "git@github.com:uptrace/bun.git",
"author": "Vladimir Mihailenco <vladimir.webdev@gmail.com>",

View file

@ -37,6 +37,18 @@ func (q *AddColumnQuery) Model(model interface{}) *AddColumnQuery {
return q
}
func (q *AddColumnQuery) Err(err error) *AddColumnQuery {
q.setErr(err)
return q
}
func (q *AddColumnQuery) Apply(fn func(*AddColumnQuery) *AddColumnQuery) *AddColumnQuery {
if fn != nil {
return fn(q)
}
return q
}
//------------------------------------------------------------------------------
func (q *AddColumnQuery) Table(tables ...string) *AddColumnQuery {

View file

@ -35,6 +35,18 @@ func (q *DropColumnQuery) Model(model interface{}) *DropColumnQuery {
return q
}
func (q *DropColumnQuery) Err(err error) *DropColumnQuery {
q.setErr(err)
return q
}
func (q *DropColumnQuery) Apply(fn func(*DropColumnQuery) *DropColumnQuery) *DropColumnQuery {
if fn != nil {
return fn(q)
}
return q
}
//------------------------------------------------------------------------------
func (q *DropColumnQuery) Table(tables ...string) *DropColumnQuery {

View file

@ -39,9 +39,17 @@ func (q *DeleteQuery) Model(model interface{}) *DeleteQuery {
return q
}
func (q *DeleteQuery) Err(err error) *DeleteQuery {
q.setErr(err)
return q
}
// Apply calls the fn passing the DeleteQuery as an argument.
func (q *DeleteQuery) Apply(fn func(*DeleteQuery) *DeleteQuery) *DeleteQuery {
return fn(q)
if fn != nil {
return fn(q)
}
return q
}
func (q *DeleteQuery) With(name string, query schema.QueryAppender) *DeleteQuery {
@ -127,13 +135,6 @@ func (q *DeleteQuery) Returning(query string, args ...interface{}) *DeleteQuery
return q
}
func (q *DeleteQuery) hasReturning() bool {
if !q.db.features.Has(feature.Returning) {
return false
}
return q.returningQuery.hasReturning()
}
//------------------------------------------------------------------------------
func (q *DeleteQuery) Operation() string {
@ -189,6 +190,14 @@ func (q *DeleteQuery) AppendQuery(fmter schema.Formatter, b []byte) (_ []byte, e
}
}
if q.hasFeature(feature.Output) && q.hasReturning() {
b = append(b, " OUTPUT "...)
b, err = q.appendOutput(fmter, b)
if err != nil {
return nil, err
}
}
b, err = q.mustAppendWhere(fmter, b, withAlias)
if err != nil {
return nil, err
@ -223,7 +232,18 @@ func (q *DeleteQuery) softDeleteSet(fmter schema.Formatter, tm time.Time) string
//------------------------------------------------------------------------------
func (q *DeleteQuery) Scan(ctx context.Context, dest ...interface{}) error {
_, err := q.scanOrExec(ctx, dest, true)
return err
}
func (q *DeleteQuery) Exec(ctx context.Context, dest ...interface{}) (sql.Result, error) {
return q.scanOrExec(ctx, dest, len(dest) > 0)
}
func (q *DeleteQuery) scanOrExec(
ctx context.Context, dest []interface{}, hasDest bool,
) (sql.Result, error) {
if q.err != nil {
return nil, q.err
}
@ -234,25 +254,33 @@ func (q *DeleteQuery) Exec(ctx context.Context, dest ...interface{}) (sql.Result
}
}
// Run append model hooks before generating the query.
if err := q.beforeAppendModel(ctx, q); err != nil {
return nil, err
}
// Generate the query before checking hasReturning.
queryBytes, err := q.AppendQuery(q.db.fmter, q.db.makeQueryBytes())
if err != nil {
return nil, err
}
useScan := hasDest || (q.hasReturning() && q.hasFeature(feature.Returning|feature.Output))
var model Model
if useScan {
var err error
model, err = q.getModel(dest)
if err != nil {
return nil, err
}
}
query := internal.String(queryBytes)
var res sql.Result
if hasDest := len(dest) > 0; hasDest || q.hasReturning() {
model, err := q.getModel(dest)
if err != nil {
return nil, err
}
if useScan {
res, err = q.scan(ctx, q, query, model, hasDest)
if err != nil {
return nil, err

View file

@ -46,6 +46,11 @@ func (q *CreateIndexQuery) Model(model interface{}) *CreateIndexQuery {
return q
}
func (q *CreateIndexQuery) Err(err error) *CreateIndexQuery {
q.setErr(err)
return q
}
func (q *CreateIndexQuery) Unique() *CreateIndexQuery {
q.unique = true
return q

View file

@ -40,6 +40,11 @@ func (q *DropIndexQuery) Model(model interface{}) *DropIndexQuery {
return q
}
func (q *DropIndexQuery) Err(err error) *DropIndexQuery {
q.setErr(err)
return q
}
//------------------------------------------------------------------------------
func (q *DropIndexQuery) Concurrently() *DropIndexQuery {

View file

@ -48,9 +48,17 @@ func (q *InsertQuery) Model(model interface{}) *InsertQuery {
return q
}
func (q *InsertQuery) Err(err error) *InsertQuery {
q.setErr(err)
return q
}
// Apply calls the fn passing the SelectQuery as an argument.
func (q *InsertQuery) Apply(fn func(*InsertQuery) *InsertQuery) *InsertQuery {
return fn(q)
if fn != nil {
return fn(q)
}
return q
}
func (q *InsertQuery) With(name string, query schema.QueryAppender) *InsertQuery {
@ -189,7 +197,7 @@ func (q *InsertQuery) AppendQuery(fmter schema.Formatter, b []byte) (_ []byte, e
return nil, err
}
b, err = q.appendColumnsValues(fmter, b)
b, err = q.appendColumnsValues(fmter, b, false)
if err != nil {
return nil, err
}
@ -211,7 +219,7 @@ func (q *InsertQuery) AppendQuery(fmter schema.Formatter, b []byte) (_ []byte, e
}
func (q *InsertQuery) appendColumnsValues(
fmter schema.Formatter, b []byte,
fmter schema.Formatter, b []byte, skipOutput bool,
) (_ []byte, err error) {
if q.hasMultiTables() {
if q.columns != nil {
@ -272,7 +280,7 @@ func (q *InsertQuery) appendColumnsValues(
b = q.appendFields(fmter, b, fields)
b = append(b, ")"...)
if q.hasFeature(feature.Output) && q.hasReturning() {
if q.hasFeature(feature.Output) && q.hasReturning() && !skipOutput {
b = append(b, " OUTPUT "...)
b, err = q.appendOutput(fmter, b)
if err != nil {
@ -534,35 +542,54 @@ func (q *InsertQuery) appendSetValues(b []byte, fields []*schema.Field) []byte {
//------------------------------------------------------------------------------
func (q *InsertQuery) Scan(ctx context.Context, dest ...interface{}) error {
_, err := q.scanOrExec(ctx, dest, true)
return err
}
func (q *InsertQuery) Exec(ctx context.Context, dest ...interface{}) (sql.Result, error) {
return q.scanOrExec(ctx, dest, len(dest) > 0)
}
func (q *InsertQuery) scanOrExec(
ctx context.Context, dest []interface{}, hasDest bool,
) (sql.Result, error) {
if q.err != nil {
return nil, q.err
}
if q.table != nil {
if err := q.beforeInsertHook(ctx); err != nil {
return nil, err
}
}
if q.err != nil {
return nil, q.err
}
// Run append model hooks before generating the query.
if err := q.beforeAppendModel(ctx, q); err != nil {
return nil, err
}
// Generate the query before checking hasReturning.
queryBytes, err := q.AppendQuery(q.db.fmter, q.db.makeQueryBytes())
if err != nil {
return nil, err
}
query := internal.String(queryBytes)
var res sql.Result
useScan := hasDest || (q.hasReturning() && q.hasFeature(feature.InsertReturning|feature.Output))
var model Model
if hasDest := len(dest) > 0; hasDest ||
(q.hasReturning() && q.hasFeature(feature.InsertReturning|feature.Output)) {
model, err := q.getModel(dest)
if useScan {
var err error
model, err = q.getModel(dest)
if err != nil {
return nil, err
}
}
query := internal.String(queryBytes)
var res sql.Result
if useScan {
res, err = q.scan(ctx, q, query, model, hasDest)
if err != nil {
return nil, err

322
vendor/github.com/uptrace/bun/query_merge.go generated vendored Normal file
View file

@ -0,0 +1,322 @@
package bun
import (
"context"
"database/sql"
"errors"
"github.com/uptrace/bun/dialect"
"github.com/uptrace/bun/dialect/feature"
"github.com/uptrace/bun/internal"
"github.com/uptrace/bun/schema"
)
type MergeQuery struct {
baseQuery
returningQuery
using schema.QueryWithArgs
on schema.QueryWithArgs
when []schema.QueryAppender
}
var _ Query = (*MergeQuery)(nil)
func NewMergeQuery(db *DB) *MergeQuery {
q := &MergeQuery{
baseQuery: baseQuery{
db: db,
conn: db.DB,
},
}
if !(q.db.dialect.Name() == dialect.MSSQL || q.db.dialect.Name() == dialect.PG) {
q.err = errors.New("bun: merge not supported for current dialect")
}
return q
}
func (q *MergeQuery) Conn(db IConn) *MergeQuery {
q.setConn(db)
return q
}
func (q *MergeQuery) Model(model interface{}) *MergeQuery {
q.setModel(model)
return q
}
func (q *MergeQuery) Err(err error) *MergeQuery {
q.setErr(err)
return q
}
// Apply calls the fn passing the MergeQuery as an argument.
func (q *MergeQuery) Apply(fn func(*MergeQuery) *MergeQuery) *MergeQuery {
if fn != nil {
return fn(q)
}
return q
}
func (q *MergeQuery) With(name string, query schema.QueryAppender) *MergeQuery {
q.addWith(name, query, false)
return q
}
func (q *MergeQuery) WithRecursive(name string, query schema.QueryAppender) *MergeQuery {
q.addWith(name, query, true)
return q
}
//------------------------------------------------------------------------------
func (q *MergeQuery) Table(tables ...string) *MergeQuery {
for _, table := range tables {
q.addTable(schema.UnsafeIdent(table))
}
return q
}
func (q *MergeQuery) TableExpr(query string, args ...interface{}) *MergeQuery {
q.addTable(schema.SafeQuery(query, args))
return q
}
func (q *MergeQuery) ModelTableExpr(query string, args ...interface{}) *MergeQuery {
q.modelTableName = schema.SafeQuery(query, args)
return q
}
//------------------------------------------------------------------------------
// Returning adds a RETURNING clause to the query.
//
// To suppress the auto-generated RETURNING clause, use `Returning("NULL")`.
// Only for mssql output, postgres not supported returning in merge query
func (q *MergeQuery) Returning(query string, args ...interface{}) *MergeQuery {
q.addReturning(schema.SafeQuery(query, args))
return q
}
//------------------------------------------------------------------------------
func (q *MergeQuery) Using(s string, args ...interface{}) *MergeQuery {
q.using = schema.SafeQuery(s, args)
return q
}
func (q *MergeQuery) On(s string, args ...interface{}) *MergeQuery {
q.on = schema.SafeQuery(s, args)
return q
}
// WhenInsert for when insert clause.
func (q *MergeQuery) WhenInsert(expr string, fn func(q *InsertQuery) *InsertQuery) *MergeQuery {
sq := NewInsertQuery(q.db)
// apply the model as default into sub query, since appendColumnsValues required
if q.model != nil {
sq = sq.Model(q.model)
}
sq = sq.Apply(fn)
q.when = append(q.when, &whenInsert{expr: expr, query: sq})
return q
}
// WhenUpdate for when update clause.
func (q *MergeQuery) WhenUpdate(expr string, fn func(q *UpdateQuery) *UpdateQuery) *MergeQuery {
sq := NewUpdateQuery(q.db)
// apply the model as default into sub query
if q.model != nil {
sq = sq.Model(q.model)
}
sq = sq.Apply(fn)
q.when = append(q.when, &whenUpdate{expr: expr, query: sq})
return q
}
// WhenDelete for when delete clause.
func (q *MergeQuery) WhenDelete(expr string) *MergeQuery {
q.when = append(q.when, &whenDelete{expr: expr})
return q
}
// When for raw expression clause.
func (q *MergeQuery) When(expr string, args ...interface{}) *MergeQuery {
q.when = append(q.when, schema.SafeQuery(expr, args))
return q
}
//------------------------------------------------------------------------------
func (q *MergeQuery) Operation() string {
return "MERGE"
}
func (q *MergeQuery) AppendQuery(fmter schema.Formatter, b []byte) (_ []byte, err error) {
if q.err != nil {
return nil, q.err
}
fmter = formatterWithModel(fmter, q)
b, err = q.appendWith(fmter, b)
if err != nil {
return nil, err
}
b = append(b, "MERGE "...)
if q.db.dialect.Name() == dialect.PG {
b = append(b, "INTO "...)
}
b, err = q.appendFirstTableWithAlias(fmter, b)
if err != nil {
return nil, err
}
b = append(b, " USING "...)
b, err = q.using.AppendQuery(fmter, b)
if err != nil {
return nil, err
}
b = append(b, " ON "...)
b, err = q.on.AppendQuery(fmter, b)
if err != nil {
return nil, err
}
for _, w := range q.when {
b = append(b, " WHEN "...)
b, err = w.AppendQuery(fmter, b)
if err != nil {
return nil, err
}
}
if q.hasFeature(feature.Output) && q.hasReturning() {
b = append(b, " OUTPUT "...)
b, err = q.appendOutput(fmter, b)
if err != nil {
return nil, err
}
}
// A MERGE statement must be terminated by a semi-colon (;).
b = append(b, ";"...)
return b, nil
}
//------------------------------------------------------------------------------
func (q *MergeQuery) Scan(ctx context.Context, dest ...interface{}) error {
_, err := q.scanOrExec(ctx, dest, true)
return err
}
func (q *MergeQuery) Exec(ctx context.Context, dest ...interface{}) (sql.Result, error) {
return q.scanOrExec(ctx, dest, len(dest) > 0)
}
func (q *MergeQuery) scanOrExec(
ctx context.Context, dest []interface{}, hasDest bool,
) (sql.Result, error) {
if q.err != nil {
return nil, q.err
}
// Run append model hooks before generating the query.
if err := q.beforeAppendModel(ctx, q); err != nil {
return nil, err
}
// Generate the query before checking hasReturning.
queryBytes, err := q.AppendQuery(q.db.fmter, q.db.makeQueryBytes())
if err != nil {
return nil, err
}
useScan := hasDest || (q.hasReturning() && q.hasFeature(feature.InsertReturning|feature.Output))
var model Model
if useScan {
var err error
model, err = q.getModel(dest)
if err != nil {
return nil, err
}
}
query := internal.String(queryBytes)
var res sql.Result
if useScan {
res, err = q.scan(ctx, q, query, model, true)
if err != nil {
return nil, err
}
} else {
res, err = q.exec(ctx, q, query)
if err != nil {
return nil, err
}
}
return res, nil
}
func (q *MergeQuery) String() string {
buf, err := q.AppendQuery(q.db.Formatter(), nil)
if err != nil {
panic(err)
}
return string(buf)
}
//------------------------------------------------------------------------------
type whenInsert struct {
expr string
query *InsertQuery
}
func (w *whenInsert) AppendQuery(fmter schema.Formatter, b []byte) (_ []byte, err error) {
b = append(b, w.expr...)
if w.query != nil {
b = append(b, " THEN INSERT"...)
b, err = w.query.appendColumnsValues(fmter, b, true)
if err != nil {
return nil, err
}
}
return b, nil
}
type whenUpdate struct {
expr string
query *UpdateQuery
}
func (w *whenUpdate) AppendQuery(fmter schema.Formatter, b []byte) (_ []byte, err error) {
b = append(b, w.expr...)
if w.query != nil {
b = append(b, " THEN UPDATE SET "...)
b, err = w.query.appendSet(fmter, b)
if err != nil {
return nil, err
}
}
return b, nil
}
type whenDelete struct {
expr string
}
func (w *whenDelete) AppendQuery(fmter schema.Formatter, b []byte) (_ []byte, err error) {
b = append(b, w.expr...)
b = append(b, " THEN DELETE"...)
return b, nil
}

View file

@ -41,6 +41,11 @@ func (q *RawQuery) Conn(db IConn) *RawQuery {
return q
}
func (q *RawQuery) Err(err error) *RawQuery {
q.setErr(err)
return q
}
func (q *RawQuery) Scan(ctx context.Context, dest ...interface{}) error {
if q.err != nil {
return q.err

View file

@ -61,9 +61,17 @@ func (q *SelectQuery) Model(model interface{}) *SelectQuery {
return q
}
func (q *SelectQuery) Err(err error) *SelectQuery {
q.setErr(err)
return q
}
// Apply calls the fn passing the SelectQuery as an argument.
func (q *SelectQuery) Apply(fn func(*SelectQuery) *SelectQuery) *SelectQuery {
return fn(q)
if fn != nil {
return fn(q)
}
return q
}
func (q *SelectQuery) With(name string, query schema.QueryAppender) *SelectQuery {

View file

@ -3,8 +3,10 @@ package bun
import (
"context"
"database/sql"
"fmt"
"sort"
"strconv"
"strings"
"github.com/uptrace/bun/dialect/feature"
"github.com/uptrace/bun/dialect/sqltype"
@ -17,7 +19,12 @@ type CreateTableQuery struct {
temp bool
ifNotExists bool
varchar int
// varchar changes the default length for VARCHAR columns.
// Because some dialects require that length is always specified for VARCHAR type,
// we will use the exact user-defined type if length is set explicitly, as in `bun:",type:varchar(5)"`,
// but assume the new default length when it's omitted, e.g. `bun:",type:varchar"`.
varchar int
fks []schema.QueryWithArgs
partitionBy schema.QueryWithArgs
@ -32,6 +39,7 @@ func NewCreateTableQuery(db *DB) *CreateTableQuery {
db: db,
conn: db.DB,
},
varchar: db.Dialect().DefaultVarcharLen(),
}
return q
}
@ -46,6 +54,11 @@ func (q *CreateTableQuery) Model(model interface{}) *CreateTableQuery {
return q
}
func (q *CreateTableQuery) Err(err error) *CreateTableQuery {
q.setErr(err)
return q
}
// ------------------------------------------------------------------------------
func (q *CreateTableQuery) Table(tables ...string) *CreateTableQuery {
@ -82,7 +95,12 @@ func (q *CreateTableQuery) IfNotExists() *CreateTableQuery {
return q
}
// Varchar sets default length for VARCHAR columns.
func (q *CreateTableQuery) Varchar(n int) *CreateTableQuery {
if n <= 0 {
q.setErr(fmt.Errorf("bun: illegal VARCHAR length: %d", n))
return q
}
q.varchar = n
return q
}
@ -120,7 +138,7 @@ func (q *CreateTableQuery) WithForeignKeys() *CreateTableQuery {
return q
}
//------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
func (q *CreateTableQuery) Operation() string {
return "CREATE TABLE"
@ -221,19 +239,23 @@ func (q *CreateTableQuery) AppendQuery(fmter schema.Formatter, b []byte) (_ []by
}
func (q *CreateTableQuery) appendSQLType(b []byte, field *schema.Field) []byte {
if field.CreateTableSQLType != field.DiscoveredSQLType {
// Most of the time these two will match, but for the cases where DiscoveredSQLType is dialect-specific,
// e.g. pgdialect would change sqltype.SmallInt to pgTypeSmallSerial for columns that have `bun:",autoincrement"`
if !strings.EqualFold(field.CreateTableSQLType, field.DiscoveredSQLType) {
return append(b, field.CreateTableSQLType...)
}
if q.varchar > 0 &&
field.CreateTableSQLType == sqltype.VarChar {
b = append(b, "varchar("...)
b = strconv.AppendInt(b, int64(q.varchar), 10)
b = append(b, ")"...)
return b
// For all common SQL types except VARCHAR, both UserDefinedSQLType and DiscoveredSQLType specify the correct type,
// and we needn't modify it. For VARCHAR columns, we will stop to check if a valid length has been set in .Varchar(int).
if !strings.EqualFold(field.CreateTableSQLType, sqltype.VarChar) || q.varchar <= 0 {
return append(b, field.CreateTableSQLType...)
}
return append(b, field.CreateTableSQLType...)
b = append(b, sqltype.VarChar...)
b = append(b, "("...)
b = strconv.AppendInt(b, int64(q.varchar), 10)
b = append(b, ")"...)
return b
}
func (q *CreateTableQuery) appendUniqueConstraints(fmter schema.Formatter, b []byte) []byte {

View file

@ -37,6 +37,11 @@ func (q *DropTableQuery) Model(model interface{}) *DropTableQuery {
return q
}
func (q *DropTableQuery) Err(err error) *DropTableQuery {
q.setErr(err)
return q
}
//------------------------------------------------------------------------------
func (q *DropTableQuery) Table(tables ...string) *DropTableQuery {

View file

@ -38,6 +38,11 @@ func (q *TruncateTableQuery) Model(model interface{}) *TruncateTableQuery {
return q
}
func (q *TruncateTableQuery) Err(err error) *TruncateTableQuery {
q.setErr(err)
return q
}
//------------------------------------------------------------------------------
func (q *TruncateTableQuery) Table(tables ...string) *TruncateTableQuery {

View file

@ -47,9 +47,17 @@ func (q *UpdateQuery) Model(model interface{}) *UpdateQuery {
return q
}
func (q *UpdateQuery) Err(err error) *UpdateQuery {
q.setErr(err)
return q
}
// Apply calls the fn passing the SelectQuery as an argument.
func (q *UpdateQuery) Apply(fn func(*UpdateQuery) *UpdateQuery) *UpdateQuery {
return fn(q)
if fn != nil {
return fn(q)
}
return q
}
func (q *UpdateQuery) With(name string, query schema.QueryAppender) *UpdateQuery {
@ -174,13 +182,6 @@ func (q *UpdateQuery) Returning(query string, args ...interface{}) *UpdateQuery
return q
}
func (q *UpdateQuery) hasReturning() bool {
if !q.db.features.Has(feature.Returning) {
return false
}
return q.returningQuery.hasReturning()
}
//------------------------------------------------------------------------------
func (q *UpdateQuery) Operation() string {
@ -229,6 +230,14 @@ func (q *UpdateQuery) AppendQuery(fmter schema.Formatter, b []byte) (_ []byte, e
}
}
if q.hasFeature(feature.Output) && q.hasReturning() {
b = append(b, " OUTPUT "...)
b, err = q.appendOutput(fmter, b)
if err != nil {
return nil, err
}
}
b, err = q.mustAppendWhere(fmter, b, q.hasTableAlias(fmter))
if err != nil {
return nil, err
@ -426,7 +435,18 @@ func (q *UpdateQuery) updateSliceWhere(fmter schema.Formatter, model *sliceTable
//------------------------------------------------------------------------------
func (q *UpdateQuery) Scan(ctx context.Context, dest ...interface{}) error {
_, err := q.scanOrExec(ctx, dest, true)
return err
}
func (q *UpdateQuery) Exec(ctx context.Context, dest ...interface{}) (sql.Result, error) {
return q.scanOrExec(ctx, dest, len(dest) > 0)
}
func (q *UpdateQuery) scanOrExec(
ctx context.Context, dest []interface{}, hasDest bool,
) (sql.Result, error) {
if q.err != nil {
return nil, q.err
}
@ -437,25 +457,33 @@ func (q *UpdateQuery) Exec(ctx context.Context, dest ...interface{}) (sql.Result
}
}
// Run append model hooks before generating the query.
if err := q.beforeAppendModel(ctx, q); err != nil {
return nil, err
}
// Generate the query before checking hasReturning.
queryBytes, err := q.AppendQuery(q.db.fmter, q.db.makeQueryBytes())
if err != nil {
return nil, err
}
useScan := hasDest || (q.hasReturning() && q.hasFeature(feature.Returning|feature.Output))
var model Model
if useScan {
var err error
model, err = q.getModel(dest)
if err != nil {
return nil, err
}
}
query := internal.String(queryBytes)
var res sql.Result
if hasDest := len(dest) > 0; hasDest || q.hasReturning() {
model, err := q.getModel(dest)
if err != nil {
return nil, err
}
if useScan {
res, err = q.scan(ctx, q, query, model, hasDest)
if err != nil {
return nil, err
@ -498,7 +526,7 @@ func (q *UpdateQuery) afterUpdateHook(ctx context.Context) error {
// table_alias.column_alias.
func (q *UpdateQuery) FQN(column string) Ident {
if q.table == nil {
panic("UpdateQuery.SetName requires a model")
panic("UpdateQuery.FQN requires a model")
}
if q.hasTableAlias(q.db.fmter) {
return Ident(q.table.Alias + "." + column)

View file

@ -37,6 +37,11 @@ func (q *ValuesQuery) Conn(db IConn) *ValuesQuery {
return q
}
func (q *ValuesQuery) Err(err error) *ValuesQuery {
q.setErr(err)
return q
}
func (q *ValuesQuery) Column(columns ...string) *ValuesQuery {
for _, column := range columns {
q.addColumn(schema.UnsafeIdent(column))

View file

@ -30,9 +30,14 @@ type Dialect interface {
AppendBytes(b []byte, bs []byte) []byte
AppendJSON(b, jsonb []byte) []byte
AppendBool(b []byte, v bool) []byte
// DefaultVarcharLen should be returned for dialects in which specifying VARCHAR length
// is mandatory in queries that modify the schema (CREATE TABLE / ADD COLUMN, etc).
// Dialects that do not have such requirement may return 0, which should be interpreted so by the caller.
DefaultVarcharLen() int
}
//------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
type BaseDialect struct{}
@ -131,7 +136,7 @@ func (BaseDialect) AppendBool(b []byte, v bool) []byte {
return dialect.AppendBool(b, v)
}
//------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
type nopDialect struct {
BaseDialect
@ -168,3 +173,7 @@ func (d *nopDialect) OnTable(table *Table) {}
func (d *nopDialect) IdentQuote() byte {
return '"'
}
func (d *nopDialect) DefaultVarcharLen() int {
return 0
}

View file

@ -66,49 +66,3 @@ func sliceElemType(v reflect.Value) reflect.Type {
}
return indirectType(elemType)
}
func makeSliceNextElemFunc(v reflect.Value) func() reflect.Value {
if v.Kind() == reflect.Array {
var pos int
return func() reflect.Value {
v := v.Index(pos)
pos++
return v
}
}
sliceType := v.Type()
elemType := sliceType.Elem()
if elemType.Kind() == reflect.Ptr {
elemType = elemType.Elem()
return func() reflect.Value {
if v.Len() < v.Cap() {
v.Set(v.Slice(0, v.Len()+1))
elem := v.Index(v.Len() - 1)
if elem.IsNil() {
elem.Set(reflect.New(elemType))
}
return elem.Elem()
}
elem := reflect.New(elemType)
v.Set(reflect.Append(v, elem))
return elem.Elem()
}
}
zero := reflect.Zero(elemType)
return func() reflect.Value {
l := v.Len()
c := v.Cap()
if l < c {
v.Set(v.Slice(0, l+1))
return v.Index(l)
}
v.Set(reflect.Append(v, zero))
return v.Index(l)
}
}

View file

@ -2,5 +2,5 @@ package bun
// Version is the current release version.
func Version() string {
return "1.1.9"
return "1.1.10"
}