Vendor packages update
This commit is contained in:
81
vendor/github.com/uptrace/bun/schema/append.go
generated
vendored
Normal file
81
vendor/github.com/uptrace/bun/schema/append.go
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/uptrace/bun/dialect"
|
||||
)
|
||||
|
||||
func In(slice any) 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(gen QueryGen, b []byte) (_ []byte, err error) {
|
||||
if in.err != nil {
|
||||
return nil, in.err
|
||||
}
|
||||
return appendIn(gen, b, in.slice), nil
|
||||
}
|
||||
|
||||
func appendIn(gen QueryGen, b []byte, slice reflect.Value) []byte {
|
||||
sliceLen := slice.Len()
|
||||
|
||||
if sliceLen == 0 {
|
||||
return dialect.AppendNull(b)
|
||||
}
|
||||
|
||||
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(gen, b, elem)
|
||||
b = append(b, ')')
|
||||
} else {
|
||||
b = gen.AppendValue(b, elem)
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func NullZero(value any) QueryAppender {
|
||||
return nullZero{
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
|
||||
type nullZero struct {
|
||||
value any
|
||||
}
|
||||
|
||||
func (nz nullZero) AppendQuery(gen QueryGen, b []byte) (_ []byte, err error) {
|
||||
if isZero(nz.value) {
|
||||
return dialect.AppendNull(b), nil
|
||||
}
|
||||
return gen.AppendValue(b, reflect.ValueOf(nz.value)), nil
|
||||
}
|
||||
316
vendor/github.com/uptrace/bun/schema/append_value.go
generated
vendored
Normal file
316
vendor/github.com/uptrace/bun/schema/append_value.go
generated
vendored
Normal file
@@ -0,0 +1,316 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/puzpuzpuz/xsync/v3"
|
||||
"github.com/uptrace/bun/dialect"
|
||||
"github.com/uptrace/bun/dialect/sqltype"
|
||||
"github.com/uptrace/bun/extra/bunjson"
|
||||
"github.com/uptrace/bun/internal"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
)
|
||||
|
||||
type (
|
||||
AppenderFunc func(gen QueryGen, b []byte, v reflect.Value) []byte
|
||||
CustomAppender func(typ reflect.Type) AppenderFunc
|
||||
)
|
||||
|
||||
var appenders = []AppenderFunc{
|
||||
reflect.Bool: AppendBoolValue,
|
||||
reflect.Int: AppendIntValue,
|
||||
reflect.Int8: AppendIntValue,
|
||||
reflect.Int16: AppendIntValue,
|
||||
reflect.Int32: AppendIntValue,
|
||||
reflect.Int64: AppendIntValue,
|
||||
reflect.Uint: AppendUintValue,
|
||||
reflect.Uint8: AppendUintValue,
|
||||
reflect.Uint16: AppendUintValue,
|
||||
reflect.Uint32: appendUint32Value,
|
||||
reflect.Uint64: appendUint64Value,
|
||||
reflect.Uintptr: nil,
|
||||
reflect.Float32: AppendFloat32Value,
|
||||
reflect.Float64: AppendFloat64Value,
|
||||
reflect.Complex64: nil,
|
||||
reflect.Complex128: nil,
|
||||
reflect.Array: AppendJSONValue,
|
||||
reflect.Chan: nil,
|
||||
reflect.Func: nil,
|
||||
reflect.Interface: nil,
|
||||
reflect.Map: AppendJSONValue,
|
||||
reflect.Ptr: nil,
|
||||
reflect.Slice: AppendJSONValue,
|
||||
reflect.String: AppendStringValue,
|
||||
reflect.Struct: AppendJSONValue,
|
||||
reflect.UnsafePointer: nil,
|
||||
}
|
||||
|
||||
var appenderCache = xsync.NewMapOf[reflect.Type, AppenderFunc]()
|
||||
|
||||
func FieldAppender(dialect Dialect, field *Field) AppenderFunc {
|
||||
if field.Tag.HasOption("msgpack") {
|
||||
return appendMsgpack
|
||||
}
|
||||
|
||||
fieldType := field.StructField.Type
|
||||
|
||||
switch strings.ToUpper(field.UserSQLType) {
|
||||
case sqltype.JSON, sqltype.JSONB:
|
||||
if fieldType.Implements(driverValuerType) {
|
||||
return appendDriverValue
|
||||
}
|
||||
|
||||
if fieldType.Kind() != reflect.Ptr {
|
||||
if reflect.PointerTo(fieldType).Implements(driverValuerType) {
|
||||
return addrAppender(appendDriverValue)
|
||||
}
|
||||
}
|
||||
|
||||
return AppendJSONValue
|
||||
}
|
||||
|
||||
return Appender(dialect, fieldType)
|
||||
}
|
||||
|
||||
func Appender(dialect Dialect, typ reflect.Type) AppenderFunc {
|
||||
if v, ok := appenderCache.Load(typ); ok {
|
||||
return v
|
||||
}
|
||||
|
||||
fn := appender(dialect, typ)
|
||||
|
||||
if v, ok := appenderCache.LoadOrStore(typ, fn); ok {
|
||||
return v
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
func appender(dialect Dialect, typ reflect.Type) AppenderFunc {
|
||||
switch typ {
|
||||
case bytesType:
|
||||
return appendBytesValue
|
||||
case timeType:
|
||||
return appendTimeValue
|
||||
case timePtrType:
|
||||
return PtrAppender(appendTimeValue)
|
||||
case ipNetType:
|
||||
return appendIPNetValue
|
||||
case ipType, netipPrefixType, netipAddrType:
|
||||
return appendStringer
|
||||
case jsonRawMessageType:
|
||||
return appendJSONRawMessageValue
|
||||
}
|
||||
|
||||
kind := typ.Kind()
|
||||
|
||||
if typ.Implements(queryAppenderType) {
|
||||
if kind == reflect.Ptr {
|
||||
return nilAwareAppender(appendQueryAppenderValue)
|
||||
}
|
||||
return appendQueryAppenderValue
|
||||
}
|
||||
if typ.Implements(driverValuerType) {
|
||||
if kind == reflect.Ptr {
|
||||
return nilAwareAppender(appendDriverValue)
|
||||
}
|
||||
return appendDriverValue
|
||||
}
|
||||
|
||||
if kind != reflect.Ptr {
|
||||
ptr := reflect.PointerTo(typ)
|
||||
if ptr.Implements(queryAppenderType) {
|
||||
return addrAppender(appendQueryAppenderValue)
|
||||
}
|
||||
if ptr.Implements(driverValuerType) {
|
||||
return addrAppender(appendDriverValue)
|
||||
}
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case reflect.Interface:
|
||||
return ifaceAppenderFunc
|
||||
case reflect.Ptr:
|
||||
if typ.Implements(jsonMarshalerType) {
|
||||
return nilAwareAppender(AppendJSONValue)
|
||||
}
|
||||
if fn := Appender(dialect, typ.Elem()); fn != nil {
|
||||
return PtrAppender(fn)
|
||||
}
|
||||
case reflect.Slice:
|
||||
if typ.Elem().Kind() == reflect.Uint8 {
|
||||
return appendBytesValue
|
||||
}
|
||||
case reflect.Array:
|
||||
if typ.Elem().Kind() == reflect.Uint8 {
|
||||
return appendArrayBytesValue
|
||||
}
|
||||
}
|
||||
|
||||
return appenders[typ.Kind()]
|
||||
}
|
||||
|
||||
func ifaceAppenderFunc(gen QueryGen, b []byte, v reflect.Value) []byte {
|
||||
if v.IsNil() {
|
||||
return dialect.AppendNull(b)
|
||||
}
|
||||
elem := v.Elem()
|
||||
appender := Appender(gen.Dialect(), elem.Type())
|
||||
return appender(gen, b, elem)
|
||||
}
|
||||
|
||||
func nilAwareAppender(fn AppenderFunc) AppenderFunc {
|
||||
return func(gen QueryGen, b []byte, v reflect.Value) []byte {
|
||||
if v.IsNil() {
|
||||
return dialect.AppendNull(b)
|
||||
}
|
||||
return fn(gen, b, v)
|
||||
}
|
||||
}
|
||||
|
||||
func PtrAppender(fn AppenderFunc) AppenderFunc {
|
||||
return func(gen QueryGen, b []byte, v reflect.Value) []byte {
|
||||
if v.IsNil() {
|
||||
return dialect.AppendNull(b)
|
||||
}
|
||||
return fn(gen, b, v.Elem())
|
||||
}
|
||||
}
|
||||
|
||||
func AppendBoolValue(gen QueryGen, b []byte, v reflect.Value) []byte {
|
||||
return gen.Dialect().AppendBool(b, v.Bool())
|
||||
}
|
||||
|
||||
func AppendIntValue(gen QueryGen, b []byte, v reflect.Value) []byte {
|
||||
return strconv.AppendInt(b, v.Int(), 10)
|
||||
}
|
||||
|
||||
func AppendUintValue(gen QueryGen, b []byte, v reflect.Value) []byte {
|
||||
return strconv.AppendUint(b, v.Uint(), 10)
|
||||
}
|
||||
|
||||
func appendUint32Value(gen QueryGen, b []byte, v reflect.Value) []byte {
|
||||
return gen.Dialect().AppendUint32(b, uint32(v.Uint()))
|
||||
}
|
||||
|
||||
func appendUint64Value(gen QueryGen, b []byte, v reflect.Value) []byte {
|
||||
return gen.Dialect().AppendUint64(b, v.Uint())
|
||||
}
|
||||
|
||||
func AppendFloat32Value(gen QueryGen, b []byte, v reflect.Value) []byte {
|
||||
return dialect.AppendFloat32(b, float32(v.Float()))
|
||||
}
|
||||
|
||||
func AppendFloat64Value(gen QueryGen, b []byte, v reflect.Value) []byte {
|
||||
return dialect.AppendFloat64(b, float64(v.Float()))
|
||||
}
|
||||
|
||||
func appendBytesValue(gen QueryGen, b []byte, v reflect.Value) []byte {
|
||||
return gen.Dialect().AppendBytes(b, v.Bytes())
|
||||
}
|
||||
|
||||
func appendArrayBytesValue(gen QueryGen, b []byte, v reflect.Value) []byte {
|
||||
if v.CanAddr() {
|
||||
return gen.Dialect().AppendBytes(b, v.Slice(0, v.Len()).Bytes())
|
||||
}
|
||||
|
||||
tmp := make([]byte, v.Len())
|
||||
reflect.Copy(reflect.ValueOf(tmp), v)
|
||||
b = gen.Dialect().AppendBytes(b, tmp)
|
||||
return b
|
||||
}
|
||||
|
||||
func AppendStringValue(gen QueryGen, b []byte, v reflect.Value) []byte {
|
||||
return gen.Dialect().AppendString(b, v.String())
|
||||
}
|
||||
|
||||
func AppendJSONValue(gen QueryGen, b []byte, v reflect.Value) []byte {
|
||||
bb, err := bunjson.Marshal(v.Interface())
|
||||
if err != nil {
|
||||
return dialect.AppendError(b, err)
|
||||
}
|
||||
|
||||
if len(bb) > 0 && bb[len(bb)-1] == '\n' {
|
||||
bb = bb[:len(bb)-1]
|
||||
}
|
||||
|
||||
return gen.Dialect().AppendJSON(b, bb)
|
||||
}
|
||||
|
||||
func appendTimeValue(gen QueryGen, b []byte, v reflect.Value) []byte {
|
||||
tm := v.Interface().(time.Time)
|
||||
return gen.Dialect().AppendTime(b, tm)
|
||||
}
|
||||
|
||||
func appendIPNetValue(gen QueryGen, b []byte, v reflect.Value) []byte {
|
||||
ipnet := v.Interface().(net.IPNet)
|
||||
return gen.Dialect().AppendString(b, ipnet.String())
|
||||
}
|
||||
|
||||
func appendStringer(gen QueryGen, b []byte, v reflect.Value) []byte {
|
||||
return gen.Dialect().AppendString(b, v.Interface().(fmt.Stringer).String())
|
||||
}
|
||||
|
||||
func appendJSONRawMessageValue(gen QueryGen, b []byte, v reflect.Value) []byte {
|
||||
bytes := v.Bytes()
|
||||
if bytes == nil {
|
||||
return dialect.AppendNull(b)
|
||||
}
|
||||
return gen.Dialect().AppendString(b, internal.String(bytes))
|
||||
}
|
||||
|
||||
func appendQueryAppenderValue(gen QueryGen, b []byte, v reflect.Value) []byte {
|
||||
return AppendQueryAppender(gen, b, v.Interface().(QueryAppender))
|
||||
}
|
||||
|
||||
func appendDriverValue(gen QueryGen, b []byte, v reflect.Value) []byte {
|
||||
value, err := v.Interface().(driver.Valuer).Value()
|
||||
if err != nil {
|
||||
return dialect.AppendError(b, err)
|
||||
}
|
||||
if _, ok := value.(driver.Valuer); ok {
|
||||
return dialect.AppendError(b, fmt.Errorf("driver.Valuer returns unsupported type %T", value))
|
||||
}
|
||||
return gen.Append(b, value)
|
||||
}
|
||||
|
||||
func addrAppender(fn AppenderFunc) AppenderFunc {
|
||||
return func(gen QueryGen, b []byte, v reflect.Value) []byte {
|
||||
if !v.CanAddr() {
|
||||
err := fmt.Errorf("bun: Append(nonaddressable %T)", v.Interface())
|
||||
return dialect.AppendError(b, err)
|
||||
}
|
||||
return fn(gen, b, v.Addr())
|
||||
}
|
||||
}
|
||||
|
||||
func appendMsgpack(gen QueryGen, b []byte, v reflect.Value) []byte {
|
||||
hexEnc := internal.NewHexEncoder(b)
|
||||
|
||||
enc := msgpack.GetEncoder()
|
||||
defer msgpack.PutEncoder(enc)
|
||||
|
||||
enc.Reset(hexEnc)
|
||||
if err := enc.EncodeValue(v); err != nil {
|
||||
return dialect.AppendError(b, err)
|
||||
}
|
||||
|
||||
if err := hexEnc.Close(); err != nil {
|
||||
return dialect.AppendError(b, err)
|
||||
}
|
||||
|
||||
return hexEnc.Bytes()
|
||||
}
|
||||
|
||||
func AppendQueryAppender(gen QueryGen, b []byte, app QueryAppender) []byte {
|
||||
bb, err := app.AppendQuery(gen, b)
|
||||
if err != nil {
|
||||
return dialect.AppendError(b, err)
|
||||
}
|
||||
return bb
|
||||
}
|
||||
194
vendor/github.com/uptrace/bun/schema/dialect.go
generated
vendored
Normal file
194
vendor/github.com/uptrace/bun/schema/dialect.go
generated
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"strconv"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/uptrace/bun/dialect"
|
||||
"github.com/uptrace/bun/dialect/feature"
|
||||
"github.com/uptrace/bun/internal/parser"
|
||||
)
|
||||
|
||||
type Dialect interface {
|
||||
Init(db *sql.DB)
|
||||
|
||||
Name() dialect.Name
|
||||
Features() feature.Feature
|
||||
|
||||
Tables() *Tables
|
||||
OnTable(table *Table)
|
||||
|
||||
IdentQuote() byte
|
||||
|
||||
AppendUint32(b []byte, n uint32) []byte
|
||||
AppendUint64(b []byte, n uint64) []byte
|
||||
AppendTime(b []byte, tm time.Time) []byte
|
||||
AppendString(b []byte, s string) []byte
|
||||
AppendBytes(b []byte, bs []byte) []byte
|
||||
AppendJSON(b, jsonb []byte) []byte
|
||||
AppendBool(b []byte, v bool) []byte
|
||||
|
||||
// AppendSequence adds the appropriate instruction for the driver to create a sequence
|
||||
// from which (autoincremented) values for the column will be generated.
|
||||
AppendSequence(b []byte, t *Table, f *Field) []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
|
||||
|
||||
// DefaultSchema should returns the name of the default database schema.
|
||||
DefaultSchema() string
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
type BaseDialect struct{}
|
||||
|
||||
func (BaseDialect) AppendUint32(b []byte, n uint32) []byte {
|
||||
return strconv.AppendUint(b, uint64(n), 10)
|
||||
}
|
||||
|
||||
func (BaseDialect) AppendUint64(b []byte, n uint64) []byte {
|
||||
return strconv.AppendUint(b, n, 10)
|
||||
}
|
||||
|
||||
func (BaseDialect) 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 (BaseDialect) AppendString(b []byte, s string) []byte {
|
||||
b = append(b, '\'')
|
||||
for _, r := range s {
|
||||
if r == '\000' {
|
||||
continue
|
||||
}
|
||||
|
||||
if r == '\'' {
|
||||
b = append(b, '\'', '\'')
|
||||
continue
|
||||
}
|
||||
|
||||
if r < utf8.RuneSelf {
|
||||
b = append(b, byte(r))
|
||||
continue
|
||||
}
|
||||
|
||||
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 (BaseDialect) AppendBytes(b, 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 (BaseDialect) 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.CutPrefix([]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, '\'')
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func (BaseDialect) AppendBool(b []byte, v bool) []byte {
|
||||
return dialect.AppendBool(b, v)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
type nopDialect struct {
|
||||
BaseDialect
|
||||
|
||||
tables *Tables
|
||||
features feature.Feature
|
||||
}
|
||||
|
||||
func newNopDialect() *nopDialect {
|
||||
d := new(nopDialect)
|
||||
d.tables = NewTables(d)
|
||||
d.features = feature.Returning
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *nopDialect) Init(*sql.DB) {}
|
||||
|
||||
func (d *nopDialect) Name() dialect.Name {
|
||||
return dialect.Invalid
|
||||
}
|
||||
|
||||
func (d *nopDialect) Features() feature.Feature {
|
||||
return d.features
|
||||
}
|
||||
|
||||
func (d *nopDialect) Tables() *Tables {
|
||||
return d.tables
|
||||
}
|
||||
|
||||
func (d *nopDialect) OnField(field *Field) {}
|
||||
|
||||
func (d *nopDialect) OnTable(table *Table) {}
|
||||
|
||||
func (d *nopDialect) IdentQuote() byte {
|
||||
return '"'
|
||||
}
|
||||
|
||||
func (d *nopDialect) DefaultVarcharLen() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (d *nopDialect) AppendSequence(b []byte, _ *Table, _ *Field) []byte {
|
||||
return b
|
||||
}
|
||||
|
||||
func (d *nopDialect) DefaultSchema() string {
|
||||
return "nop"
|
||||
}
|
||||
137
vendor/github.com/uptrace/bun/schema/field.go
generated
vendored
Normal file
137
vendor/github.com/uptrace/bun/schema/field.go
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/uptrace/bun/dialect"
|
||||
"github.com/uptrace/bun/internal"
|
||||
"github.com/uptrace/bun/internal/tagparser"
|
||||
)
|
||||
|
||||
type Field struct {
|
||||
Table *Table // Contains this field
|
||||
StructField reflect.StructField
|
||||
IsPtr bool
|
||||
|
||||
Tag tagparser.Tag
|
||||
IndirectType reflect.Type
|
||||
Index []int
|
||||
|
||||
Name string // SQL name, .e.g. id
|
||||
SQLName Safe // escaped SQL name, e.g. "id"
|
||||
GoName string // struct field name, e.g. Id
|
||||
|
||||
DiscoveredSQLType string
|
||||
UserSQLType string
|
||||
CreateTableSQLType string
|
||||
SQLDefault string
|
||||
|
||||
OnDelete string
|
||||
OnUpdate string
|
||||
|
||||
IsPK bool
|
||||
NotNull bool
|
||||
NullZero bool
|
||||
AutoIncrement bool
|
||||
Identity bool
|
||||
|
||||
Append AppenderFunc
|
||||
Scan ScannerFunc
|
||||
IsZero IsZeroerFunc
|
||||
}
|
||||
|
||||
func (f *Field) String() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
func (f *Field) WithIndex(path []int) *Field {
|
||||
if len(path) == 0 {
|
||||
return f
|
||||
}
|
||||
clone := *f
|
||||
clone.Index = makeIndex(path, f.Index)
|
||||
return &clone
|
||||
}
|
||||
|
||||
func (f *Field) Clone() *Field {
|
||||
cp := *f
|
||||
cp.Index = cp.Index[:len(f.Index):len(f.Index)]
|
||||
return &cp
|
||||
}
|
||||
|
||||
func (f *Field) Value(strct reflect.Value) reflect.Value {
|
||||
return internal.FieldByIndexAlloc(strct, f.Index)
|
||||
}
|
||||
|
||||
func (f *Field) HasNilValue(v reflect.Value) bool {
|
||||
if len(f.Index) == 1 {
|
||||
return v.Field(f.Index[0]).IsNil()
|
||||
}
|
||||
|
||||
for _, index := range f.Index {
|
||||
if v.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
return true
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
v = v.Field(index)
|
||||
}
|
||||
return v.IsNil()
|
||||
}
|
||||
|
||||
func (f *Field) HasZeroValue(v reflect.Value) bool {
|
||||
if len(f.Index) == 1 {
|
||||
return f.IsZero(v.Field(f.Index[0]))
|
||||
}
|
||||
|
||||
for _, index := range f.Index {
|
||||
if v.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
return true
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
v = v.Field(index)
|
||||
}
|
||||
return f.IsZero(v)
|
||||
}
|
||||
|
||||
func (f *Field) AppendValue(gen QueryGen, b []byte, strct reflect.Value) []byte {
|
||||
fv, ok := fieldByIndex(strct, f.Index)
|
||||
if !ok {
|
||||
return dialect.AppendNull(b)
|
||||
}
|
||||
|
||||
if (f.IsPtr && fv.IsNil()) || (f.NullZero && f.IsZero(fv)) {
|
||||
return dialect.AppendNull(b)
|
||||
}
|
||||
if f.Append == nil {
|
||||
panic(fmt.Errorf("bun: AppendValue(unsupported %s)", fv.Type()))
|
||||
}
|
||||
return f.Append(gen, b, fv)
|
||||
}
|
||||
|
||||
func (f *Field) ScanValue(strct reflect.Value, src any) error {
|
||||
if src == nil {
|
||||
if fv, ok := fieldByIndex(strct, f.Index); ok {
|
||||
return f.ScanWithCheck(fv, src)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
fv := internal.FieldByIndexAlloc(strct, f.Index)
|
||||
return f.ScanWithCheck(fv, src)
|
||||
}
|
||||
|
||||
func (f *Field) ScanWithCheck(fv reflect.Value, src any) error {
|
||||
if f.Scan == nil {
|
||||
return fmt.Errorf("bun: Scan(unsupported %s)", f.IndirectType)
|
||||
}
|
||||
return f.Scan(fv, src)
|
||||
}
|
||||
|
||||
func (f *Field) SkipUpdate() bool {
|
||||
return f.Tag.HasOption("skipupdate")
|
||||
}
|
||||
43
vendor/github.com/uptrace/bun/schema/hook.go
generated
vendored
Normal file
43
vendor/github.com/uptrace/bun/schema/hook.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type Model interface {
|
||||
ScanRows(ctx context.Context, rows *sql.Rows) (int, error)
|
||||
Value() any
|
||||
}
|
||||
|
||||
type Query interface {
|
||||
QueryAppender
|
||||
Operation() string
|
||||
GetModel() Model
|
||||
GetTableName() string
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type BeforeAppendModelHook interface {
|
||||
BeforeAppendModel(ctx context.Context, query Query) error
|
||||
}
|
||||
|
||||
var beforeAppendModelHookType = reflect.TypeFor[BeforeAppendModelHook]()
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type BeforeScanRowHook interface {
|
||||
BeforeScanRow(context.Context) error
|
||||
}
|
||||
|
||||
var beforeScanRowHookType = reflect.TypeFor[BeforeScanRowHook]()
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type AfterScanRowHook interface {
|
||||
AfterScanRow(context.Context) error
|
||||
}
|
||||
|
||||
var afterScanRowHookType = reflect.TypeFor[AfterScanRowHook]()
|
||||
291
vendor/github.com/uptrace/bun/schema/querygen.go
generated
vendored
Normal file
291
vendor/github.com/uptrace/bun/schema/querygen.go
generated
vendored
Normal file
@@ -0,0 +1,291 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/uptrace/bun/dialect"
|
||||
"github.com/uptrace/bun/dialect/feature"
|
||||
"github.com/uptrace/bun/internal"
|
||||
"github.com/uptrace/bun/internal/parser"
|
||||
)
|
||||
|
||||
var nopQueryGen = QueryGen{
|
||||
dialect: newNopDialect(),
|
||||
}
|
||||
|
||||
type QueryGen struct {
|
||||
dialect Dialect
|
||||
args *namedArgList
|
||||
}
|
||||
|
||||
func NewQueryGen(dialect Dialect) QueryGen {
|
||||
return QueryGen{
|
||||
dialect: dialect,
|
||||
}
|
||||
}
|
||||
|
||||
func NewNopQueryGen() QueryGen {
|
||||
return nopQueryGen
|
||||
}
|
||||
|
||||
func (f QueryGen) IsNop() bool {
|
||||
return f.dialect.Name() == dialect.Invalid
|
||||
}
|
||||
|
||||
func (f QueryGen) Dialect() Dialect {
|
||||
return f.dialect
|
||||
}
|
||||
|
||||
func (f QueryGen) IdentQuote() byte {
|
||||
return f.dialect.IdentQuote()
|
||||
}
|
||||
|
||||
func (gen QueryGen) Append(b []byte, v any) []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 gen.Dialect().AppendUint32(b, v)
|
||||
case uint64:
|
||||
return gen.Dialect().AppendUint64(b, v)
|
||||
case float32:
|
||||
return dialect.AppendFloat32(b, v)
|
||||
case float64:
|
||||
return dialect.AppendFloat64(b, v)
|
||||
case string:
|
||||
return gen.Dialect().AppendString(b, v)
|
||||
case time.Time:
|
||||
return gen.Dialect().AppendTime(b, v)
|
||||
case []byte:
|
||||
return gen.Dialect().AppendBytes(b, v)
|
||||
case QueryAppender:
|
||||
return AppendQueryAppender(gen, b, v)
|
||||
default:
|
||||
vv := reflect.ValueOf(v)
|
||||
if vv.Kind() == reflect.Ptr && vv.IsNil() {
|
||||
return dialect.AppendNull(b)
|
||||
}
|
||||
appender := Appender(gen.Dialect(), vv.Type())
|
||||
return appender(gen, b, vv)
|
||||
}
|
||||
}
|
||||
|
||||
func (f QueryGen) AppendName(b []byte, name string) []byte {
|
||||
return dialect.AppendName(b, name, f.IdentQuote())
|
||||
}
|
||||
|
||||
func (f QueryGen) AppendIdent(b []byte, ident string) []byte {
|
||||
return dialect.AppendIdent(b, ident, f.IdentQuote())
|
||||
}
|
||||
|
||||
func (f QueryGen) AppendValue(b []byte, v reflect.Value) []byte {
|
||||
if v.Kind() == reflect.Ptr && v.IsNil() {
|
||||
return dialect.AppendNull(b)
|
||||
}
|
||||
appender := Appender(f.dialect, v.Type())
|
||||
return appender(f, b, v)
|
||||
}
|
||||
|
||||
func (f QueryGen) HasFeature(feature feature.Feature) bool {
|
||||
return f.dialect.Features().Has(feature)
|
||||
}
|
||||
|
||||
func (f QueryGen) WithArg(arg NamedArgAppender) QueryGen {
|
||||
return QueryGen{
|
||||
dialect: f.dialect,
|
||||
args: f.args.WithArg(arg),
|
||||
}
|
||||
}
|
||||
|
||||
func (f QueryGen) WithNamedArg(name string, value any) QueryGen {
|
||||
return QueryGen{
|
||||
dialect: f.dialect,
|
||||
args: f.args.WithArg(&namedArg{name: name, value: value}),
|
||||
}
|
||||
}
|
||||
|
||||
func (f QueryGen) FormatQuery(query string, args ...any) string {
|
||||
if f.IsNop() || (args == nil && f.args == nil) || strings.IndexByte(query, '?') == -1 {
|
||||
return query
|
||||
}
|
||||
return internal.String(f.AppendQuery(nil, query, args...))
|
||||
}
|
||||
|
||||
func (f QueryGen) AppendQuery(dst []byte, query string, args ...any) []byte {
|
||||
if f.IsNop() || (args == nil && f.args == nil) || strings.IndexByte(query, '?') == -1 {
|
||||
return append(dst, query...)
|
||||
}
|
||||
return f.append(dst, parser.NewString(query), args)
|
||||
}
|
||||
|
||||
func (f QueryGen) append(dst []byte, p *parser.Parser, args []any) []byte {
|
||||
var namedArgs NamedArgAppender
|
||||
if len(args) == 1 {
|
||||
if v, ok := args[0].(NamedArgAppender); ok {
|
||||
namedArgs = v
|
||||
} else if v, ok := newStructArgs(f, args[0]); ok {
|
||||
namedArgs = v
|
||||
}
|
||||
}
|
||||
|
||||
var argIndex int
|
||||
for p.Valid() {
|
||||
b, ok := p.ReadSep('?')
|
||||
if !ok {
|
||||
dst = append(dst, b...)
|
||||
continue
|
||||
}
|
||||
if len(b) > 0 && b[len(b)-1] == '\\' {
|
||||
dst = append(dst, b[:len(b)-1]...)
|
||||
dst = append(dst, '?')
|
||||
continue
|
||||
}
|
||||
dst = append(dst, b...)
|
||||
|
||||
name, numeric := p.ReadIdentifier()
|
||||
if name != "" {
|
||||
if numeric {
|
||||
idx, err := strconv.Atoi(name)
|
||||
if err != nil {
|
||||
goto restore_arg
|
||||
}
|
||||
|
||||
if idx >= len(args) {
|
||||
goto restore_arg
|
||||
}
|
||||
|
||||
dst = f.appendArg(dst, args[idx])
|
||||
continue
|
||||
}
|
||||
|
||||
if namedArgs != nil {
|
||||
dst, ok = namedArgs.AppendNamedArg(f, dst, name)
|
||||
if ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
dst, ok = f.args.AppendNamedArg(f, dst, name)
|
||||
if ok {
|
||||
continue
|
||||
}
|
||||
|
||||
restore_arg:
|
||||
dst = append(dst, '?')
|
||||
dst = append(dst, name...)
|
||||
continue
|
||||
}
|
||||
|
||||
if argIndex >= len(args) {
|
||||
dst = append(dst, '?')
|
||||
continue
|
||||
}
|
||||
|
||||
arg := args[argIndex]
|
||||
argIndex++
|
||||
|
||||
dst = f.appendArg(dst, arg)
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
func (gen QueryGen) appendArg(b []byte, arg any) []byte {
|
||||
switch arg := arg.(type) {
|
||||
case QueryAppender:
|
||||
bb, err := arg.AppendQuery(gen, b)
|
||||
if err != nil {
|
||||
return dialect.AppendError(b, err)
|
||||
}
|
||||
return bb
|
||||
default:
|
||||
return gen.Append(b, arg)
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type NamedArgAppender interface {
|
||||
AppendNamedArg(gen QueryGen, b []byte, name string) ([]byte, bool)
|
||||
}
|
||||
|
||||
type namedArgList struct {
|
||||
arg NamedArgAppender
|
||||
next *namedArgList
|
||||
}
|
||||
|
||||
func (l *namedArgList) WithArg(arg NamedArgAppender) *namedArgList {
|
||||
return &namedArgList{
|
||||
arg: arg,
|
||||
next: l,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *namedArgList) AppendNamedArg(gen QueryGen, b []byte, name string) ([]byte, bool) {
|
||||
for l != nil && l.arg != nil {
|
||||
if b, ok := l.arg.AppendNamedArg(gen, b, name); ok {
|
||||
return b, true
|
||||
}
|
||||
l = l.next
|
||||
}
|
||||
return b, false
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type namedArg struct {
|
||||
name string
|
||||
value any
|
||||
}
|
||||
|
||||
var _ NamedArgAppender = (*namedArg)(nil)
|
||||
|
||||
func (a *namedArg) AppendNamedArg(gen QueryGen, b []byte, name string) ([]byte, bool) {
|
||||
if a.name == name {
|
||||
return gen.appendArg(b, a.value), true
|
||||
}
|
||||
return b, false
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type structArgs struct {
|
||||
table *Table
|
||||
strct reflect.Value
|
||||
}
|
||||
|
||||
var _ NamedArgAppender = (*structArgs)(nil)
|
||||
|
||||
func newStructArgs(gen QueryGen, strct any) (*structArgs, bool) {
|
||||
v := reflect.ValueOf(strct)
|
||||
if !v.IsValid() {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
v = reflect.Indirect(v)
|
||||
if v.Kind() != reflect.Struct {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return &structArgs{
|
||||
table: gen.Dialect().Tables().Get(v.Type()),
|
||||
strct: v,
|
||||
}, true
|
||||
}
|
||||
|
||||
func (m *structArgs) AppendNamedArg(gen QueryGen, b []byte, name string) ([]byte, bool) {
|
||||
return m.table.AppendNamedArg(gen, b, name, m.strct)
|
||||
}
|
||||
51
vendor/github.com/uptrace/bun/schema/reflect.go
generated
vendored
Normal file
51
vendor/github.com/uptrace/bun/schema/reflect.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"net"
|
||||
"net/netip"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
bytesType = reflect.TypeFor[[]byte]()
|
||||
timePtrType = reflect.TypeFor[*time.Time]()
|
||||
timeType = reflect.TypeFor[time.Time]()
|
||||
ipType = reflect.TypeFor[net.IP]()
|
||||
ipNetType = reflect.TypeFor[net.IPNet]()
|
||||
netipPrefixType = reflect.TypeFor[netip.Prefix]()
|
||||
netipAddrType = reflect.TypeFor[netip.Addr]()
|
||||
jsonRawMessageType = reflect.TypeFor[json.RawMessage]()
|
||||
|
||||
driverValuerType = reflect.TypeFor[driver.Valuer]()
|
||||
queryAppenderType = reflect.TypeFor[QueryAppender]()
|
||||
jsonMarshalerType = reflect.TypeFor[json.Marshaler]()
|
||||
)
|
||||
|
||||
func indirectType(t reflect.Type) reflect.Type {
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func fieldByIndex(v reflect.Value, index []int) (_ reflect.Value, ok bool) {
|
||||
if len(index) == 1 {
|
||||
return v.Field(index[0]), true
|
||||
}
|
||||
|
||||
for i, idx := range index {
|
||||
if i > 0 {
|
||||
if v.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
return v, false
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
}
|
||||
v = v.Field(idx)
|
||||
}
|
||||
return v, true
|
||||
}
|
||||
84
vendor/github.com/uptrace/bun/schema/relation.go
generated
vendored
Normal file
84
vendor/github.com/uptrace/bun/schema/relation.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
InvalidRelation = iota
|
||||
HasOneRelation
|
||||
BelongsToRelation
|
||||
HasManyRelation
|
||||
ManyToManyRelation
|
||||
)
|
||||
|
||||
type Relation struct {
|
||||
Type int
|
||||
Field *Field // Has the bun tag defining this relation.
|
||||
|
||||
// Base and Join can be explained with this query:
|
||||
//
|
||||
// SELECT * FROM base_table JOIN join_table
|
||||
JoinTable *Table
|
||||
BasePKs []*Field
|
||||
JoinPKs []*Field
|
||||
OnUpdate string
|
||||
OnDelete string
|
||||
Condition []string
|
||||
|
||||
PolymorphicField *Field
|
||||
PolymorphicValue string
|
||||
|
||||
M2MTable *Table
|
||||
M2MBasePKs []*Field
|
||||
M2MJoinPKs []*Field
|
||||
}
|
||||
|
||||
// References returns true if the table which defines this Relation
|
||||
// needs to declare a foreign key constraint, as is the case
|
||||
// for 'has-one' and 'belongs-to' relations. For other relations,
|
||||
// the constraint is created either in the referencing table (1:N, 'has-many' relations)
|
||||
// or the junction table (N:N, 'm2m' relations).
|
||||
//
|
||||
// Usage of `rel:` tag does not always imply creation of foreign keys (when WithForeignKeys() is not set)
|
||||
// and can be used exclusively for joining tables at query time. For example:
|
||||
//
|
||||
// type User struct {
|
||||
// ID int64 `bun:",pk"`
|
||||
// Profile *Profile `bun:",rel:has-one,join:id=user_id"`
|
||||
// }
|
||||
//
|
||||
// Creating a FK users.id -> profiles.user_id would be confusing and incorrect,
|
||||
// so for such cases References() returns false. One notable exception to this rule
|
||||
// is when a Relation is defined in a junction table, in which case it is perfectly
|
||||
// fine for its primary keys to reference other tables. Consider:
|
||||
//
|
||||
// // UsersToGroups maps users to groups they follow.
|
||||
// type UsersToGroups struct {
|
||||
// UserID string `bun:"user_id,pk"` // Needs FK to users.id
|
||||
// GroupID string `bun:"group_id,pk"` // Needs FK to groups.id
|
||||
//
|
||||
// User *User `bun:"rel:belongs-to,join:user_id=id"`
|
||||
// Group *Group `bun:"rel:belongs-to,join:group_id=id"`
|
||||
// }
|
||||
//
|
||||
// Here BooksToReaders has a composite primary key, composed of other primary keys.
|
||||
func (r *Relation) References() bool {
|
||||
allPK := true
|
||||
nonePK := true
|
||||
for _, f := range r.BasePKs {
|
||||
allPK = allPK && f.IsPK
|
||||
nonePK = nonePK && !f.IsPK
|
||||
}
|
||||
|
||||
// Erring on the side of caution, only create foreign keys
|
||||
// if the referencing columns are part of a composite PK
|
||||
// in the junction table of the m2m relationship.
|
||||
effectsM2M := r.Field.Table.IsM2MTable && allPK
|
||||
|
||||
return (r.Type == HasOneRelation || r.Type == BelongsToRelation) && (effectsM2M || nonePK)
|
||||
}
|
||||
|
||||
func (r *Relation) String() string {
|
||||
return fmt.Sprintf("relation=%s", r.Field.GoName)
|
||||
}
|
||||
566
vendor/github.com/uptrace/bun/schema/scan.go
generated
vendored
Normal file
566
vendor/github.com/uptrace/bun/schema/scan.go
generated
vendored
Normal file
@@ -0,0 +1,566 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/puzpuzpuz/xsync/v3"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
|
||||
"github.com/uptrace/bun/dialect/sqltype"
|
||||
"github.com/uptrace/bun/extra/bunjson"
|
||||
"github.com/uptrace/bun/internal"
|
||||
)
|
||||
|
||||
var scannerType = reflect.TypeFor[sql.Scanner]()
|
||||
|
||||
type ScannerFunc func(dest reflect.Value, src any) error
|
||||
|
||||
var scanners []ScannerFunc
|
||||
|
||||
func init() {
|
||||
scanners = []ScannerFunc{
|
||||
reflect.Bool: scanBool,
|
||||
reflect.Int: scanInt64,
|
||||
reflect.Int8: scanInt64,
|
||||
reflect.Int16: scanInt64,
|
||||
reflect.Int32: scanInt64,
|
||||
reflect.Int64: scanInt64,
|
||||
reflect.Uint: scanUint64,
|
||||
reflect.Uint8: scanUint64,
|
||||
reflect.Uint16: scanUint64,
|
||||
reflect.Uint32: scanUint64,
|
||||
reflect.Uint64: scanUint64,
|
||||
reflect.Uintptr: scanUint64,
|
||||
reflect.Float32: scanFloat,
|
||||
reflect.Float64: scanFloat,
|
||||
reflect.Complex64: nil,
|
||||
reflect.Complex128: nil,
|
||||
reflect.Array: nil,
|
||||
reflect.Interface: scanInterface,
|
||||
reflect.Map: scanJSON,
|
||||
reflect.Ptr: nil,
|
||||
reflect.Slice: scanJSON,
|
||||
reflect.String: scanString,
|
||||
reflect.Struct: scanJSON,
|
||||
reflect.UnsafePointer: nil,
|
||||
}
|
||||
}
|
||||
|
||||
var scannerCache = xsync.NewMapOf[reflect.Type, ScannerFunc]()
|
||||
|
||||
func FieldScanner(dialect Dialect, field *Field) ScannerFunc {
|
||||
if field.Tag.HasOption("msgpack") {
|
||||
return scanMsgpack
|
||||
}
|
||||
if field.Tag.HasOption("json_use_number") {
|
||||
return scanJSONUseNumber
|
||||
}
|
||||
if field.StructField.Type.Kind() == reflect.Interface {
|
||||
switch strings.ToUpper(field.UserSQLType) {
|
||||
case sqltype.JSON, sqltype.JSONB:
|
||||
return scanJSONIntoInterface
|
||||
}
|
||||
}
|
||||
return Scanner(field.StructField.Type)
|
||||
}
|
||||
|
||||
func Scanner(typ reflect.Type) ScannerFunc {
|
||||
if v, ok := scannerCache.Load(typ); ok {
|
||||
return v
|
||||
}
|
||||
|
||||
fn := scanner(typ)
|
||||
|
||||
if v, ok := scannerCache.LoadOrStore(typ, fn); ok {
|
||||
return v
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
func scanner(typ reflect.Type) ScannerFunc {
|
||||
kind := typ.Kind()
|
||||
|
||||
if kind == reflect.Ptr {
|
||||
if fn := Scanner(typ.Elem()); fn != nil {
|
||||
return PtrScanner(fn)
|
||||
}
|
||||
}
|
||||
|
||||
switch typ {
|
||||
case bytesType:
|
||||
return scanBytes
|
||||
case timeType:
|
||||
return scanTime
|
||||
case ipType:
|
||||
return scanIP
|
||||
case ipNetType:
|
||||
return scanIPNet
|
||||
case netipAddrType:
|
||||
return scanNetIpAddr
|
||||
case netipPrefixType:
|
||||
return scanNetIpPrefix
|
||||
case jsonRawMessageType:
|
||||
return scanBytes
|
||||
}
|
||||
|
||||
if typ.Implements(scannerType) {
|
||||
return scanScanner
|
||||
}
|
||||
|
||||
if kind != reflect.Ptr {
|
||||
ptr := reflect.PointerTo(typ)
|
||||
if ptr.Implements(scannerType) {
|
||||
return addrScanner(scanScanner)
|
||||
}
|
||||
}
|
||||
|
||||
if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 {
|
||||
return scanBytes
|
||||
}
|
||||
|
||||
return scanners[kind]
|
||||
}
|
||||
|
||||
func scanBool(dest reflect.Value, src any) error {
|
||||
switch src := src.(type) {
|
||||
case nil:
|
||||
dest.SetBool(false)
|
||||
return nil
|
||||
case bool:
|
||||
dest.SetBool(src)
|
||||
return nil
|
||||
case int64:
|
||||
dest.SetBool(src != 0)
|
||||
return nil
|
||||
case []byte:
|
||||
f, err := strconv.ParseBool(internal.String(src))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dest.SetBool(f)
|
||||
return nil
|
||||
case string:
|
||||
f, err := strconv.ParseBool(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dest.SetBool(f)
|
||||
return nil
|
||||
default:
|
||||
return scanError(dest.Type(), src)
|
||||
}
|
||||
}
|
||||
|
||||
func scanInt64(dest reflect.Value, src any) error {
|
||||
switch src := src.(type) {
|
||||
case nil:
|
||||
dest.SetInt(0)
|
||||
return nil
|
||||
case int64:
|
||||
dest.SetInt(src)
|
||||
return nil
|
||||
case uint64:
|
||||
dest.SetInt(int64(src))
|
||||
return nil
|
||||
case []byte:
|
||||
n, err := strconv.ParseInt(internal.String(src), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dest.SetInt(n)
|
||||
return nil
|
||||
case string:
|
||||
n, err := strconv.ParseInt(src, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dest.SetInt(n)
|
||||
return nil
|
||||
default:
|
||||
return scanError(dest.Type(), src)
|
||||
}
|
||||
}
|
||||
|
||||
func scanUint64(dest reflect.Value, src any) error {
|
||||
switch src := src.(type) {
|
||||
case nil:
|
||||
dest.SetUint(0)
|
||||
return nil
|
||||
case uint64:
|
||||
dest.SetUint(src)
|
||||
return nil
|
||||
case int64:
|
||||
dest.SetUint(uint64(src))
|
||||
return nil
|
||||
case []byte:
|
||||
n, err := strconv.ParseUint(internal.String(src), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dest.SetUint(n)
|
||||
return nil
|
||||
case string:
|
||||
n, err := strconv.ParseUint(src, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dest.SetUint(n)
|
||||
return nil
|
||||
default:
|
||||
return scanError(dest.Type(), src)
|
||||
}
|
||||
}
|
||||
|
||||
func scanFloat(dest reflect.Value, src any) error {
|
||||
switch src := src.(type) {
|
||||
case nil:
|
||||
dest.SetFloat(0)
|
||||
return nil
|
||||
case float32:
|
||||
dest.SetFloat(float64(src))
|
||||
return nil
|
||||
case float64:
|
||||
dest.SetFloat(src)
|
||||
return nil
|
||||
case []byte:
|
||||
f, err := strconv.ParseFloat(internal.String(src), 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dest.SetFloat(f)
|
||||
return nil
|
||||
case string:
|
||||
f, err := strconv.ParseFloat(src, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dest.SetFloat(f)
|
||||
return nil
|
||||
default:
|
||||
return scanError(dest.Type(), src)
|
||||
}
|
||||
}
|
||||
|
||||
func scanString(dest reflect.Value, src any) error {
|
||||
switch src := src.(type) {
|
||||
case nil:
|
||||
dest.SetString("")
|
||||
return nil
|
||||
case string:
|
||||
dest.SetString(src)
|
||||
return nil
|
||||
case []byte:
|
||||
dest.SetString(string(src))
|
||||
return nil
|
||||
case time.Time:
|
||||
dest.SetString(src.Format(time.RFC3339Nano))
|
||||
return nil
|
||||
case int64:
|
||||
dest.SetString(strconv.FormatInt(src, 10))
|
||||
return nil
|
||||
case uint64:
|
||||
dest.SetString(strconv.FormatUint(src, 10))
|
||||
return nil
|
||||
case float64:
|
||||
dest.SetString(strconv.FormatFloat(src, 'G', -1, 64))
|
||||
return nil
|
||||
default:
|
||||
return scanError(dest.Type(), src)
|
||||
}
|
||||
}
|
||||
|
||||
func scanBytes(dest reflect.Value, src any) error {
|
||||
switch src := src.(type) {
|
||||
case nil:
|
||||
dest.SetBytes(nil)
|
||||
return nil
|
||||
case string:
|
||||
dest.SetBytes([]byte(src))
|
||||
return nil
|
||||
case []byte:
|
||||
clone := make([]byte, len(src))
|
||||
copy(clone, src)
|
||||
|
||||
dest.SetBytes(clone)
|
||||
return nil
|
||||
default:
|
||||
return scanError(dest.Type(), src)
|
||||
}
|
||||
}
|
||||
|
||||
func scanTime(dest reflect.Value, src any) error {
|
||||
switch src := src.(type) {
|
||||
case nil:
|
||||
destTime := dest.Addr().Interface().(*time.Time)
|
||||
*destTime = time.Time{}
|
||||
return nil
|
||||
case time.Time:
|
||||
destTime := dest.Addr().Interface().(*time.Time)
|
||||
*destTime = src
|
||||
return nil
|
||||
case string:
|
||||
srcTime, err := internal.ParseTime(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
destTime := dest.Addr().Interface().(*time.Time)
|
||||
*destTime = srcTime
|
||||
return nil
|
||||
case []byte:
|
||||
srcTime, err := internal.ParseTime(internal.String(src))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
destTime := dest.Addr().Interface().(*time.Time)
|
||||
*destTime = srcTime
|
||||
return nil
|
||||
default:
|
||||
return scanError(dest.Type(), src)
|
||||
}
|
||||
}
|
||||
|
||||
func scanScanner(dest reflect.Value, src any) error {
|
||||
return dest.Interface().(sql.Scanner).Scan(src)
|
||||
}
|
||||
|
||||
func scanMsgpack(dest reflect.Value, src any) error {
|
||||
if src == nil {
|
||||
return scanNull(dest)
|
||||
}
|
||||
|
||||
b, err := toBytes(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dec := msgpack.GetDecoder()
|
||||
defer msgpack.PutDecoder(dec)
|
||||
|
||||
dec.Reset(bytes.NewReader(b))
|
||||
return dec.DecodeValue(dest)
|
||||
}
|
||||
|
||||
func scanJSON(dest reflect.Value, src any) error {
|
||||
if src == nil {
|
||||
return scanNull(dest)
|
||||
}
|
||||
|
||||
b, err := toBytes(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return bunjson.Unmarshal(b, dest.Addr().Interface())
|
||||
}
|
||||
|
||||
func scanJSONUseNumber(dest reflect.Value, src any) error {
|
||||
if src == nil {
|
||||
return scanNull(dest)
|
||||
}
|
||||
|
||||
b, err := toBytes(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dec := bunjson.NewDecoder(bytes.NewReader(b))
|
||||
dec.UseNumber()
|
||||
return dec.Decode(dest.Addr().Interface())
|
||||
}
|
||||
|
||||
func scanIP(dest reflect.Value, src any) error {
|
||||
if src == nil {
|
||||
return scanNull(dest)
|
||||
}
|
||||
|
||||
b, err := toBytes(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ip := net.ParseIP(internal.String(b))
|
||||
if ip == nil {
|
||||
return fmt.Errorf("bun: invalid ip: %q", b)
|
||||
}
|
||||
|
||||
ptr := dest.Addr().Interface().(*net.IP)
|
||||
*ptr = ip
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func scanIPNet(dest reflect.Value, src any) error {
|
||||
if src == nil {
|
||||
return scanNull(dest)
|
||||
}
|
||||
|
||||
b, err := toBytes(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, ipnet, err := net.ParseCIDR(internal.String(b))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ptr := dest.Addr().Interface().(*net.IPNet)
|
||||
*ptr = *ipnet
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func scanNetIpAddr(dest reflect.Value, src any) error {
|
||||
if src == nil {
|
||||
return scanNull(dest)
|
||||
}
|
||||
|
||||
b, err := toBytes(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val, _ := netip.ParseAddr(internal.String(b))
|
||||
if !val.IsValid() {
|
||||
return fmt.Errorf("bun: invalid ip: %q", b)
|
||||
}
|
||||
|
||||
ptr := dest.Addr().Interface().(*netip.Addr)
|
||||
*ptr = val
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func scanNetIpPrefix(dest reflect.Value, src any) error {
|
||||
if src == nil {
|
||||
return scanNull(dest)
|
||||
}
|
||||
|
||||
b, err := toBytes(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val, _ := netip.ParsePrefix(internal.String(b))
|
||||
if !val.IsValid() {
|
||||
return fmt.Errorf("bun: invalid prefix: %q", b)
|
||||
}
|
||||
|
||||
ptr := dest.Addr().Interface().(*netip.Prefix)
|
||||
*ptr = val
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func addrScanner(fn ScannerFunc) ScannerFunc {
|
||||
return func(dest reflect.Value, src any) error {
|
||||
if !dest.CanAddr() {
|
||||
return fmt.Errorf("bun: Scan(nonaddressable %T)", dest.Interface())
|
||||
}
|
||||
return fn(dest.Addr(), src)
|
||||
}
|
||||
}
|
||||
|
||||
func toBytes(src any) ([]byte, error) {
|
||||
switch src := src.(type) {
|
||||
case string:
|
||||
return internal.Bytes(src), nil
|
||||
case []byte:
|
||||
return src, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("bun: got %T, wanted []byte or string", src)
|
||||
}
|
||||
}
|
||||
|
||||
func PtrScanner(fn ScannerFunc) ScannerFunc {
|
||||
return func(dest reflect.Value, src any) error {
|
||||
if src == nil {
|
||||
if !dest.CanAddr() {
|
||||
if dest.IsNil() {
|
||||
return nil
|
||||
}
|
||||
return fn(dest.Elem(), src)
|
||||
}
|
||||
|
||||
if !dest.IsNil() {
|
||||
dest.Set(reflect.New(dest.Type().Elem()))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if dest.IsNil() {
|
||||
dest.Set(reflect.New(dest.Type().Elem()))
|
||||
}
|
||||
|
||||
if dest.Kind() == reflect.Map {
|
||||
return fn(dest, src)
|
||||
}
|
||||
|
||||
return fn(dest.Elem(), src)
|
||||
}
|
||||
}
|
||||
|
||||
func scanNull(dest reflect.Value) error {
|
||||
if nilable(dest.Kind()) && dest.IsNil() {
|
||||
return nil
|
||||
}
|
||||
dest.Set(reflect.New(dest.Type()).Elem())
|
||||
return nil
|
||||
}
|
||||
|
||||
func scanJSONIntoInterface(dest reflect.Value, src any) error {
|
||||
if dest.IsNil() {
|
||||
if src == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
b, err := toBytes(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return bunjson.Unmarshal(b, dest.Addr().Interface())
|
||||
}
|
||||
|
||||
dest = dest.Elem()
|
||||
if fn := Scanner(dest.Type()); fn != nil {
|
||||
return fn(dest, src)
|
||||
}
|
||||
return scanError(dest.Type(), src)
|
||||
}
|
||||
|
||||
func scanInterface(dest reflect.Value, src any) error {
|
||||
if dest.IsNil() {
|
||||
if src == nil {
|
||||
return nil
|
||||
}
|
||||
dest.Set(reflect.ValueOf(src))
|
||||
return nil
|
||||
}
|
||||
|
||||
dest = dest.Elem()
|
||||
if fn := Scanner(dest.Type()); fn != nil {
|
||||
return fn(dest, src)
|
||||
}
|
||||
return scanError(dest.Type(), src)
|
||||
}
|
||||
|
||||
func nilable(kind reflect.Kind) bool {
|
||||
switch kind {
|
||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func scanError(dest reflect.Type, src any) error {
|
||||
return fmt.Errorf("bun: can't scan %#v (%T) into %s", src, src, dest.String())
|
||||
}
|
||||
133
vendor/github.com/uptrace/bun/schema/sqlfmt.go
generated
vendored
Normal file
133
vendor/github.com/uptrace/bun/schema/sqlfmt.go
generated
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"strings"
|
||||
|
||||
"github.com/uptrace/bun/internal"
|
||||
)
|
||||
|
||||
type QueryAppender interface {
|
||||
AppendQuery(gen QueryGen, b []byte) ([]byte, error)
|
||||
}
|
||||
|
||||
type ColumnsAppender interface {
|
||||
AppendColumns(gen QueryGen, b []byte) ([]byte, error)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Safe represents a safe SQL query.
|
||||
type Safe string
|
||||
|
||||
var _ QueryAppender = (*Safe)(nil)
|
||||
|
||||
func (s Safe) AppendQuery(gen QueryGen, b []byte) ([]byte, error) {
|
||||
return append(b, s...), nil
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Name represents a single SQL name, for example, a column name.
|
||||
type Name string
|
||||
|
||||
var _ QueryAppender = (*Name)(nil)
|
||||
|
||||
func (s Name) AppendQuery(gen QueryGen, b []byte) ([]byte, error) {
|
||||
return gen.AppendName(b, string(s)), nil
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Ident represents a SQL identifier, for example,
|
||||
// a fully qualified column name such as `table_name.col_name`.
|
||||
type Ident string
|
||||
|
||||
var _ QueryAppender = (*Ident)(nil)
|
||||
|
||||
func (s Ident) AppendQuery(gen QueryGen, b []byte) ([]byte, error) {
|
||||
return gen.AppendIdent(b, string(s)), nil
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// NOTE: It should not be modified after creation.
|
||||
type QueryWithArgs struct {
|
||||
Query string
|
||||
Args []any
|
||||
}
|
||||
|
||||
var _ QueryAppender = QueryWithArgs{}
|
||||
|
||||
func SafeQuery(query string, args []any) QueryWithArgs {
|
||||
if args == nil {
|
||||
args = make([]any, 0)
|
||||
} else if len(query) > 0 && strings.IndexByte(query, '?') == -1 {
|
||||
internal.Warn.Printf("query %q has %v args, but no placeholders", query, args)
|
||||
}
|
||||
return QueryWithArgs{
|
||||
Query: query,
|
||||
Args: args,
|
||||
}
|
||||
}
|
||||
|
||||
func UnsafeIdent(ident string) QueryWithArgs {
|
||||
return QueryWithArgs{Query: ident}
|
||||
}
|
||||
|
||||
func (q QueryWithArgs) IsZero() bool {
|
||||
return q.Query == "" && q.Args == nil
|
||||
}
|
||||
|
||||
func (q QueryWithArgs) AppendQuery(gen QueryGen, b []byte) ([]byte, error) {
|
||||
if q.Args == nil {
|
||||
return gen.AppendIdent(b, q.Query), nil
|
||||
}
|
||||
return gen.AppendQuery(b, q.Query, q.Args...), nil
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type Order string
|
||||
|
||||
const (
|
||||
OrderNone Order = ""
|
||||
OrderAsc Order = "ASC"
|
||||
OrderAscNullsFirst Order = "ASC NULLS FIRST"
|
||||
OrderAscNullsLast Order = "ASC NULLS LAST"
|
||||
OrderDesc Order = "DESC"
|
||||
OrderDescNullsFirst Order = "DESC NULLS FIRST"
|
||||
OrderDescNullsLast Order = "DESC NULLS LAST"
|
||||
)
|
||||
|
||||
func (s Order) AppendQuery(gen QueryGen, b []byte) ([]byte, error) {
|
||||
return AppendOrder(b, s), nil
|
||||
}
|
||||
|
||||
func AppendOrder(b []byte, sortDir Order) []byte {
|
||||
switch sortDir {
|
||||
case OrderAsc, OrderDesc,
|
||||
OrderAscNullsFirst, OrderAscNullsLast,
|
||||
OrderDescNullsFirst, OrderDescNullsLast:
|
||||
return append(b, sortDir...)
|
||||
case OrderNone:
|
||||
return b
|
||||
default:
|
||||
slog.Error("unsupported sort direction", slog.String("sort_dir", string(sortDir)))
|
||||
return b
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type QueryWithSep struct {
|
||||
QueryWithArgs
|
||||
Sep string
|
||||
}
|
||||
|
||||
func SafeQueryWithSep(query string, args []any, sep string) QueryWithSep {
|
||||
return QueryWithSep{
|
||||
QueryWithArgs: SafeQuery(query, args),
|
||||
Sep: sep,
|
||||
}
|
||||
}
|
||||
141
vendor/github.com/uptrace/bun/schema/sqltype.go
generated
vendored
Normal file
141
vendor/github.com/uptrace/bun/schema/sqltype.go
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/uptrace/bun/dialect"
|
||||
"github.com/uptrace/bun/dialect/sqltype"
|
||||
"github.com/uptrace/bun/internal"
|
||||
)
|
||||
|
||||
var (
|
||||
bunNullTimeType = reflect.TypeFor[NullTime]()
|
||||
nullTimeType = reflect.TypeFor[sql.NullTime]()
|
||||
nullBoolType = reflect.TypeFor[sql.NullBool]()
|
||||
nullFloatType = reflect.TypeFor[sql.NullFloat64]()
|
||||
nullIntType = reflect.TypeFor[sql.NullInt64]()
|
||||
nullStringType = reflect.TypeFor[sql.NullString]()
|
||||
)
|
||||
|
||||
var sqlTypes = []string{
|
||||
reflect.Bool: sqltype.Boolean,
|
||||
reflect.Int: sqltype.BigInt,
|
||||
reflect.Int8: sqltype.SmallInt,
|
||||
reflect.Int16: sqltype.SmallInt,
|
||||
reflect.Int32: sqltype.Integer,
|
||||
reflect.Int64: sqltype.BigInt,
|
||||
reflect.Uint: sqltype.BigInt,
|
||||
reflect.Uint8: sqltype.SmallInt,
|
||||
reflect.Uint16: sqltype.SmallInt,
|
||||
reflect.Uint32: sqltype.Integer,
|
||||
reflect.Uint64: sqltype.BigInt,
|
||||
reflect.Uintptr: sqltype.BigInt,
|
||||
reflect.Float32: sqltype.Real,
|
||||
reflect.Float64: sqltype.DoublePrecision,
|
||||
reflect.Complex64: "",
|
||||
reflect.Complex128: "",
|
||||
reflect.Array: "",
|
||||
reflect.Interface: "",
|
||||
reflect.Map: sqltype.VarChar,
|
||||
reflect.Ptr: "",
|
||||
reflect.Slice: sqltype.VarChar,
|
||||
reflect.String: sqltype.VarChar,
|
||||
reflect.Struct: sqltype.VarChar,
|
||||
}
|
||||
|
||||
func DiscoverSQLType(typ reflect.Type) string {
|
||||
switch typ {
|
||||
case timeType, nullTimeType, bunNullTimeType:
|
||||
return sqltype.Timestamp
|
||||
case nullBoolType:
|
||||
return sqltype.Boolean
|
||||
case nullFloatType:
|
||||
return sqltype.DoublePrecision
|
||||
case nullIntType:
|
||||
return sqltype.BigInt
|
||||
case nullStringType:
|
||||
return sqltype.VarChar
|
||||
case jsonRawMessageType:
|
||||
return sqltype.JSON
|
||||
}
|
||||
|
||||
switch typ.Kind() {
|
||||
case reflect.Slice:
|
||||
if typ.Elem().Kind() == reflect.Uint8 {
|
||||
return sqltype.Blob
|
||||
}
|
||||
}
|
||||
|
||||
return sqlTypes[typ.Kind()]
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
var jsonNull = []byte("null")
|
||||
|
||||
// NullTime is a time.Time wrapper that marshals zero time as JSON null and SQL NULL.
|
||||
type NullTime struct {
|
||||
time.Time
|
||||
}
|
||||
|
||||
var (
|
||||
_ json.Marshaler = (*NullTime)(nil)
|
||||
_ json.Unmarshaler = (*NullTime)(nil)
|
||||
_ sql.Scanner = (*NullTime)(nil)
|
||||
_ QueryAppender = (*NullTime)(nil)
|
||||
)
|
||||
|
||||
func (tm NullTime) MarshalJSON() ([]byte, error) {
|
||||
if tm.IsZero() {
|
||||
return jsonNull, nil
|
||||
}
|
||||
return tm.Time.MarshalJSON()
|
||||
}
|
||||
|
||||
func (tm *NullTime) UnmarshalJSON(b []byte) error {
|
||||
if bytes.Equal(b, jsonNull) {
|
||||
tm.Time = time.Time{}
|
||||
return nil
|
||||
}
|
||||
return tm.Time.UnmarshalJSON(b)
|
||||
}
|
||||
|
||||
func (tm NullTime) AppendQuery(gen QueryGen, b []byte) ([]byte, error) {
|
||||
if tm.IsZero() {
|
||||
return dialect.AppendNull(b), nil
|
||||
}
|
||||
return gen.Dialect().AppendTime(b, tm.Time), nil
|
||||
}
|
||||
|
||||
func (tm *NullTime) Scan(src any) error {
|
||||
if src == nil {
|
||||
tm.Time = time.Time{}
|
||||
return nil
|
||||
}
|
||||
|
||||
switch src := src.(type) {
|
||||
case time.Time:
|
||||
tm.Time = src
|
||||
return nil
|
||||
case string:
|
||||
newtm, err := internal.ParseTime(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tm.Time = newtm
|
||||
return nil
|
||||
case []byte:
|
||||
newtm, err := internal.ParseTime(internal.String(src))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tm.Time = newtm
|
||||
return nil
|
||||
default:
|
||||
return scanError(bunNullTimeType, src)
|
||||
}
|
||||
}
|
||||
1130
vendor/github.com/uptrace/bun/schema/table.go
generated
vendored
Normal file
1130
vendor/github.com/uptrace/bun/schema/table.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
114
vendor/github.com/uptrace/bun/schema/tables.go
generated
vendored
Normal file
114
vendor/github.com/uptrace/bun/schema/tables.go
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"github.com/puzpuzpuz/xsync/v3"
|
||||
)
|
||||
|
||||
type Tables struct {
|
||||
dialect Dialect
|
||||
|
||||
mu sync.Mutex
|
||||
tables *xsync.MapOf[reflect.Type, *Table]
|
||||
|
||||
inProgress map[reflect.Type]*Table
|
||||
}
|
||||
|
||||
func NewTables(dialect Dialect) *Tables {
|
||||
return &Tables{
|
||||
dialect: dialect,
|
||||
tables: xsync.NewMapOf[reflect.Type, *Table](),
|
||||
inProgress: make(map[reflect.Type]*Table),
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tables) Register(models ...any) {
|
||||
for _, model := range models {
|
||||
_ = t.Get(reflect.TypeOf(model).Elem())
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tables) Get(typ reflect.Type) *Table {
|
||||
typ = indirectType(typ)
|
||||
if typ.Kind() != reflect.Struct {
|
||||
panic(fmt.Errorf("got %s, wanted %s", typ.Kind(), reflect.Struct))
|
||||
}
|
||||
|
||||
if v, ok := t.tables.Load(typ); ok {
|
||||
return v
|
||||
}
|
||||
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
if v, ok := t.tables.Load(typ); ok {
|
||||
return v
|
||||
}
|
||||
|
||||
table := t.InProgress(typ)
|
||||
table.initRelations()
|
||||
|
||||
t.dialect.OnTable(table)
|
||||
for _, field := range table.FieldMap {
|
||||
if field.UserSQLType == "" {
|
||||
field.UserSQLType = field.DiscoveredSQLType
|
||||
}
|
||||
if field.CreateTableSQLType == "" {
|
||||
field.CreateTableSQLType = field.UserSQLType
|
||||
}
|
||||
}
|
||||
|
||||
t.tables.Store(typ, table)
|
||||
return table
|
||||
}
|
||||
|
||||
func (t *Tables) InProgress(typ reflect.Type) *Table {
|
||||
if table, ok := t.inProgress[typ]; ok {
|
||||
return table
|
||||
}
|
||||
|
||||
table := new(Table)
|
||||
t.inProgress[typ] = table
|
||||
table.init(t.dialect, typ)
|
||||
|
||||
return table
|
||||
}
|
||||
|
||||
// ByModel gets the table by its Go name.
|
||||
func (t *Tables) ByModel(name string) *Table {
|
||||
var found *Table
|
||||
t.tables.Range(func(typ reflect.Type, table *Table) bool {
|
||||
if table.TypeName == name {
|
||||
found = table
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
return found
|
||||
}
|
||||
|
||||
// ByName gets the table by its SQL name.
|
||||
func (t *Tables) ByName(name string) *Table {
|
||||
var found *Table
|
||||
t.tables.Range(func(typ reflect.Type, table *Table) bool {
|
||||
if table.Name == name {
|
||||
found = table
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
return found
|
||||
}
|
||||
|
||||
// All returns all registered tables.
|
||||
func (t *Tables) All() []*Table {
|
||||
var found []*Table
|
||||
t.tables.Range(func(typ reflect.Type, table *Table) bool {
|
||||
found = append(found, table)
|
||||
return true
|
||||
})
|
||||
return found
|
||||
}
|
||||
161
vendor/github.com/uptrace/bun/schema/zerochecker.go
generated
vendored
Normal file
161
vendor/github.com/uptrace/bun/schema/zerochecker.go
generated
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var isZeroerType = reflect.TypeFor[isZeroer]()
|
||||
|
||||
type isZeroer interface {
|
||||
IsZero() bool
|
||||
}
|
||||
|
||||
func isZero(v any) bool {
|
||||
switch v := v.(type) {
|
||||
case isZeroer:
|
||||
return v.IsZero()
|
||||
case string:
|
||||
return v == ""
|
||||
case []byte:
|
||||
return v == nil
|
||||
case int:
|
||||
return v == 0
|
||||
case int64:
|
||||
return v == 0
|
||||
case uint:
|
||||
return v == 0
|
||||
case uint64:
|
||||
return v == 0
|
||||
case float32:
|
||||
return v == 0
|
||||
case float64:
|
||||
return v == 0
|
||||
case int8:
|
||||
return v == 0
|
||||
case int16:
|
||||
return v == 0
|
||||
case int32:
|
||||
return v == 0
|
||||
case uint8:
|
||||
return v == 0
|
||||
case uint16:
|
||||
return v == 0
|
||||
case uint32:
|
||||
return v == 0
|
||||
default:
|
||||
rv := reflect.ValueOf(v)
|
||||
fn := zeroChecker(rv.Type())
|
||||
return fn(rv)
|
||||
}
|
||||
}
|
||||
|
||||
type IsZeroerFunc func(reflect.Value) bool
|
||||
|
||||
func zeroChecker(typ reflect.Type) IsZeroerFunc {
|
||||
if typ.Implements(isZeroerType) {
|
||||
return isZeroInterface
|
||||
}
|
||||
|
||||
kind := typ.Kind()
|
||||
|
||||
if kind != reflect.Ptr {
|
||||
ptr := reflect.PointerTo(typ)
|
||||
if ptr.Implements(isZeroerType) {
|
||||
return addrChecker(isZeroInterface)
|
||||
}
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case reflect.Array:
|
||||
if typ.Elem().Kind() == reflect.Uint8 {
|
||||
return isZeroBytes
|
||||
}
|
||||
return isZeroLen
|
||||
case reflect.String:
|
||||
return isZeroLen
|
||||
case reflect.Bool:
|
||||
return isZeroBool
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return isZeroInt
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return isZeroUint
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return isZeroFloat
|
||||
case reflect.Interface, reflect.Ptr, reflect.Slice, reflect.Map:
|
||||
return isNil
|
||||
}
|
||||
|
||||
if typ.Implements(driverValuerType) {
|
||||
return isZeroDriverValue
|
||||
}
|
||||
|
||||
return notZero
|
||||
}
|
||||
|
||||
func addrChecker(fn IsZeroerFunc) IsZeroerFunc {
|
||||
return func(v reflect.Value) bool {
|
||||
if !v.CanAddr() {
|
||||
return false
|
||||
}
|
||||
return fn(v.Addr())
|
||||
}
|
||||
}
|
||||
|
||||
func isZeroInterface(v reflect.Value) bool {
|
||||
if v.Kind() == reflect.Ptr && v.IsNil() {
|
||||
return true
|
||||
}
|
||||
return v.Interface().(isZeroer).IsZero()
|
||||
}
|
||||
|
||||
func isZeroDriverValue(v reflect.Value) bool {
|
||||
if v.Kind() == reflect.Ptr {
|
||||
return v.IsNil()
|
||||
}
|
||||
|
||||
valuer := v.Interface().(driver.Valuer)
|
||||
value, err := valuer.Value()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return value == nil
|
||||
}
|
||||
|
||||
func isZeroLen(v reflect.Value) bool {
|
||||
return v.Len() == 0
|
||||
}
|
||||
|
||||
func isNil(v reflect.Value) bool {
|
||||
return v.IsNil()
|
||||
}
|
||||
|
||||
func isZeroBool(v reflect.Value) bool {
|
||||
return !v.Bool()
|
||||
}
|
||||
|
||||
func isZeroInt(v reflect.Value) bool {
|
||||
return v.Int() == 0
|
||||
}
|
||||
|
||||
func isZeroUint(v reflect.Value) bool {
|
||||
return v.Uint() == 0
|
||||
}
|
||||
|
||||
func isZeroFloat(v reflect.Value) bool {
|
||||
return v.Float() == 0
|
||||
}
|
||||
|
||||
func isZeroBytes(v reflect.Value) bool {
|
||||
b := v.Slice(0, v.Len()).Bytes()
|
||||
for _, c := range b {
|
||||
if c != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func notZero(v reflect.Value) bool {
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user