diff options
Diffstat (limited to 'vendor/github.com/uptrace/bun/dialect')
13 files changed, 962 insertions, 902 deletions
diff --git a/vendor/github.com/uptrace/bun/dialect/dialect.go b/vendor/github.com/uptrace/bun/dialect/dialect.go index 03b81fbbc..4dde63c92 100644 --- a/vendor/github.com/uptrace/bun/dialect/dialect.go +++ b/vendor/github.com/uptrace/bun/dialect/dialect.go @@ -12,6 +12,8 @@ func (n Name) String() string { return "mysql" case MSSQL: return "mssql" + case Oracle: + return "oracle" default: return "invalid" } @@ -23,4 +25,5 @@ const ( SQLite MySQL MSSQL + Oracle ) diff --git a/vendor/github.com/uptrace/bun/dialect/pgdialect/append.go b/vendor/github.com/uptrace/bun/dialect/pgdialect/append.go index 7e9491abc..c95fa86e7 100644 --- a/vendor/github.com/uptrace/bun/dialect/pgdialect/append.go +++ b/vendor/github.com/uptrace/bun/dialect/pgdialect/append.go @@ -2,12 +2,9 @@ package pgdialect import ( "database/sql/driver" - "encoding/hex" "fmt" "reflect" - "strconv" "time" - "unicode/utf8" "github.com/uptrace/bun/dialect" "github.com/uptrace/bun/schema" @@ -32,316 +29,10 @@ var ( sliceTimeType = reflect.TypeOf([]time.Time(nil)) ) -func arrayAppend(fmter schema.Formatter, b []byte, v interface{}) []byte { - switch v := v.(type) { - case int64: - return strconv.AppendInt(b, v, 10) - case float64: - return dialect.AppendFloat64(b, v) - case bool: - return dialect.AppendBool(b, v) - case []byte: - return arrayAppendBytes(b, v) - case string: - return arrayAppendString(b, v) - case time.Time: - return fmter.Dialect().AppendTime(b, v) - default: - err := fmt.Errorf("pgdialect: can't append %T", v) - return dialect.AppendError(b, err) - } -} - -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 { - return dialect.AppendError(b, err) - } - return arrayAppend(fmter, b, iface) -} - -//------------------------------------------------------------------------------ - -func (d *Dialect) arrayAppender(typ reflect.Type) schema.AppenderFunc { - kind := typ.Kind() - - switch kind { - case reflect.Ptr: - if fn := d.arrayAppender(typ.Elem()); fn != nil { - return schema.PtrAppender(fn) - } - case reflect.Slice, reflect.Array: - // ok: - default: - return nil - } - - elemType := typ.Elem() - - if kind == reflect.Slice { - switch elemType { - case stringType: - return appendStringSliceValue - case intType: - return appendIntSliceValue - case int64Type: - return appendInt64SliceValue - case float64Type: - return appendFloat64SliceValue - case timeType: - return appendTimeSliceValue - } - } - - appendElem := d.arrayElemAppender(elemType) - if appendElem == nil { - panic(fmt.Errorf("pgdialect: %s is not supported", typ)) - } - - return func(fmter schema.Formatter, b []byte, v reflect.Value) []byte { - kind := v.Kind() - switch kind { - case reflect.Ptr, reflect.Slice: - if v.IsNil() { - return dialect.AppendNull(b) - } - } - - if kind == reflect.Ptr { - v = v.Elem() - } - - b = append(b, '\'') - - b = append(b, '{') - ln := v.Len() - for i := 0; i < ln; i++ { - elem := v.Index(i) - b = appendElem(fmter, b, elem) - b = append(b, ',') - } - if v.Len() > 0 { - b[len(b)-1] = '}' // Replace trailing comma. - } else { - b = append(b, '}') - } - - b = append(b, '\'') - - return b - } -} - -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) +func appendTime(buf []byte, tm time.Time) []byte { + return tm.UTC().AppendFormat(buf, "2006-01-02 15:04:05.999999-07:00") } -func appendStringSlice(b []byte, ss []string) []byte { - if ss == nil { - return dialect.AppendNull(b) - } - - b = append(b, '\'') - - b = append(b, '{') - for _, s := range ss { - b = arrayAppendString(b, s) - b = append(b, ',') - } - if len(ss) > 0 { - b[len(b)-1] = '}' // Replace trailing comma. - } else { - b = append(b, '}') - } - - b = append(b, '\'') - - return b -} - -func appendIntSliceValue(fmter schema.Formatter, b []byte, v reflect.Value) []byte { - ints := v.Convert(sliceIntType).Interface().([]int) - return appendIntSlice(b, ints) -} - -func appendIntSlice(b []byte, ints []int) []byte { - if ints == nil { - return dialect.AppendNull(b) - } - - b = append(b, '\'') - - b = append(b, '{') - for _, n := range ints { - b = strconv.AppendInt(b, int64(n), 10) - b = append(b, ',') - } - if len(ints) > 0 { - b[len(b)-1] = '}' // Replace trailing comma. - } else { - b = append(b, '}') - } - - b = append(b, '\'') - - return b -} - -func appendInt64SliceValue(fmter schema.Formatter, b []byte, v reflect.Value) []byte { - ints := v.Convert(sliceInt64Type).Interface().([]int64) - return appendInt64Slice(b, ints) -} - -func appendInt64Slice(b []byte, ints []int64) []byte { - if ints == nil { - return dialect.AppendNull(b) - } - - b = append(b, '\'') - - b = append(b, '{') - for _, n := range ints { - b = strconv.AppendInt(b, n, 10) - b = append(b, ',') - } - if len(ints) > 0 { - b[len(b)-1] = '}' // Replace trailing comma. - } else { - b = append(b, '}') - } - - b = append(b, '\'') - - return b -} - -func appendFloat64SliceValue(fmter schema.Formatter, b []byte, v reflect.Value) []byte { - floats := v.Convert(sliceFloat64Type).Interface().([]float64) - return appendFloat64Slice(b, floats) -} - -func appendFloat64Slice(b []byte, floats []float64) []byte { - if floats == nil { - return dialect.AppendNull(b) - } - - b = append(b, '\'') - - b = append(b, '{') - for _, n := range floats { - b = dialect.AppendFloat64(b, n) - b = append(b, ',') - } - if len(floats) > 0 { - b[len(b)-1] = '}' // Replace trailing comma. - } else { - b = append(b, '}') - } - - b = append(b, '\'') - - return b -} - -//------------------------------------------------------------------------------ - -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 { - switch r { - case 0: - // ignore - case '\'': - b = append(b, "''"...) - case '"': - b = append(b, '\\', '"') - case '\\': - b = append(b, '\\', '\\') - default: - if r < utf8.RuneSelf { - b = append(b, byte(r)) - break - } - l := len(b) - if cap(b)-l < utf8.UTFMax { - b = append(b, make([]byte, utf8.UTFMax)...) - } - n := utf8.EncodeRune(b[l:l+utf8.UTFMax], r) - b = b[:l+n] - } - } - b = append(b, '"') - 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)) func (d *Dialect) hstoreAppender(typ reflect.Type) schema.AppenderFunc { diff --git a/vendor/github.com/uptrace/bun/dialect/pgdialect/array.go b/vendor/github.com/uptrace/bun/dialect/pgdialect/array.go index 281cff733..46b55659b 100644 --- a/vendor/github.com/uptrace/bun/dialect/pgdialect/array.go +++ b/vendor/github.com/uptrace/bun/dialect/pgdialect/array.go @@ -2,9 +2,16 @@ package pgdialect import ( "database/sql" + "database/sql/driver" + "encoding/hex" "fmt" "reflect" + "strconv" + "time" + "unicode/utf8" + "github.com/uptrace/bun/dialect" + "github.com/uptrace/bun/internal" "github.com/uptrace/bun/schema" ) @@ -20,7 +27,7 @@ type ArrayValue struct { // // For struct fields you can use array tag: // -// Emails []string `bun:",array"` +// Emails []string `bun:",array"` func Array(vi interface{}) *ArrayValue { v := reflect.ValueOf(vi) if !v.IsValid() { @@ -63,3 +70,576 @@ func (a *ArrayValue) Value() interface{} { } return nil } + +//------------------------------------------------------------------------------ + +func (d *Dialect) arrayAppender(typ reflect.Type) schema.AppenderFunc { + kind := typ.Kind() + + switch kind { + case reflect.Ptr: + if fn := d.arrayAppender(typ.Elem()); fn != nil { + return schema.PtrAppender(fn) + } + case reflect.Slice, reflect.Array: + // continue below + default: + return nil + } + + elemType := typ.Elem() + + if kind == reflect.Slice { + switch elemType { + case stringType: + return appendStringSliceValue + case intType: + return appendIntSliceValue + case int64Type: + return appendInt64SliceValue + case float64Type: + return appendFloat64SliceValue + case timeType: + return appendTimeSliceValue + } + } + + appendElem := d.arrayElemAppender(elemType) + if appendElem == nil { + panic(fmt.Errorf("pgdialect: %s is not supported", typ)) + } + + return func(fmter schema.Formatter, b []byte, v reflect.Value) []byte { + kind := v.Kind() + switch kind { + case reflect.Ptr, reflect.Slice: + if v.IsNil() { + return dialect.AppendNull(b) + } + } + + if kind == reflect.Ptr { + v = v.Elem() + } + + b = append(b, "'{"...) + + ln := v.Len() + for i := 0; i < ln; i++ { + elem := v.Index(i) + if i > 0 { + b = append(b, ',') + } + b = appendElem(fmter, b, elem) + } + + b = append(b, "}'"...) + + return b + } +} + +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 arrayAppend(fmter schema.Formatter, b []byte, v interface{}) []byte { + switch v := v.(type) { + case int64: + return strconv.AppendInt(b, v, 10) + case float64: + return dialect.AppendFloat64(b, v) + case bool: + return dialect.AppendBool(b, v) + case []byte: + return arrayAppendBytes(b, v) + case string: + return arrayAppendString(b, v) + case time.Time: + return fmter.Dialect().AppendTime(b, v) + default: + err := fmt.Errorf("pgdialect: can't append %T", v) + return dialect.AppendError(b, err) + } +} + +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 { + return dialect.AppendError(b, err) + } + return arrayAppend(fmter, b, iface) +} + +func appendStringSliceValue(fmter schema.Formatter, b []byte, v reflect.Value) []byte { + ss := v.Convert(sliceStringType).Interface().([]string) + return appendStringSlice(b, ss) +} + +func appendStringSlice(b []byte, ss []string) []byte { + if ss == nil { + return dialect.AppendNull(b) + } + + b = append(b, '\'') + + b = append(b, '{') + for _, s := range ss { + b = arrayAppendString(b, s) + b = append(b, ',') + } + if len(ss) > 0 { + b[len(b)-1] = '}' // Replace trailing comma. + } else { + b = append(b, '}') + } + + b = append(b, '\'') + + return b +} + +func appendIntSliceValue(fmter schema.Formatter, b []byte, v reflect.Value) []byte { + ints := v.Convert(sliceIntType).Interface().([]int) + return appendIntSlice(b, ints) +} + +func appendIntSlice(b []byte, ints []int) []byte { + if ints == nil { + return dialect.AppendNull(b) + } + + b = append(b, '\'') + + b = append(b, '{') + for _, n := range ints { + b = strconv.AppendInt(b, int64(n), 10) + b = append(b, ',') + } + if len(ints) > 0 { + b[len(b)-1] = '}' // Replace trailing comma. + } else { + b = append(b, '}') + } + + b = append(b, '\'') + + return b +} + +func appendInt64SliceValue(fmter schema.Formatter, b []byte, v reflect.Value) []byte { + ints := v.Convert(sliceInt64Type).Interface().([]int64) + return appendInt64Slice(b, ints) +} + +func appendInt64Slice(b []byte, ints []int64) []byte { + if ints == nil { + return dialect.AppendNull(b) + } + + b = append(b, '\'') + + b = append(b, '{') + for _, n := range ints { + b = strconv.AppendInt(b, n, 10) + b = append(b, ',') + } + if len(ints) > 0 { + b[len(b)-1] = '}' // Replace trailing comma. + } else { + b = append(b, '}') + } + + b = append(b, '\'') + + return b +} + +func appendFloat64SliceValue(fmter schema.Formatter, b []byte, v reflect.Value) []byte { + floats := v.Convert(sliceFloat64Type).Interface().([]float64) + return appendFloat64Slice(b, floats) +} + +func appendFloat64Slice(b []byte, floats []float64) []byte { + if floats == nil { + return dialect.AppendNull(b) + } + + b = append(b, '\'') + + b = append(b, '{') + for _, n := range floats { + b = dialect.AppendFloat64(b, n) + b = append(b, ',') + } + if len(floats) > 0 { + b[len(b)-1] = '}' // Replace trailing comma. + } else { + b = append(b, '}') + } + + b = append(b, '\'') + + 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 = appendTime(b, t) + 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 +} + +//------------------------------------------------------------------------------ + +func arrayScanner(typ reflect.Type) schema.ScannerFunc { + kind := typ.Kind() + + switch kind { + case reflect.Ptr: + if fn := arrayScanner(typ.Elem()); fn != nil { + return schema.PtrScanner(fn) + } + case reflect.Slice, reflect.Array: + // ok: + default: + return nil + } + + elemType := typ.Elem() + + if kind == reflect.Slice { + switch elemType { + case stringType: + return scanStringSliceValue + case intType: + return scanIntSliceValue + case int64Type: + return scanInt64SliceValue + case float64Type: + return scanFloat64SliceValue + } + } + + scanElem := schema.Scanner(elemType) + return func(dest reflect.Value, src interface{}) error { + dest = reflect.Indirect(dest) + if !dest.CanSet() { + return fmt.Errorf("bun: Scan(non-settable %s)", dest.Type()) + } + + kind := dest.Kind() + + if src == nil { + if kind != reflect.Slice || !dest.IsNil() { + dest.Set(reflect.Zero(dest.Type())) + } + return nil + } + + if kind == reflect.Slice { + if dest.IsNil() { + dest.Set(reflect.MakeSlice(dest.Type(), 0, 0)) + } else if dest.Len() > 0 { + dest.Set(dest.Slice(0, 0)) + } + } + + b, err := toBytes(src) + if err != nil { + return err + } + + p := newArrayParser(b) + nextValue := internal.MakeSliceNextElemFunc(dest) + for p.Next() { + elem := p.Elem() + elemValue := nextValue() + if err := scanElem(elemValue, elem); err != nil { + return fmt.Errorf("scanElem failed: %w", err) + } + } + return p.Err() + } +} + +func scanStringSliceValue(dest reflect.Value, src interface{}) error { + dest = reflect.Indirect(dest) + if !dest.CanSet() { + return fmt.Errorf("bun: Scan(non-settable %s)", dest.Type()) + } + + slice, err := decodeStringSlice(src) + if err != nil { + return err + } + + dest.Set(reflect.ValueOf(slice)) + return nil +} + +func decodeStringSlice(src interface{}) ([]string, error) { + if src == nil { + return nil, nil + } + + b, err := toBytes(src) + if err != nil { + return nil, err + } + + slice := make([]string, 0) + + p := newArrayParser(b) + for p.Next() { + elem := p.Elem() + slice = append(slice, string(elem)) + } + if err := p.Err(); err != nil { + return nil, err + } + return slice, nil +} + +func scanIntSliceValue(dest reflect.Value, src interface{}) error { + dest = reflect.Indirect(dest) + if !dest.CanSet() { + return fmt.Errorf("bun: Scan(non-settable %s)", dest.Type()) + } + + slice, err := decodeIntSlice(src) + if err != nil { + return err + } + + dest.Set(reflect.ValueOf(slice)) + return nil +} + +func decodeIntSlice(src interface{}) ([]int, error) { + if src == nil { + return nil, nil + } + + b, err := toBytes(src) + if err != nil { + return nil, err + } + + slice := make([]int, 0) + + p := newArrayParser(b) + for p.Next() { + elem := p.Elem() + + if elem == nil { + slice = append(slice, 0) + continue + } + + n, err := strconv.Atoi(bytesToString(elem)) + if err != nil { + return nil, err + } + + slice = append(slice, n) + } + if err := p.Err(); err != nil { + return nil, err + } + return slice, nil +} + +func scanInt64SliceValue(dest reflect.Value, src interface{}) error { + dest = reflect.Indirect(dest) + if !dest.CanSet() { + return fmt.Errorf("bun: Scan(non-settable %s)", dest.Type()) + } + + slice, err := decodeInt64Slice(src) + if err != nil { + return err + } + + dest.Set(reflect.ValueOf(slice)) + return nil +} + +func decodeInt64Slice(src interface{}) ([]int64, error) { + if src == nil { + return nil, nil + } + + b, err := toBytes(src) + if err != nil { + return nil, err + } + + slice := make([]int64, 0) + + p := newArrayParser(b) + for p.Next() { + elem := p.Elem() + + if elem == nil { + slice = append(slice, 0) + continue + } + + n, err := strconv.ParseInt(bytesToString(elem), 10, 64) + if err != nil { + return nil, err + } + + slice = append(slice, n) + } + if err := p.Err(); err != nil { + return nil, err + } + return slice, nil +} + +func scanFloat64SliceValue(dest reflect.Value, src interface{}) error { + dest = reflect.Indirect(dest) + if !dest.CanSet() { + return fmt.Errorf("bun: Scan(non-settable %s)", dest.Type()) + } + + slice, err := scanFloat64Slice(src) + if err != nil { + return err + } + + dest.Set(reflect.ValueOf(slice)) + return nil +} + +func scanFloat64Slice(src interface{}) ([]float64, error) { + if src == -1 { + return nil, nil + } + + b, err := toBytes(src) + if err != nil { + return nil, err + } + + slice := make([]float64, 0) + + p := newArrayParser(b) + for p.Next() { + elem := p.Elem() + + if elem == nil { + slice = append(slice, 0) + continue + } + + n, err := strconv.ParseFloat(bytesToString(elem), 64) + if err != nil { + return nil, err + } + + slice = append(slice, n) + } + if err := p.Err(); err != nil { + return nil, err + } + return slice, nil +} + +func toBytes(src interface{}) ([]byte, error) { + switch src := src.(type) { + case string: + return stringToBytes(src), nil + case []byte: + return src, nil + default: + return nil, fmt.Errorf("bun: got %T, wanted []byte or string", src) + } +} + +//------------------------------------------------------------------------------ + +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 { + switch r { + case 0: + // ignore + case '\'': + b = append(b, "''"...) + case '"': + b = append(b, '\\', '"') + case '\\': + b = append(b, '\\', '\\') + default: + if r < utf8.RuneSelf { + b = append(b, byte(r)) + break + } + l := len(b) + if cap(b)-l < utf8.UTFMax { + b = append(b, make([]byte, utf8.UTFMax)...) + } + n := utf8.EncodeRune(b[l:l+utf8.UTFMax], r) + b = b[:l+n] + } + } + b = append(b, '"') + return b +} diff --git a/vendor/github.com/uptrace/bun/dialect/pgdialect/array_parser.go b/vendor/github.com/uptrace/bun/dialect/pgdialect/array_parser.go index a8358337e..462f8d91d 100644 --- a/vendor/github.com/uptrace/bun/dialect/pgdialect/array_parser.go +++ b/vendor/github.com/uptrace/bun/dialect/pgdialect/array_parser.go @@ -2,132 +2,92 @@ package pgdialect import ( "bytes" - "encoding/hex" "fmt" "io" ) type arrayParser struct { - *streamParser - err error + p pgparser + + elem []byte + err error } func newArrayParser(b []byte) *arrayParser { - p := &arrayParser{ - streamParser: newStreamParser(b, 1), - } + p := new(arrayParser) + if len(b) < 2 || b[0] != '{' || b[len(b)-1] != '}' { - p.err = fmt.Errorf("bun: can't parse array: %q", b) + p.err = fmt.Errorf("pgdialect: can't parse array: %q", b) + return p } + + p.p.Reset(b[1 : len(b)-1]) return p } -func (p *arrayParser) NextElem() ([]byte, error) { +func (p *arrayParser) Next() bool { if p.err != nil { - return nil, p.err + return false } + p.err = p.readNext() + return p.err == nil +} + +func (p *arrayParser) Err() error { + if p.err != io.EOF { + return p.err + } + return nil +} - c, err := p.readByte() - if err != nil { - return nil, err +func (p *arrayParser) Elem() []byte { + return p.elem +} + +func (p *arrayParser) readNext() error { + ch := p.p.Read() + if ch == 0 { + return io.EOF } - switch c { + switch ch { case '}': - return nil, io.EOF + return io.EOF case '"': - b, err := p.readSubstring() + b, err := p.p.ReadSubstring(ch) if err != nil { - return nil, err - } - - if p.peek() == ',' { - p.skipNext() + return err } - return b, nil - default: - b := p.readSimple() - if bytes.Equal(b, []byte("NULL")) { - b = nil + if p.p.Peek() == ',' { + p.p.Advance() } - if p.peek() == ',' { - p.skipNext() + p.elem = b + return nil + case '[', '(': + rng, err := p.p.ReadRange(ch) + if err != nil { + return err } - return b, nil - } -} - -func (p *arrayParser) readSimple() []byte { - p.unreadByte() - - if i := bytes.IndexByte(p.b[p.i:], ','); i >= 0 { - b := p.b[p.i : p.i+i] - p.i += i - return b - } - - b := p.b[p.i : len(p.b)-1] - p.i = len(p.b) - 1 - return b -} - -func (p *arrayParser) readSubstring() ([]byte, error) { - c, err := p.readByte() - if err != nil { - return nil, err - } - - p.buf = p.buf[:0] - for { - if c == '"' { - break + if p.p.Peek() == ',' { + p.p.Advance() } - next, err := p.readByte() - if err != nil { - return nil, err + p.elem = rng + return nil + default: + lit := p.p.ReadLiteral(ch) + if bytes.Equal(lit, []byte("NULL")) { + lit = nil } - if c == '\\' { - switch next { - case '\\', '"': - p.buf = append(p.buf, next) - - c, err = p.readByte() - if err != nil { - return nil, err - } - default: - p.buf = append(p.buf, '\\') - c = next - } - continue + if p.p.Peek() == ',' { + p.p.Advance() } - 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 + p.elem = lit + return nil } - - return p.buf, nil } diff --git a/vendor/github.com/uptrace/bun/dialect/pgdialect/array_scan.go b/vendor/github.com/uptrace/bun/dialect/pgdialect/array_scan.go index a8ff29715..6b8abda3d 100644 --- a/vendor/github.com/uptrace/bun/dialect/pgdialect/array_scan.go +++ b/vendor/github.com/uptrace/bun/dialect/pgdialect/array_scan.go @@ -1,302 +1 @@ package pgdialect - -import ( - "fmt" - "io" - "reflect" - "strconv" - - "github.com/uptrace/bun/internal" - "github.com/uptrace/bun/schema" -) - -func arrayScanner(typ reflect.Type) schema.ScannerFunc { - kind := typ.Kind() - - switch kind { - case reflect.Ptr: - if fn := arrayScanner(typ.Elem()); fn != nil { - return schema.PtrScanner(fn) - } - case reflect.Slice, reflect.Array: - // ok: - default: - return nil - } - - elemType := typ.Elem() - - if kind == reflect.Slice { - switch elemType { - case stringType: - return scanStringSliceValue - case intType: - return scanIntSliceValue - case int64Type: - return scanInt64SliceValue - case float64Type: - return scanFloat64SliceValue - } - } - - scanElem := schema.Scanner(elemType) - return func(dest reflect.Value, src interface{}) error { - dest = reflect.Indirect(dest) - if !dest.CanSet() { - return fmt.Errorf("bun: Scan(non-settable %s)", dest.Type()) - } - - kind := dest.Kind() - - if src == nil { - if kind != reflect.Slice || !dest.IsNil() { - dest.Set(reflect.Zero(dest.Type())) - } - return nil - } - - if kind == reflect.Slice { - if dest.IsNil() { - dest.Set(reflect.MakeSlice(dest.Type(), 0, 0)) - } else if dest.Len() > 0 { - dest.Set(dest.Slice(0, 0)) - } - } - - b, err := toBytes(src) - if err != nil { - return err - } - - p := newArrayParser(b) - nextValue := internal.MakeSliceNextElemFunc(dest) - for { - elem, err := p.NextElem() - if err != nil { - if err == io.EOF { - break - } - return err - } - - elemValue := nextValue() - if err := scanElem(elemValue, elem); err != nil { - return err - } - } - - return nil - } -} - -func scanStringSliceValue(dest reflect.Value, src interface{}) error { - dest = reflect.Indirect(dest) - if !dest.CanSet() { - return fmt.Errorf("bun: Scan(non-settable %s)", dest.Type()) - } - - slice, err := decodeStringSlice(src) - if err != nil { - return err - } - - dest.Set(reflect.ValueOf(slice)) - return nil -} - -func decodeStringSlice(src interface{}) ([]string, error) { - if src == nil { - return nil, nil - } - - b, err := toBytes(src) - if err != nil { - return nil, err - } - - slice := make([]string, 0) - - p := newArrayParser(b) - for { - elem, err := p.NextElem() - if err != nil { - if err == io.EOF { - break - } - return nil, err - } - slice = append(slice, string(elem)) - } - - return slice, nil -} - -func scanIntSliceValue(dest reflect.Value, src interface{}) error { - dest = reflect.Indirect(dest) - if !dest.CanSet() { - return fmt.Errorf("bun: Scan(non-settable %s)", dest.Type()) - } - - slice, err := decodeIntSlice(src) - if err != nil { - return err - } - - dest.Set(reflect.ValueOf(slice)) - return nil -} - -func decodeIntSlice(src interface{}) ([]int, error) { - if src == nil { - return nil, nil - } - - b, err := toBytes(src) - if err != nil { - return nil, err - } - - slice := make([]int, 0) - - p := newArrayParser(b) - for { - elem, err := p.NextElem() - if err != nil { - if err == io.EOF { - break - } - return nil, err - } - - if elem == nil { - slice = append(slice, 0) - continue - } - - n, err := strconv.Atoi(bytesToString(elem)) - if err != nil { - return nil, err - } - - slice = append(slice, n) - } - - return slice, nil -} - -func scanInt64SliceValue(dest reflect.Value, src interface{}) error { - dest = reflect.Indirect(dest) - if !dest.CanSet() { - return fmt.Errorf("bun: Scan(non-settable %s)", dest.Type()) - } - - slice, err := decodeInt64Slice(src) - if err != nil { - return err - } - - dest.Set(reflect.ValueOf(slice)) - return nil -} - -func decodeInt64Slice(src interface{}) ([]int64, error) { - if src == nil { - return nil, nil - } - - b, err := toBytes(src) - if err != nil { - return nil, err - } - - slice := make([]int64, 0) - - p := newArrayParser(b) - for { - elem, err := p.NextElem() - if err != nil { - if err == io.EOF { - break - } - return nil, err - } - - if elem == nil { - slice = append(slice, 0) - continue - } - - n, err := strconv.ParseInt(bytesToString(elem), 10, 64) - if err != nil { - return nil, err - } - - slice = append(slice, n) - } - - return slice, nil -} - -func scanFloat64SliceValue(dest reflect.Value, src interface{}) error { - dest = reflect.Indirect(dest) - if !dest.CanSet() { - return fmt.Errorf("bun: Scan(non-settable %s)", dest.Type()) - } - - slice, err := scanFloat64Slice(src) - if err != nil { - return err - } - - dest.Set(reflect.ValueOf(slice)) - return nil -} - -func scanFloat64Slice(src interface{}) ([]float64, error) { - if src == -1 { - return nil, nil - } - - b, err := toBytes(src) - if err != nil { - return nil, err - } - - slice := make([]float64, 0) - - p := newArrayParser(b) - for { - elem, err := p.NextElem() - if err != nil { - if err == io.EOF { - break - } - return nil, err - } - - if elem == nil { - slice = append(slice, 0) - continue - } - - n, err := strconv.ParseFloat(bytesToString(elem), 64) - if err != nil { - return nil, err - } - - slice = append(slice, n) - } - - return slice, nil -} - -func toBytes(src interface{}) ([]byte, error) { - switch src := src.(type) { - case string: - return stringToBytes(src), nil - case []byte: - return src, nil - default: - return nil, fmt.Errorf("bun: got %T, wanted []byte or string", src) - } -} diff --git a/vendor/github.com/uptrace/bun/dialect/pgdialect/dialect.go b/vendor/github.com/uptrace/bun/dialect/pgdialect/dialect.go index f100e682c..358971f61 100644 --- a/vendor/github.com/uptrace/bun/dialect/pgdialect/dialect.go +++ b/vendor/github.com/uptrace/bun/dialect/pgdialect/dialect.go @@ -89,9 +89,17 @@ func (d *Dialect) onField(field *schema.Field) { if field.Tag.HasOption("array") || strings.HasSuffix(field.UserSQLType, "[]") { field.Append = d.arrayAppender(field.StructField.Type) field.Scan = arrayScanner(field.StructField.Type) + return } - if field.DiscoveredSQLType == sqltype.HSTORE { + if field.Tag.HasOption("multirange") { + field.Append = d.arrayAppender(field.StructField.Type) + field.Scan = arrayScanner(field.StructField.Type) + return + } + + switch field.DiscoveredSQLType { + case sqltype.HSTORE: field.Append = d.hstoreAppender(field.StructField.Type) field.Scan = hstoreScanner(field.StructField.Type) } diff --git a/vendor/github.com/uptrace/bun/dialect/pgdialect/hstore_parser.go b/vendor/github.com/uptrace/bun/dialect/pgdialect/hstore_parser.go index 7a18b50b1..fec401786 100644 --- a/vendor/github.com/uptrace/bun/dialect/pgdialect/hstore_parser.go +++ b/vendor/github.com/uptrace/bun/dialect/pgdialect/hstore_parser.go @@ -3,140 +3,98 @@ package pgdialect import ( "bytes" "fmt" + "io" ) type hstoreParser struct { - *streamParser - err error + p pgparser + + key string + value string + err error } func newHStoreParser(b []byte) *hstoreParser { - p := &hstoreParser{ - streamParser: newStreamParser(b, 0), - } - if len(b) < 6 || b[0] != '"' { - p.err = fmt.Errorf("bun: can't parse hstore: %q", b) + p := new(hstoreParser) + if len(b) != 0 && (len(b) < 6 || b[0] != '"') { + p.err = fmt.Errorf("pgdialect: can't parse hstore: %q", b) + return p } + p.p.Reset(b) return p } -func (p *hstoreParser) NextKey() (string, error) { +func (p *hstoreParser) Next() bool { if p.err != nil { - return "", p.err + return false } + p.err = p.readNext() + return p.err == nil +} - err := p.skipByte('"') - if err != nil { - return "", err +func (p *hstoreParser) Err() error { + if p.err != io.EOF { + return p.err } + return nil +} - key, err := p.readSubstring() - if err != nil { - return "", err - } +func (p *hstoreParser) Key() string { + return p.key +} - const separator = "=>" +func (p *hstoreParser) Value() string { + return p.value +} - for i := range separator { - err = p.skipByte(separator[i]) - if err != nil { - return "", err - } +func (p *hstoreParser) readNext() error { + if !p.p.Valid() { + return io.EOF } - return string(key), nil -} + if err := p.p.Skip('"'); err != nil { + return err + } -func (p *hstoreParser) NextValue() (string, error) { - if p.err != nil { - return "", p.err + key, err := p.p.ReadUnescapedSubstring('"') + if err != nil { + return err + } + p.key = string(key) + + if err := p.p.SkipPrefix([]byte("=>")); err != nil { + return err } - c, err := p.readByte() + ch, err := p.p.ReadByte() if err != nil { - return "", err + return err } - switch c { + switch ch { case '"': - value, err := p.readSubstring() + value, err := p.p.ReadUnescapedSubstring(ch) if err != nil { - return "", err - } - - if p.peek() == ',' { - p.skipNext() - } - - if p.peek() == ' ' { - p.skipNext() + return err } - - return string(value), nil + p.skipComma() + p.value = string(value) + return nil default: - value := p.readSimple() + value := p.p.ReadLiteral(ch) if bytes.Equal(value, []byte("NULL")) { - value = nil - } - - if p.peek() == ',' { - p.skipNext() + p.value = "" } - - return string(value), nil - } -} - -func (p *hstoreParser) readSimple() []byte { - p.unreadByte() - - if i := bytes.IndexByte(p.b[p.i:], ','); i >= 0 { - b := p.b[p.i : p.i+i] - p.i += i - return b + p.skipComma() + return nil } - - b := p.b[p.i:len(p.b)] - p.i = len(p.b) - return b } -func (p *hstoreParser) readSubstring() ([]byte, error) { - c, err := p.readByte() - if err != nil { - return nil, err +func (p *hstoreParser) skipComma() { + if p.p.Peek() == ',' { + p.p.Advance() } - - p.buf = p.buf[:0] - for { - if c == '"' { - break - } - - next, err := p.readByte() - if err != nil { - return nil, err - } - - if c == '\\' { - switch next { - case '\\', '"': - p.buf = append(p.buf, next) - - c, err = p.readByte() - if err != nil { - return nil, err - } - default: - p.buf = append(p.buf, '\\') - c = next - } - continue - } - - p.buf = append(p.buf, c) - c = next + if p.p.Peek() == ' ' { + p.p.Advance() } - - return p.buf, nil } diff --git a/vendor/github.com/uptrace/bun/dialect/pgdialect/hstore_scan.go b/vendor/github.com/uptrace/bun/dialect/pgdialect/hstore_scan.go index b10b06b8d..62ab89a3a 100644 --- a/vendor/github.com/uptrace/bun/dialect/pgdialect/hstore_scan.go +++ b/vendor/github.com/uptrace/bun/dialect/pgdialect/hstore_scan.go @@ -2,7 +2,6 @@ package pgdialect import ( "fmt" - "io" "reflect" "github.com/uptrace/bun/schema" @@ -58,25 +57,11 @@ func decodeMapStringString(src interface{}) (map[string]string, error) { m := make(map[string]string) p := newHStoreParser(b) - for { - key, err := p.NextKey() - if err != nil { - if err == io.EOF { - break - } - return nil, err - } - - value, err := p.NextValue() - if err != nil { - if err == io.EOF { - break - } - return nil, err - } - - m[key] = value + for p.Next() { + m[p.Key()] = p.Value() + } + if err := p.Err(); err != nil { + return nil, err } - return m, nil } diff --git a/vendor/github.com/uptrace/bun/dialect/pgdialect/range.go b/vendor/github.com/uptrace/bun/dialect/pgdialect/range.go new file mode 100644 index 000000000..b942a068e --- /dev/null +++ b/vendor/github.com/uptrace/bun/dialect/pgdialect/range.go @@ -0,0 +1,240 @@ +package pgdialect + +import ( + "bytes" + "database/sql" + "encoding/hex" + "fmt" + "io" + "time" + + "github.com/uptrace/bun/internal" + "github.com/uptrace/bun/internal/parser" + "github.com/uptrace/bun/schema" +) + +type MultiRange[T any] []Range[T] + +type Range[T any] struct { + Lower, Upper T + LowerBound, UpperBound RangeBound +} + +type RangeBound byte + +const ( + RangeBoundInclusiveLeft RangeBound = '[' + RangeBoundInclusiveRight RangeBound = ']' + RangeBoundExclusiveLeft RangeBound = '(' + RangeBoundExclusiveRight RangeBound = ')' +) + +func NewRange[T any](lower, upper T) Range[T] { + return Range[T]{ + Lower: lower, + Upper: upper, + LowerBound: RangeBoundInclusiveLeft, + UpperBound: RangeBoundExclusiveRight, + } +} + +var _ sql.Scanner = (*Range[any])(nil) + +func (r *Range[T]) Scan(anySrc any) (err error) { + src := anySrc.([]byte) + + if len(src) == 0 { + return io.ErrUnexpectedEOF + } + r.LowerBound = RangeBound(src[0]) + src = src[1:] + + src, err = scanElem(&r.Lower, src) + if err != nil { + return err + } + + if len(src) == 0 { + return io.ErrUnexpectedEOF + } + if ch := src[0]; ch != ',' { + return fmt.Errorf("got %q, wanted %q", ch, ',') + } + src = src[1:] + + src, err = scanElem(&r.Upper, src) + if err != nil { + return err + } + + if len(src) == 0 { + return io.ErrUnexpectedEOF + } + r.UpperBound = RangeBound(src[0]) + src = src[1:] + + if len(src) > 0 { + return fmt.Errorf("unread data: %q", src) + } + return nil +} + +var _ schema.QueryAppender = (*Range[any])(nil) + +func (r *Range[T]) AppendQuery(fmt schema.Formatter, buf []byte) ([]byte, error) { + buf = append(buf, byte(r.LowerBound)) + buf = appendElem(buf, r.Lower) + buf = append(buf, ',') + buf = appendElem(buf, r.Upper) + buf = append(buf, byte(r.UpperBound)) + return buf, nil +} + +func appendElem(buf []byte, val any) []byte { + switch val := val.(type) { + case time.Time: + buf = append(buf, '"') + buf = appendTime(buf, val) + buf = append(buf, '"') + return buf + default: + panic(fmt.Errorf("unsupported range type: %T", val)) + } +} + +func scanElem(ptr any, src []byte) ([]byte, error) { + switch ptr := ptr.(type) { + case *time.Time: + src, str, err := readStringLiteral(src) + if err != nil { + return nil, err + } + + tm, err := internal.ParseTime(internal.String(str)) + if err != nil { + return nil, err + } + *ptr = tm + + return src, nil + default: + panic(fmt.Errorf("unsupported range type: %T", ptr)) + } +} + +func readStringLiteral(src []byte) ([]byte, []byte, error) { + p := newParser(src) + + if err := p.Skip('"'); err != nil { + return nil, nil, err + } + + str, err := p.ReadSubstring('"') + if err != nil { + return nil, nil, err + } + + src = p.Remaining() + return src, str, nil +} + +//------------------------------------------------------------------------------ + +type pgparser struct { + parser.Parser + buf []byte +} + +func newParser(b []byte) *pgparser { + p := new(pgparser) + p.Reset(b) + return p +} + +func (p *pgparser) ReadLiteral(ch byte) []byte { + p.Unread() + lit, _ := p.ReadSep(',') + return lit +} + +func (p *pgparser) ReadUnescapedSubstring(ch byte) ([]byte, error) { + return p.readSubstring(ch, false) +} + +func (p *pgparser) ReadSubstring(ch byte) ([]byte, error) { + return p.readSubstring(ch, true) +} + +func (p *pgparser) readSubstring(ch byte, escaped bool) ([]byte, error) { + ch, err := p.ReadByte() + if err != nil { + return nil, err + } + + p.buf = p.buf[:0] + for { + if ch == '"' { + break + } + + next, err := p.ReadByte() + if err != nil { + return nil, err + } + + if ch == '\\' { + switch next { + case '\\', '"': + p.buf = append(p.buf, next) + + ch, err = p.ReadByte() + if err != nil { + return nil, err + } + default: + p.buf = append(p.buf, '\\') + ch = next + } + continue + } + + if escaped && ch == '\'' && next == '\'' { + p.buf = append(p.buf, next) + ch, err = p.ReadByte() + if err != nil { + return nil, err + } + continue + } + + p.buf = append(p.buf, ch) + ch = 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 +} + +func (p *pgparser) ReadRange(ch byte) ([]byte, error) { + p.buf = p.buf[:0] + p.buf = append(p.buf, ch) + + for p.Valid() { + ch = p.Read() + p.buf = append(p.buf, ch) + if ch == ']' || ch == ')' { + break + } + } + + return p.buf, nil +} diff --git a/vendor/github.com/uptrace/bun/dialect/pgdialect/sqltype.go b/vendor/github.com/uptrace/bun/dialect/pgdialect/sqltype.go index dadea5c1c..fad84209d 100644 --- a/vendor/github.com/uptrace/bun/dialect/pgdialect/sqltype.go +++ b/vendor/github.com/uptrace/bun/dialect/pgdialect/sqltype.go @@ -1,6 +1,7 @@ package pgdialect import ( + "database/sql" "encoding/json" "net" "reflect" @@ -27,14 +28,6 @@ const ( pgTypeSerial = "SERIAL" // 4 byte autoincrementing integer pgTypeBigSerial = "BIGSERIAL" // 8 byte autoincrementing integer - // Character Types - pgTypeChar = "CHAR" // fixed length string (blank padded) - pgTypeText = "TEXT" // variable length string without limit - - // JSON Types - pgTypeJSON = "JSON" // text representation of json data - pgTypeJSONB = "JSONB" // binary representation of json data - // Binary Data Types pgTypeBytea = "BYTEA" // binary string ) @@ -43,6 +36,7 @@ var ( ipType = reflect.TypeOf((*net.IP)(nil)).Elem() ipNetType = reflect.TypeOf((*net.IPNet)(nil)).Elem() jsonRawMessageType = reflect.TypeOf((*json.RawMessage)(nil)).Elem() + nullStringType = reflect.TypeOf((*sql.NullString)(nil)).Elem() ) func (d *Dialect) DefaultVarcharLen() int { @@ -78,12 +72,14 @@ func fieldSQLType(field *schema.Field) string { func sqlType(typ reflect.Type) string { switch typ { + case nullStringType: // typ.Kind() == reflect.Struct, test for exact match + return sqltype.VarChar case ipType: return pgTypeInet case ipNetType: return pgTypeCidr case jsonRawMessageType: - return pgTypeJSONB + return sqltype.JSONB } sqlType := schema.DiscoverSQLType(typ) @@ -93,16 +89,16 @@ func sqlType(typ reflect.Type) string { } switch typ.Kind() { - case reflect.Map, reflect.Struct: + case reflect.Map, reflect.Struct: // except typ == nullStringType, see above if sqlType == sqltype.VarChar { - return pgTypeJSONB + return sqltype.JSONB } return sqlType case reflect.Array, reflect.Slice: if typ.Elem().Kind() == reflect.Uint8 { return pgTypeBytea } - return pgTypeJSONB + return sqltype.JSONB } return sqlType diff --git a/vendor/github.com/uptrace/bun/dialect/pgdialect/stream_parser.go b/vendor/github.com/uptrace/bun/dialect/pgdialect/stream_parser.go deleted file mode 100644 index 7b9a15f62..000000000 --- a/vendor/github.com/uptrace/bun/dialect/pgdialect/stream_parser.go +++ /dev/null @@ -1,60 +0,0 @@ -package pgdialect - -import ( - "fmt" - "io" -) - -type streamParser struct { - b []byte - i int - - buf []byte -} - -func newStreamParser(b []byte, start int) *streamParser { - return &streamParser{ - b: b, - i: start, - } -} - -func (p *streamParser) valid() bool { - return p.i < len(p.b) -} - -func (p *streamParser) skipByte(skip byte) error { - c, err := p.readByte() - if err != nil { - return err - } - if c == skip { - return nil - } - p.unreadByte() - return fmt.Errorf("got %q, wanted %q", c, skip) -} - -func (p *streamParser) readByte() (byte, error) { - if p.valid() { - c := p.b[p.i] - p.i++ - return c, nil - } - return 0, io.EOF -} - -func (p *streamParser) unreadByte() { - p.i-- -} - -func (p *streamParser) peek() byte { - if p.valid() { - return p.b[p.i] - } - return 0 -} - -func (p *streamParser) skipNext() { - p.i++ -} diff --git a/vendor/github.com/uptrace/bun/dialect/pgdialect/version.go b/vendor/github.com/uptrace/bun/dialect/pgdialect/version.go index b5e5e3cb0..c06043647 100644 --- a/vendor/github.com/uptrace/bun/dialect/pgdialect/version.go +++ b/vendor/github.com/uptrace/bun/dialect/pgdialect/version.go @@ -2,5 +2,5 @@ package pgdialect // Version is the current release version. func Version() string { - return "1.2.1" + return "1.2.5" } diff --git a/vendor/github.com/uptrace/bun/dialect/sqlitedialect/version.go b/vendor/github.com/uptrace/bun/dialect/sqlitedialect/version.go index 06e5bb1a4..e3cceaa77 100644 --- a/vendor/github.com/uptrace/bun/dialect/sqlitedialect/version.go +++ b/vendor/github.com/uptrace/bun/dialect/sqlitedialect/version.go @@ -2,5 +2,5 @@ package sqlitedialect // Version is the current release version. func Version() string { - return "1.2.1" + return "1.2.5" } |