gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

append_value.go (8161B)


      1 package schema
      2 
      3 import (
      4 	"database/sql/driver"
      5 	"fmt"
      6 	"net"
      7 	"reflect"
      8 	"strconv"
      9 	"strings"
     10 	"sync"
     11 	"time"
     12 
     13 	"github.com/uptrace/bun/dialect"
     14 	"github.com/uptrace/bun/dialect/sqltype"
     15 	"github.com/uptrace/bun/extra/bunjson"
     16 	"github.com/uptrace/bun/internal"
     17 	"github.com/vmihailenco/msgpack/v5"
     18 )
     19 
     20 type (
     21 	AppenderFunc   func(fmter Formatter, b []byte, v reflect.Value) []byte
     22 	CustomAppender func(typ reflect.Type) AppenderFunc
     23 )
     24 
     25 var appenders = []AppenderFunc{
     26 	reflect.Bool:          AppendBoolValue,
     27 	reflect.Int:           AppendIntValue,
     28 	reflect.Int8:          AppendIntValue,
     29 	reflect.Int16:         AppendIntValue,
     30 	reflect.Int32:         AppendIntValue,
     31 	reflect.Int64:         AppendIntValue,
     32 	reflect.Uint:          AppendUintValue,
     33 	reflect.Uint8:         AppendUintValue,
     34 	reflect.Uint16:        AppendUintValue,
     35 	reflect.Uint32:        appendUint32Value,
     36 	reflect.Uint64:        appendUint64Value,
     37 	reflect.Uintptr:       nil,
     38 	reflect.Float32:       AppendFloat32Value,
     39 	reflect.Float64:       AppendFloat64Value,
     40 	reflect.Complex64:     nil,
     41 	reflect.Complex128:    nil,
     42 	reflect.Array:         AppendJSONValue,
     43 	reflect.Chan:          nil,
     44 	reflect.Func:          nil,
     45 	reflect.Interface:     nil,
     46 	reflect.Map:           AppendJSONValue,
     47 	reflect.Ptr:           nil,
     48 	reflect.Slice:         AppendJSONValue,
     49 	reflect.String:        AppendStringValue,
     50 	reflect.Struct:        AppendJSONValue,
     51 	reflect.UnsafePointer: nil,
     52 }
     53 
     54 var appenderMap sync.Map
     55 
     56 func FieldAppender(dialect Dialect, field *Field) AppenderFunc {
     57 	if field.Tag.HasOption("msgpack") {
     58 		return appendMsgpack
     59 	}
     60 
     61 	fieldType := field.StructField.Type
     62 
     63 	switch strings.ToUpper(field.UserSQLType) {
     64 	case sqltype.JSON, sqltype.JSONB:
     65 		if fieldType.Implements(driverValuerType) {
     66 			return appendDriverValue
     67 		}
     68 
     69 		if fieldType.Kind() != reflect.Ptr {
     70 			if reflect.PtrTo(fieldType).Implements(driverValuerType) {
     71 				return addrAppender(appendDriverValue)
     72 			}
     73 		}
     74 
     75 		return AppendJSONValue
     76 	}
     77 
     78 	return Appender(dialect, fieldType)
     79 }
     80 
     81 func Appender(dialect Dialect, typ reflect.Type) AppenderFunc {
     82 	if v, ok := appenderMap.Load(typ); ok {
     83 		return v.(AppenderFunc)
     84 	}
     85 
     86 	fn := appender(dialect, typ)
     87 
     88 	if v, ok := appenderMap.LoadOrStore(typ, fn); ok {
     89 		return v.(AppenderFunc)
     90 	}
     91 	return fn
     92 }
     93 
     94 func appender(dialect Dialect, typ reflect.Type) AppenderFunc {
     95 	switch typ {
     96 	case bytesType:
     97 		return appendBytesValue
     98 	case timeType:
     99 		return appendTimeValue
    100 	case timePtrType:
    101 		return PtrAppender(appendTimeValue)
    102 	case ipType:
    103 		return appendIPValue
    104 	case ipNetType:
    105 		return appendIPNetValue
    106 	case jsonRawMessageType:
    107 		return appendJSONRawMessageValue
    108 	}
    109 
    110 	kind := typ.Kind()
    111 
    112 	if typ.Implements(queryAppenderType) {
    113 		if kind == reflect.Ptr {
    114 			return nilAwareAppender(appendQueryAppenderValue)
    115 		}
    116 		return appendQueryAppenderValue
    117 	}
    118 	if typ.Implements(driverValuerType) {
    119 		if kind == reflect.Ptr {
    120 			return nilAwareAppender(appendDriverValue)
    121 		}
    122 		return appendDriverValue
    123 	}
    124 
    125 	if kind != reflect.Ptr {
    126 		ptr := reflect.PtrTo(typ)
    127 		if ptr.Implements(queryAppenderType) {
    128 			return addrAppender(appendQueryAppenderValue)
    129 		}
    130 		if ptr.Implements(driverValuerType) {
    131 			return addrAppender(appendDriverValue)
    132 		}
    133 	}
    134 
    135 	switch kind {
    136 	case reflect.Interface:
    137 		return ifaceAppenderFunc
    138 	case reflect.Ptr:
    139 		if typ.Implements(jsonMarshalerType) {
    140 			return nilAwareAppender(AppendJSONValue)
    141 		}
    142 		if fn := Appender(dialect, typ.Elem()); fn != nil {
    143 			return PtrAppender(fn)
    144 		}
    145 	case reflect.Slice:
    146 		if typ.Elem().Kind() == reflect.Uint8 {
    147 			return appendBytesValue
    148 		}
    149 	case reflect.Array:
    150 		if typ.Elem().Kind() == reflect.Uint8 {
    151 			return appendArrayBytesValue
    152 		}
    153 	}
    154 
    155 	return appenders[typ.Kind()]
    156 }
    157 
    158 func ifaceAppenderFunc(fmter Formatter, b []byte, v reflect.Value) []byte {
    159 	if v.IsNil() {
    160 		return dialect.AppendNull(b)
    161 	}
    162 	elem := v.Elem()
    163 	appender := Appender(fmter.Dialect(), elem.Type())
    164 	return appender(fmter, b, elem)
    165 }
    166 
    167 func nilAwareAppender(fn AppenderFunc) AppenderFunc {
    168 	return func(fmter Formatter, b []byte, v reflect.Value) []byte {
    169 		if v.IsNil() {
    170 			return dialect.AppendNull(b)
    171 		}
    172 		return fn(fmter, b, v)
    173 	}
    174 }
    175 
    176 func PtrAppender(fn AppenderFunc) AppenderFunc {
    177 	return func(fmter Formatter, b []byte, v reflect.Value) []byte {
    178 		if v.IsNil() {
    179 			return dialect.AppendNull(b)
    180 		}
    181 		return fn(fmter, b, v.Elem())
    182 	}
    183 }
    184 
    185 func AppendBoolValue(fmter Formatter, b []byte, v reflect.Value) []byte {
    186 	return fmter.Dialect().AppendBool(b, v.Bool())
    187 }
    188 
    189 func AppendIntValue(fmter Formatter, b []byte, v reflect.Value) []byte {
    190 	return strconv.AppendInt(b, v.Int(), 10)
    191 }
    192 
    193 func AppendUintValue(fmter Formatter, b []byte, v reflect.Value) []byte {
    194 	return strconv.AppendUint(b, v.Uint(), 10)
    195 }
    196 
    197 func appendUint32Value(fmter Formatter, b []byte, v reflect.Value) []byte {
    198 	return fmter.Dialect().AppendUint32(b, uint32(v.Uint()))
    199 }
    200 
    201 func appendUint64Value(fmter Formatter, b []byte, v reflect.Value) []byte {
    202 	return fmter.Dialect().AppendUint64(b, v.Uint())
    203 }
    204 
    205 func AppendFloat32Value(fmter Formatter, b []byte, v reflect.Value) []byte {
    206 	return dialect.AppendFloat32(b, float32(v.Float()))
    207 }
    208 
    209 func AppendFloat64Value(fmter Formatter, b []byte, v reflect.Value) []byte {
    210 	return dialect.AppendFloat64(b, float64(v.Float()))
    211 }
    212 
    213 func appendBytesValue(fmter Formatter, b []byte, v reflect.Value) []byte {
    214 	return fmter.Dialect().AppendBytes(b, v.Bytes())
    215 }
    216 
    217 func appendArrayBytesValue(fmter Formatter, b []byte, v reflect.Value) []byte {
    218 	if v.CanAddr() {
    219 		return fmter.Dialect().AppendBytes(b, v.Slice(0, v.Len()).Bytes())
    220 	}
    221 
    222 	tmp := make([]byte, v.Len())
    223 	reflect.Copy(reflect.ValueOf(tmp), v)
    224 	b = fmter.Dialect().AppendBytes(b, tmp)
    225 	return b
    226 }
    227 
    228 func AppendStringValue(fmter Formatter, b []byte, v reflect.Value) []byte {
    229 	return fmter.Dialect().AppendString(b, v.String())
    230 }
    231 
    232 func AppendJSONValue(fmter Formatter, b []byte, v reflect.Value) []byte {
    233 	bb, err := bunjson.Marshal(v.Interface())
    234 	if err != nil {
    235 		return dialect.AppendError(b, err)
    236 	}
    237 
    238 	if len(bb) > 0 && bb[len(bb)-1] == '\n' {
    239 		bb = bb[:len(bb)-1]
    240 	}
    241 
    242 	return fmter.Dialect().AppendJSON(b, bb)
    243 }
    244 
    245 func appendTimeValue(fmter Formatter, b []byte, v reflect.Value) []byte {
    246 	tm := v.Interface().(time.Time)
    247 	return fmter.Dialect().AppendTime(b, tm)
    248 }
    249 
    250 func appendIPValue(fmter Formatter, b []byte, v reflect.Value) []byte {
    251 	ip := v.Interface().(net.IP)
    252 	return fmter.Dialect().AppendString(b, ip.String())
    253 }
    254 
    255 func appendIPNetValue(fmter Formatter, b []byte, v reflect.Value) []byte {
    256 	ipnet := v.Interface().(net.IPNet)
    257 	return fmter.Dialect().AppendString(b, ipnet.String())
    258 }
    259 
    260 func appendJSONRawMessageValue(fmter Formatter, b []byte, v reflect.Value) []byte {
    261 	bytes := v.Bytes()
    262 	if bytes == nil {
    263 		return dialect.AppendNull(b)
    264 	}
    265 	return fmter.Dialect().AppendString(b, internal.String(bytes))
    266 }
    267 
    268 func appendQueryAppenderValue(fmter Formatter, b []byte, v reflect.Value) []byte {
    269 	return AppendQueryAppender(fmter, b, v.Interface().(QueryAppender))
    270 }
    271 
    272 func appendDriverValue(fmter Formatter, b []byte, v reflect.Value) []byte {
    273 	value, err := v.Interface().(driver.Valuer).Value()
    274 	if err != nil {
    275 		return dialect.AppendError(b, err)
    276 	}
    277 	if _, ok := value.(driver.Valuer); ok {
    278 		return dialect.AppendError(b, fmt.Errorf("driver.Valuer returns unsupported type %T", value))
    279 	}
    280 	return Append(fmter, b, value)
    281 }
    282 
    283 func addrAppender(fn AppenderFunc) AppenderFunc {
    284 	return func(fmter Formatter, b []byte, v reflect.Value) []byte {
    285 		if !v.CanAddr() {
    286 			err := fmt.Errorf("bun: Append(nonaddressable %T)", v.Interface())
    287 			return dialect.AppendError(b, err)
    288 		}
    289 		return fn(fmter, b, v.Addr())
    290 	}
    291 }
    292 
    293 func appendMsgpack(fmter Formatter, b []byte, v reflect.Value) []byte {
    294 	hexEnc := internal.NewHexEncoder(b)
    295 
    296 	enc := msgpack.GetEncoder()
    297 	defer msgpack.PutEncoder(enc)
    298 
    299 	enc.Reset(hexEnc)
    300 	if err := enc.EncodeValue(v); err != nil {
    301 		return dialect.AppendError(b, err)
    302 	}
    303 
    304 	if err := hexEnc.Close(); err != nil {
    305 		return dialect.AppendError(b, err)
    306 	}
    307 
    308 	return hexEnc.Bytes()
    309 }
    310 
    311 func AppendQueryAppender(fmter Formatter, b []byte, app QueryAppender) []byte {
    312 	bb, err := app.AppendQuery(fmter, b)
    313 	if err != nil {
    314 		return dialect.AppendError(b, err)
    315 	}
    316 	return bb
    317 }