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 }