upstep bun to v1.0.14 (#291)

This commit is contained in:
tobi 2021-10-24 13:14:37 +02:00 committed by GitHub
commit 8b7c3507fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
100 changed files with 5071 additions and 3836 deletions

View file

@ -4,11 +4,9 @@ import (
"encoding/hex"
"math"
"strconv"
"time"
"unicode/utf8"
"github.com/uptrace/bun/internal"
"github.com/uptrace/bun/internal/parser"
)
func AppendError(b []byte, err error) []byte {
@ -78,55 +76,16 @@ func AppendString(b []byte, s string) []byte {
return b
}
func AppendBytes(b []byte, bytes []byte) []byte {
if bytes == nil {
func AppendBytes(b, bs []byte) []byte {
if bs == nil {
return AppendNull(b)
}
b = append(b, `'\x`...)
s := len(b)
b = append(b, make([]byte, hex.EncodedLen(len(bytes)))...)
hex.Encode(b[s:], bytes)
b = append(b, '\'')
return b
}
func AppendTime(b []byte, tm time.Time) []byte {
b = append(b, '\'')
b = tm.UTC().AppendFormat(b, "2006-01-02 15:04:05.999999-07:00")
b = append(b, '\'')
return b
}
func AppendJSON(b, jsonb []byte) []byte {
b = append(b, '\'')
p := parser.New(jsonb)
for p.Valid() {
c := p.Read()
switch c {
case '"':
b = append(b, '"')
case '\'':
b = append(b, "''"...)
case '\000':
continue
case '\\':
if p.SkipBytes([]byte("u0000")) {
b = append(b, `\\u0000`...)
} else {
b = append(b, '\\')
if p.Valid() {
b = append(b, p.Read())
}
}
default:
b = append(b, c)
}
}
b = append(b, make([]byte, hex.EncodedLen(len(bs)))...)
hex.Encode(b[s:], bs)
b = append(b, '\'')

View file

@ -2,6 +2,7 @@ package pgdialect
import (
"database/sql/driver"
"encoding/hex"
"fmt"
"reflect"
"strconv"
@ -28,26 +29,6 @@ var (
sliceFloat64Type = reflect.TypeOf([]float64(nil))
)
func customAppender(typ reflect.Type) schema.AppenderFunc {
switch typ.Kind() {
case reflect.Uint32:
return appendUint32ValueAsInt
case reflect.Uint, reflect.Uint64:
return appendUint64ValueAsInt
}
return nil
}
func appendUint32ValueAsInt(fmter schema.Formatter, b []byte, v reflect.Value) []byte {
return strconv.AppendInt(b, int64(int32(v.Uint())), 10)
}
func appendUint64ValueAsInt(fmter schema.Formatter, b []byte, v reflect.Value) []byte {
return strconv.AppendInt(b, int64(v.Uint()), 10)
}
//------------------------------------------------------------------------------
func arrayAppend(fmter schema.Formatter, b []byte, v interface{}) []byte {
switch v := v.(type) {
case int64:
@ -57,31 +38,25 @@ func arrayAppend(fmter schema.Formatter, b []byte, v interface{}) []byte {
case bool:
return dialect.AppendBool(b, v)
case []byte:
return dialect.AppendBytes(b, v)
return arrayAppendBytes(b, v)
case string:
return arrayAppendString(b, v)
case time.Time:
return dialect.AppendTime(b, v)
return fmter.Dialect().AppendTime(b, v)
default:
err := fmt.Errorf("pgdialect: can't append %T", v)
return dialect.AppendError(b, err)
}
}
func arrayElemAppender(typ reflect.Type) schema.AppenderFunc {
if typ.Kind() == reflect.String {
return arrayAppendStringValue
}
if typ.Implements(driverValuerType) {
return arrayAppendDriverValue
}
return schema.Appender(typ, customAppender)
}
func arrayAppendStringValue(fmter schema.Formatter, b []byte, v reflect.Value) []byte {
return arrayAppendString(b, v.String())
}
func arrayAppendBytesValue(fmter schema.Formatter, b []byte, v reflect.Value) []byte {
return arrayAppendBytes(b, v.Bytes())
}
func arrayAppendDriverValue(fmter schema.Formatter, b []byte, v reflect.Value) []byte {
iface, err := v.Interface().(driver.Valuer).Value()
if err != nil {
@ -92,12 +67,12 @@ func arrayAppendDriverValue(fmter schema.Formatter, b []byte, v reflect.Value) [
//------------------------------------------------------------------------------
func arrayAppender(typ reflect.Type) schema.AppenderFunc {
func (d *Dialect) arrayAppender(typ reflect.Type) schema.AppenderFunc {
kind := typ.Kind()
switch kind {
case reflect.Ptr:
if fn := arrayAppender(typ.Elem()); fn != nil {
if fn := d.arrayAppender(typ.Elem()); fn != nil {
return schema.PtrAppender(fn)
}
case reflect.Slice, reflect.Array:
@ -121,7 +96,7 @@ func arrayAppender(typ reflect.Type) schema.AppenderFunc {
}
}
appendElem := arrayElemAppender(elemType)
appendElem := d.arrayElemAppender(elemType)
if appendElem == nil {
panic(fmt.Errorf("pgdialect: %s is not supported", typ))
}
@ -159,6 +134,21 @@ func arrayAppender(typ reflect.Type) schema.AppenderFunc {
}
}
func (d *Dialect) arrayElemAppender(typ reflect.Type) schema.AppenderFunc {
if typ.Implements(driverValuerType) {
return arrayAppendDriverValue
}
switch typ.Kind() {
case reflect.String:
return arrayAppendStringValue
case reflect.Slice:
if typ.Elem().Kind() == reflect.Uint8 {
return arrayAppendBytesValue
}
}
return schema.Appender(d, typ)
}
func appendStringSliceValue(fmter schema.Formatter, b []byte, v reflect.Value) []byte {
ss := v.Convert(sliceStringType).Interface().([]string)
return appendStringSlice(b, ss)
@ -273,6 +263,22 @@ func appendFloat64Slice(b []byte, floats []float64) []byte {
//------------------------------------------------------------------------------
func arrayAppendBytes(b []byte, bs []byte) []byte {
if bs == nil {
return dialect.AppendNull(b)
}
b = append(b, `"\\x`...)
s := len(b)
b = append(b, make([]byte, hex.EncodedLen(len(bs)))...)
hex.Encode(b[s:], bs)
b = append(b, '"')
return b
}
func arrayAppendString(b []byte, s string) []byte {
b = append(b, '"')
for _, r := range s {
@ -280,7 +286,7 @@ func arrayAppendString(b []byte, s string) []byte {
case 0:
// ignore
case '\'':
b = append(b, "'''"...)
b = append(b, "''"...)
case '"':
b = append(b, '\\', '"')
case '\\':

View file

@ -30,7 +30,7 @@ func Array(vi interface{}) *ArrayValue {
return &ArrayValue{
v: v,
append: arrayAppender(v.Type()),
append: pgDialect.arrayAppender(v.Type()),
scan: arrayScanner(v.Type()),
}
}

View file

@ -2,6 +2,7 @@ package pgdialect
import (
"bytes"
"encoding/hex"
"fmt"
"io"
)
@ -109,11 +110,29 @@ func (p *arrayParser) readSubstring() ([]byte, error) {
}
continue
}
if c == '\'' && next == '\'' {
p.buf = append(p.buf, next)
c, err = p.readByte()
if err != nil {
return nil, err
}
continue
}
p.buf = append(p.buf, c)
c = next
}
if bytes.HasPrefix(p.buf, []byte("\\x")) && len(p.buf)%2 == 0 {
data := p.buf[2:]
buf := make([]byte, hex.DecodedLen(len(data)))
n, err := hex.Decode(buf, data)
if err != nil {
return nil, err
}
return buf[:n], nil
}
return p.buf, nil
}

View file

@ -2,10 +2,7 @@ package pgdialect
import (
"database/sql"
"reflect"
"strconv"
"sync"
"time"
"github.com/uptrace/bun/dialect"
"github.com/uptrace/bun/dialect/feature"
@ -13,12 +10,13 @@ import (
"github.com/uptrace/bun/schema"
)
var pgDialect = New()
type Dialect struct {
schema.BaseDialect
tables *schema.Tables
features feature.Feature
appenderMap sync.Map
scannerMap sync.Map
}
func New() *Dialect {
@ -71,7 +69,7 @@ func (d *Dialect) onField(field *schema.Field) {
}
if field.Tag.HasOption("array") {
field.Append = arrayAppender(field.StructField.Type)
field.Append = d.arrayAppender(field.StructField.Type)
field.Scan = arrayScanner(field.StructField.Type)
}
}
@ -80,72 +78,10 @@ func (d *Dialect) IdentQuote() byte {
return '"'
}
func (d *Dialect) Append(fmter schema.Formatter, b []byte, v interface{}) []byte {
switch v := v.(type) {
case nil:
return dialect.AppendNull(b)
case bool:
return dialect.AppendBool(b, v)
case int:
return strconv.AppendInt(b, int64(v), 10)
case int32:
return strconv.AppendInt(b, int64(v), 10)
case int64:
return strconv.AppendInt(b, v, 10)
case uint:
return strconv.AppendInt(b, int64(v), 10)
case uint32:
return strconv.AppendInt(b, int64(v), 10)
case uint64:
return strconv.AppendInt(b, int64(v), 10)
case float32:
return dialect.AppendFloat32(b, v)
case float64:
return dialect.AppendFloat64(b, v)
case string:
return dialect.AppendString(b, v)
case time.Time:
return dialect.AppendTime(b, v)
case []byte:
return dialect.AppendBytes(b, v)
case schema.QueryAppender:
return schema.AppendQueryAppender(fmter, b, v)
default:
vv := reflect.ValueOf(v)
if vv.Kind() == reflect.Ptr && vv.IsNil() {
return dialect.AppendNull(b)
}
appender := d.Appender(vv.Type())
return appender(fmter, b, vv)
}
func (d *Dialect) AppendUint32(b []byte, n uint32) []byte {
return strconv.AppendInt(b, int64(int32(n)), 10)
}
func (d *Dialect) Appender(typ reflect.Type) schema.AppenderFunc {
if v, ok := d.appenderMap.Load(typ); ok {
return v.(schema.AppenderFunc)
}
fn := schema.Appender(typ, customAppender)
if v, ok := d.appenderMap.LoadOrStore(typ, fn); ok {
return v.(schema.AppenderFunc)
}
return fn
}
func (d *Dialect) FieldAppender(field *schema.Field) schema.AppenderFunc {
return schema.FieldAppender(d, field)
}
func (d *Dialect) Scanner(typ reflect.Type) schema.ScannerFunc {
if v, ok := d.scannerMap.Load(typ); ok {
return v.(schema.ScannerFunc)
}
fn := scanner(typ)
if v, ok := d.scannerMap.LoadOrStore(typ, fn); ok {
return v.(schema.ScannerFunc)
}
return fn
func (d *Dialect) AppendUint64(b []byte, n uint64) []byte {
return strconv.AppendInt(b, int64(n), 10)
}

View file

@ -68,6 +68,10 @@ func fieldSQLType(field *schema.Field) string {
}
}
if field.DiscoveredSQLType == sqltype.Blob {
return pgTypeBytea
}
return sqlType(field.IndirectType)
}

View file

@ -2,8 +2,7 @@ package sqlitedialect
import (
"database/sql"
"reflect"
"sync"
"encoding/hex"
"github.com/uptrace/bun/dialect"
"github.com/uptrace/bun/dialect/feature"
@ -12,11 +11,10 @@ import (
)
type Dialect struct {
schema.BaseDialect
tables *schema.Tables
features feature.Feature
appenderMap sync.Map
scannerMap sync.Map
}
func New() *Dialect {
@ -50,48 +48,36 @@ func (d *Dialect) OnTable(table *schema.Table) {
}
func (d *Dialect) onField(field *schema.Field) {
// INTEGER PRIMARY KEY is an alias for the ROWID.
// It is safe to convert all ints to INTEGER, because SQLite types don't have size.
switch field.DiscoveredSQLType {
case sqltype.SmallInt, sqltype.BigInt:
field.DiscoveredSQLType = sqltype.Integer
}
field.DiscoveredSQLType = fieldSQLType(field)
}
func (d *Dialect) IdentQuote() byte {
return '"'
}
func (d *Dialect) Append(fmter schema.Formatter, b []byte, v interface{}) []byte {
return schema.Append(fmter, b, v, nil)
}
func (d *Dialect) Appender(typ reflect.Type) schema.AppenderFunc {
if v, ok := d.appenderMap.Load(typ); ok {
return v.(schema.AppenderFunc)
func (d *Dialect) AppendBytes(b []byte, bs []byte) []byte {
if bs == nil {
return dialect.AppendNull(b)
}
fn := schema.Appender(typ, nil)
b = append(b, `X'`...)
if v, ok := d.appenderMap.LoadOrStore(typ, fn); ok {
return v.(schema.AppenderFunc)
}
return fn
s := len(b)
b = append(b, make([]byte, hex.EncodedLen(len(bs)))...)
hex.Encode(b[s:], bs)
b = append(b, '\'')
return b
}
func (d *Dialect) FieldAppender(field *schema.Field) schema.AppenderFunc {
return schema.FieldAppender(d, field)
}
func (d *Dialect) Scanner(typ reflect.Type) schema.ScannerFunc {
if v, ok := d.scannerMap.Load(typ); ok {
return v.(schema.ScannerFunc)
func fieldSQLType(field *schema.Field) string {
switch field.DiscoveredSQLType {
case sqltype.SmallInt, sqltype.BigInt:
// INTEGER PRIMARY KEY is an alias for the ROWID.
// It is safe to convert all ints to INTEGER, because SQLite types don't have size.
return sqltype.Integer
default:
return field.DiscoveredSQLType
}
fn := scanner(typ)
if v, ok := d.scannerMap.LoadOrStore(typ, fn); ok {
return v.(schema.ScannerFunc)
}
return fn
}

View file

@ -8,6 +8,7 @@ const (
Real = "REAL"
DoublePrecision = "DOUBLE PRECISION"
VarChar = "VARCHAR"
Blob = "BLOB"
Timestamp = "TIMESTAMP"
JSON = "JSON"
JSONB = "JSONB"