summaryrefslogtreecommitdiff
path: root/vendor/github.com/uptrace/bun/schema/append_value.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/uptrace/bun/schema/append_value.go')
-rw-r--r--vendor/github.com/uptrace/bun/schema/append_value.go237
1 files changed, 237 insertions, 0 deletions
diff --git a/vendor/github.com/uptrace/bun/schema/append_value.go b/vendor/github.com/uptrace/bun/schema/append_value.go
new file mode 100644
index 000000000..0c4677069
--- /dev/null
+++ b/vendor/github.com/uptrace/bun/schema/append_value.go
@@ -0,0 +1,237 @@
+package schema
+
+import (
+ "database/sql/driver"
+ "encoding/json"
+ "fmt"
+ "net"
+ "reflect"
+ "strconv"
+ "time"
+
+ "github.com/uptrace/bun/dialect"
+ "github.com/uptrace/bun/extra/bunjson"
+ "github.com/uptrace/bun/internal"
+)
+
+var (
+ timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
+ ipType = reflect.TypeOf((*net.IP)(nil)).Elem()
+ ipNetType = reflect.TypeOf((*net.IPNet)(nil)).Elem()
+ jsonRawMessageType = reflect.TypeOf((*json.RawMessage)(nil)).Elem()
+
+ driverValuerType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
+ queryAppenderType = reflect.TypeOf((*QueryAppender)(nil)).Elem()
+)
+
+type (
+ AppenderFunc func(fmter Formatter, 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: AppendUintValue,
+ reflect.Uint64: AppendUintValue,
+ 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,
+}
+
+func Appender(typ reflect.Type, custom CustomAppender) AppenderFunc {
+ switch typ {
+ case timeType:
+ return appendTimeValue
+ case ipType:
+ return appendIPValue
+ case ipNetType:
+ return appendIPNetValue
+ case jsonRawMessageType:
+ return appendJSONRawMessageValue
+ }
+
+ if typ.Implements(queryAppenderType) {
+ return appendQueryAppenderValue
+ }
+ if typ.Implements(driverValuerType) {
+ return driverValueAppender(custom)
+ }
+
+ kind := typ.Kind()
+
+ if kind != reflect.Ptr {
+ ptr := reflect.PtrTo(typ)
+ if ptr.Implements(queryAppenderType) {
+ return addrAppender(appendQueryAppenderValue, custom)
+ }
+ if ptr.Implements(driverValuerType) {
+ return addrAppender(driverValueAppender(custom), custom)
+ }
+ }
+
+ switch kind {
+ case reflect.Interface:
+ return ifaceAppenderFunc(typ, custom)
+ case reflect.Ptr:
+ return ptrAppenderFunc(typ, custom)
+ case reflect.Slice:
+ if typ.Elem().Kind() == reflect.Uint8 {
+ return appendBytesValue
+ }
+ case reflect.Array:
+ if typ.Elem().Kind() == reflect.Uint8 {
+ return appendArrayBytesValue
+ }
+ }
+
+ if custom != nil {
+ if fn := custom(typ); fn != nil {
+ return fn
+ }
+ }
+ return appenders[typ.Kind()]
+}
+
+func ifaceAppenderFunc(typ reflect.Type, custom func(reflect.Type) AppenderFunc) AppenderFunc {
+ return func(fmter Formatter, b []byte, v reflect.Value) []byte {
+ if v.IsNil() {
+ return dialect.AppendNull(b)
+ }
+ elem := v.Elem()
+ appender := Appender(elem.Type(), custom)
+ return appender(fmter, b, elem)
+ }
+}
+
+func ptrAppenderFunc(typ reflect.Type, custom func(reflect.Type) AppenderFunc) AppenderFunc {
+ appender := Appender(typ.Elem(), custom)
+ return func(fmter Formatter, b []byte, v reflect.Value) []byte {
+ if v.IsNil() {
+ return dialect.AppendNull(b)
+ }
+ return appender(fmter, b, v.Elem())
+ }
+}
+
+func AppendBoolValue(fmter Formatter, b []byte, v reflect.Value) []byte {
+ return dialect.AppendBool(b, v.Bool())
+}
+
+func AppendIntValue(fmter Formatter, b []byte, v reflect.Value) []byte {
+ return strconv.AppendInt(b, v.Int(), 10)
+}
+
+func AppendUintValue(fmter Formatter, b []byte, v reflect.Value) []byte {
+ return strconv.AppendUint(b, v.Uint(), 10)
+}
+
+func AppendFloat32Value(fmter Formatter, b []byte, v reflect.Value) []byte {
+ return dialect.AppendFloat32(b, float32(v.Float()))
+}
+
+func AppendFloat64Value(fmter Formatter, b []byte, v reflect.Value) []byte {
+ return dialect.AppendFloat64(b, float64(v.Float()))
+}
+
+func appendBytesValue(fmter Formatter, b []byte, v reflect.Value) []byte {
+ return dialect.AppendBytes(b, v.Bytes())
+}
+
+func appendArrayBytesValue(fmter Formatter, b []byte, v reflect.Value) []byte {
+ if v.CanAddr() {
+ return dialect.AppendBytes(b, v.Slice(0, v.Len()).Bytes())
+ }
+
+ tmp := make([]byte, v.Len())
+ reflect.Copy(reflect.ValueOf(tmp), v)
+ b = dialect.AppendBytes(b, tmp)
+ return b
+}
+
+func AppendStringValue(fmter Formatter, b []byte, v reflect.Value) []byte {
+ return dialect.AppendString(b, v.String())
+}
+
+func AppendJSONValue(fmter Formatter, 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 dialect.AppendJSON(b, bb)
+}
+
+func appendTimeValue(fmter Formatter, b []byte, v reflect.Value) []byte {
+ tm := v.Interface().(time.Time)
+ return dialect.AppendTime(b, tm)
+}
+
+func appendIPValue(fmter Formatter, b []byte, v reflect.Value) []byte {
+ ip := v.Interface().(net.IP)
+ return dialect.AppendString(b, ip.String())
+}
+
+func appendIPNetValue(fmter Formatter, b []byte, v reflect.Value) []byte {
+ ipnet := v.Interface().(net.IPNet)
+ return dialect.AppendString(b, ipnet.String())
+}
+
+func appendJSONRawMessageValue(fmter Formatter, b []byte, v reflect.Value) []byte {
+ bytes := v.Bytes()
+ if bytes == nil {
+ return dialect.AppendNull(b)
+ }
+ return dialect.AppendString(b, internal.String(bytes))
+}
+
+func appendQueryAppenderValue(fmter Formatter, b []byte, v reflect.Value) []byte {
+ return AppendQueryAppender(fmter, b, v.Interface().(QueryAppender))
+}
+
+func driverValueAppender(custom CustomAppender) AppenderFunc {
+ return func(fmter Formatter, b []byte, v reflect.Value) []byte {
+ return appendDriverValue(fmter, b, v.Interface().(driver.Valuer), custom)
+ }
+}
+
+func appendDriverValue(fmter Formatter, b []byte, v driver.Valuer, custom CustomAppender) []byte {
+ value, err := v.Value()
+ if err != nil {
+ return dialect.AppendError(b, err)
+ }
+ return Append(fmter, b, value, custom)
+}
+
+func addrAppender(fn AppenderFunc, custom CustomAppender) AppenderFunc {
+ return func(fmter Formatter, 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(fmter, b, v.Addr())
+ }
+}