github.com/seeker-insurance/kit@v0.0.13/db/null/zero/float.go (about) 1 package zero 2 3 import ( 4 "database/sql" 5 "encoding/json" 6 "fmt" 7 "math" 8 "reflect" 9 "strconv" 10 ) 11 12 // Float is a nullable float64. Zero input will be considered null. 13 // JSON marshals to zero if null. 14 // Considered null to SQL if zero. 15 type Float struct { 16 sql.NullFloat64 17 } 18 19 // NewFloat creates a new Float 20 func NewFloat(f float64, valid bool) Float { 21 return Float{ 22 NullFloat64: sql.NullFloat64{ 23 Float64: f, 24 Valid: valid, 25 }, 26 } 27 } 28 29 // FloatFrom creates a new Float that will be null if zero. 30 func FloatFrom(f float64) Float { 31 return NewFloat(f, f != 0) 32 } 33 34 // FloatFromPtr creates a new Float that be null if f is nil. 35 func FloatFromPtr(f *float64) Float { 36 if f == nil { 37 return NewFloat(0, false) 38 } 39 return NewFloat(*f, true) 40 } 41 42 // UnmarshalJSON implements json.Unmarshaler. 43 // It supports number and null input. 44 // 0 will be considered a null Float. 45 // It also supports unmarshalling a sql.NullFloat64. 46 func (f *Float) UnmarshalJSON(data []byte) error { 47 var err error 48 var v interface{} 49 if err = json.Unmarshal(data, &v); err != nil { 50 return err 51 } 52 switch x := v.(type) { 53 case float64: 54 f.Float64 = x 55 case string: 56 str := string(x) 57 if len(str) == 0 { 58 f.Valid = false 59 return nil 60 } 61 f.Float64, err = strconv.ParseFloat(str, 64) 62 case map[string]interface{}: 63 err = json.Unmarshal(data, &f.NullFloat64) 64 case nil: 65 f.Valid = false 66 return nil 67 default: 68 err = fmt.Errorf("json: cannot unmarshal %v into Go value of type zero.Float", reflect.TypeOf(v).Name()) 69 } 70 f.Valid = (err == nil) && (f.Float64 != 0) 71 return err 72 } 73 74 // UnmarshalText implements encoding.TextUnmarshaler. 75 // It will unmarshal to a null Float if the input is a blank, zero, or not a float. 76 // It will return an error if the input is not a float, blank, or "null". 77 func (f *Float) UnmarshalText(text []byte) error { 78 str := string(text) 79 if str == "" || str == "null" { 80 f.Valid = false 81 return nil 82 } 83 var err error 84 f.Float64, err = strconv.ParseFloat(string(text), 64) 85 f.Valid = (err == nil) && (f.Float64 != 0) 86 return err 87 } 88 89 // MarshalJSON implements json.Marshaler. 90 // It will encode null if this Float is null. 91 func (f Float) MarshalJSON() ([]byte, error) { 92 n := f.Float64 93 if !f.Valid { 94 n = 0 95 } 96 if math.IsInf(f.Float64, 0) || math.IsNaN(f.Float64) { 97 return nil, &json.UnsupportedValueError{ 98 Value: reflect.ValueOf(f.Float64), 99 Str: strconv.FormatFloat(f.Float64, 'g', -1, 64), 100 } 101 } 102 return []byte(strconv.FormatFloat(n, 'f', -1, 64)), nil 103 } 104 105 // MarshalText implements encoding.TextMarshaler. 106 // It will encode a zero if this Float is null. 107 func (f Float) MarshalText() ([]byte, error) { 108 n := f.Float64 109 if !f.Valid { 110 n = 0 111 } 112 return []byte(strconv.FormatFloat(n, 'f', -1, 64)), nil 113 } 114 115 // SetValid changes this Float's value and also sets it to be non-null. 116 func (f *Float) SetValid(v float64) { 117 f.Float64 = v 118 f.Valid = true 119 } 120 121 // Ptr returns a poFloater to this Float's value, or a nil poFloater if this Float is null. 122 func (f Float) Ptr() *float64 { 123 if !f.Valid { 124 return nil 125 } 126 return &f.Float64 127 } 128 129 // IsZero returns true for null or zero Floats, for future omitempty support (Go 1.4?) 130 func (f Float) IsZero() bool { 131 return !f.Valid || f.Float64 == 0 132 }