Vendor packages update
This commit is contained in:
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())
|
||||
}
|
||||
Reference in New Issue
Block a user