github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/sqx/daonull.go (about) 1 package sqx 2 3 import ( 4 "database/sql" 5 "fmt" 6 "reflect" 7 8 "github.com/bingoohuang/gg/pkg/reflector" 9 ) 10 11 // NullAny represents any that may be null. 12 // NullAny implements the Scanner interface so it can be used as a scan destination. 13 type NullAny struct { 14 Type reflect.Type 15 Val reflect.Value 16 } 17 18 // Scan assigns a value from a database driver. 19 // 20 // The src value will be of one of the following types: 21 // 22 // int64 23 // float64 24 // bool 25 // []byte 26 // string 27 // time.Time 28 // nil - for NULL values 29 // 30 // An error should be returned if the value cannot be stored 31 // without loss of information. 32 // 33 // Reference types such as []byte are only valid until the next call to Scan 34 // and should not be retained. Their underlying memory is owned by the driver. 35 // If retention is necessary, copy their values before the next call to Scan. 36 func (n *NullAny) Scan(value interface{}) error { 37 if value == nil { 38 return nil 39 } 40 41 var err error 42 n.Val = reflect.ValueOf(value) 43 if converter, ok := CustomDriverValueConverters[n.Val.Type()]; ok { 44 value, err = converter.Convert(value) 45 if err != nil { 46 return err 47 } 48 n.Val = reflect.ValueOf(value) 49 } 50 51 if n.Type == nil { 52 return nil 53 } 54 55 switch n.Type.Kind() { 56 case reflect.String: 57 sn := &sql.NullString{} 58 if err := sn.Scan(value); err != nil { 59 return err 60 } 61 62 n.Val = reflect.ValueOf(sn.String).Convert(n.Type) 63 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, 64 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32: 65 sn := &sql.NullInt32{} 66 if err := sn.Scan(value); err != nil { 67 return err 68 } 69 n.Val = reflect.ValueOf(sn.Int32).Convert(n.Type) 70 case reflect.Int64, reflect.Uint64: 71 sn := &sql.NullInt64{} 72 if err := sn.Scan(value); err != nil { 73 return err 74 } 75 n.Val = reflect.ValueOf(sn.Int64).Convert(n.Type) 76 case reflect.Float32, reflect.Float64: 77 sn := &sql.NullFloat64{} 78 if err := sn.Scan(value); err != nil { 79 return err 80 } 81 82 n.Val = reflect.ValueOf(sn.Float64).Convert(n.Type) 83 case reflect.Bool: 84 sn := &sql.NullBool{} 85 if err := sn.Scan(value); err != nil { 86 return err 87 } 88 89 n.Val = reflect.ValueOf(sn.Bool).Convert(n.Type) 90 case reflect.Interface: 91 n.Val = n.Val.Convert(n.Type) 92 default: 93 if n.Type == reflector.TimeType || reflector.TimeType.ConvertibleTo(n.Type) { 94 sn := &sql.NullTime{} 95 if err := sn.Scan(value); err != nil { 96 return err 97 } 98 99 n.Val = reflect.ValueOf(sn.Time).Convert(n.Type) 100 } else { 101 sn := &sql.NullString{} 102 if err := sn.Scan(value); err != nil { 103 return err 104 } 105 106 n.Val = reflect.ValueOf(sn.String).Convert(n.Type) 107 } 108 } 109 110 return nil 111 } 112 113 func (n *NullAny) Get() interface{} { 114 if n.Val.IsValid() { 115 i := n.Val.Interface() 116 if s, ok := i.([]byte); ok { 117 return string(s) 118 } 119 120 return i 121 } 122 123 return nil 124 } 125 126 func (n *NullAny) GetVal() reflect.Value { 127 if n.Type == nil { 128 return reflect.Value{} 129 } 130 131 if n.Val.IsValid() { 132 return n.Val 133 } 134 135 return reflect.New(n.Type).Elem() 136 } 137 138 func (n *NullAny) String() string { 139 if n.Val.IsValid() { 140 i := n.Val.Interface() 141 if iv, ok := i.([]byte); ok { 142 return string(iv) 143 } 144 return fmt.Sprintf("%v", i) 145 } 146 147 return "" 148 } 149 150 func (n *NullAny) Valid() bool { 151 return n.Val.IsValid() 152 }