github.com/go-playground/pkg/v5@v5.29.1/values/option/option_sql_go1.22.go (about) 1 //go:build go1.22 2 3 package optionext 4 5 import ( 6 "database/sql" 7 "database/sql/driver" 8 "encoding/json" 9 "fmt" 10 "math" 11 "reflect" 12 "time" 13 ) 14 15 var ( 16 scanType = reflect.TypeFor[sql.Scanner]() 17 valuerType = reflect.TypeFor[driver.Valuer]() 18 byteSliceType = reflect.TypeFor[[]byte]() 19 timeType = reflect.TypeFor[time.Time]() 20 stringType = reflect.TypeFor[string]() 21 int64Type = reflect.TypeFor[int64]() 22 float64Type = reflect.TypeFor[float64]() 23 boolType = reflect.TypeFor[bool]() 24 ) 25 26 // Value implements the driver.Valuer interface. 27 // 28 // This honours the `driver.Valuer` interface if the value implements it. 29 // It also supports custom types of the std types and treats all else as []byte 30 func (o Option[T]) Value() (driver.Value, error) { 31 if o.IsNone() { 32 return nil, nil 33 } 34 val := reflect.ValueOf(o.value) 35 36 if val.Type().Implements(valuerType) { 37 return val.Interface().(driver.Valuer).Value() 38 } 39 switch val.Kind() { 40 case reflect.String: 41 return val.Convert(stringType).Interface(), nil 42 case reflect.Bool: 43 return val.Convert(boolType).Interface(), nil 44 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 45 return val.Convert(int64Type).Interface(), nil 46 case reflect.Float64: 47 return val.Convert(float64Type).Interface(), nil 48 case reflect.Slice, reflect.Array: 49 if val.Type().ConvertibleTo(byteSliceType) { 50 return val.Convert(byteSliceType).Interface(), nil 51 } 52 return json.Marshal(val.Interface()) 53 case reflect.Struct: 54 if val.CanConvert(timeType) { 55 return val.Convert(timeType).Interface(), nil 56 } 57 return json.Marshal(val.Interface()) 58 case reflect.Map: 59 return json.Marshal(val.Interface()) 60 default: 61 return o.value, nil 62 } 63 } 64 65 // Scan implements the sql.Scanner interface. 66 func (o *Option[T]) Scan(value any) error { 67 68 if value == nil { 69 *o = None[T]() 70 return nil 71 } 72 73 val := reflect.ValueOf(&o.value) 74 75 if val.Type().Implements(scanType) { 76 err := val.Interface().(sql.Scanner).Scan(value) 77 if err != nil { 78 return err 79 } 80 o.isSome = true 81 return nil 82 } 83 84 val = val.Elem() 85 86 switch val.Kind() { 87 case reflect.String, reflect.Bool, reflect.Uint8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float64: 88 var v sql.Null[T] 89 if err := v.Scan(value); err != nil { 90 return err 91 } 92 *o = Some(reflect.ValueOf(v.V).Convert(val.Type()).Interface().(T)) 93 case reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: 94 v := reflect.ValueOf(value) 95 if v.Type().ConvertibleTo(val.Type()) { 96 *o = Some(reflect.ValueOf(v.Convert(val.Type()).Interface()).Interface().(T)) 97 } else { 98 return fmt.Errorf("value %T not convertable to %T", value, o.value) 99 } 100 case reflect.Float32: 101 var v sql.Null[float64] 102 if err := v.Scan(value); err != nil { 103 return err 104 } 105 *o = Some(reflect.ValueOf(v.V).Convert(val.Type()).Interface().(T)) 106 case reflect.Int: 107 var v sql.Null[int64] 108 if err := v.Scan(value); err != nil { 109 return err 110 } 111 if v.V > math.MaxInt || v.V < math.MinInt { 112 return fmt.Errorf("value %d out of range for int", v.V) 113 } 114 *o = Some(reflect.ValueOf(v.V).Convert(val.Type()).Interface().(T)) 115 case reflect.Int8: 116 var v sql.Null[int64] 117 if err := v.Scan(value); err != nil { 118 return err 119 } 120 if v.V > math.MaxInt8 || v.V < math.MinInt8 { 121 return fmt.Errorf("value %d out of range for int8", v.V) 122 } 123 *o = Some(reflect.ValueOf(v.V).Convert(val.Type()).Interface().(T)) 124 case reflect.Interface: 125 *o = Some(reflect.ValueOf(value).Convert(val.Type()).Interface().(T)) 126 case reflect.Struct: 127 if val.CanConvert(timeType) { 128 switch t := value.(type) { 129 case string: 130 tm, err := time.Parse(time.RFC3339Nano, t) 131 if err != nil { 132 return err 133 } 134 *o = Some(reflect.ValueOf(tm).Convert(val.Type()).Interface().(T)) 135 136 case []byte: 137 tm, err := time.Parse(time.RFC3339Nano, string(t)) 138 if err != nil { 139 return err 140 } 141 *o = Some(reflect.ValueOf(tm).Convert(val.Type()).Interface().(T)) 142 143 default: 144 var v sql.Null[time.Time] 145 if err := v.Scan(value); err != nil { 146 return err 147 } 148 *o = Some(reflect.ValueOf(v.V).Convert(val.Type()).Interface().(T)) 149 } 150 return nil 151 } 152 fallthrough 153 154 default: 155 switch val.Kind() { 156 case reflect.Struct, reflect.Slice, reflect.Map: 157 v := reflect.ValueOf(value) 158 159 if v.Type().ConvertibleTo(byteSliceType) { 160 if val.Kind() == reflect.Slice && val.Type().Elem().Kind() == reflect.Uint8 { 161 *o = Some(reflect.ValueOf(v.Convert(val.Type()).Interface()).Interface().(T)) 162 } else { 163 if err := json.Unmarshal(v.Convert(byteSliceType).Interface().([]byte), &o.value); err != nil { 164 return err 165 } 166 } 167 o.isSome = true 168 return nil 169 } 170 } 171 return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", value, o.value) 172 } 173 return nil 174 }