github.com/seeker-insurance/kit@v0.0.13/db/null/float.go (about) 1 package null 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. 13 // It does not consider zero values to be null. 14 // It will decode to null, not zero, if null. 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 always be valid. 30 func FloatFrom(f float64) Float { 31 return NewFloat(f, true) 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 // ValueOrZero returns the inner value if valid, otherwise zero. 43 func (f Float) ValueOrZero() float64 { 44 if !f.Valid { 45 return 0 46 } 47 return f.Float64 48 } 49 50 // UnmarshalJSON implements json.Unmarshaler. 51 // It supports number and null input. 52 // 0 will not be considered a null Float. 53 // It also supports unmarshalling a sql.NullFloat64. 54 func (f *Float) UnmarshalJSON(data []byte) error { 55 var err error 56 var v interface{} 57 if err = json.Unmarshal(data, &v); err != nil { 58 return err 59 } 60 switch x := v.(type) { 61 case float64: 62 f.Float64 = float64(x) 63 case string: 64 str := string(x) 65 if len(str) == 0 { 66 f.Valid = false 67 return nil 68 } 69 f.Float64, err = strconv.ParseFloat(str, 64) 70 case map[string]interface{}: 71 err = json.Unmarshal(data, &f.NullFloat64) 72 case nil: 73 f.Valid = false 74 return nil 75 default: 76 err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Float", reflect.TypeOf(v).Name()) 77 } 78 f.Valid = err == nil 79 return err 80 } 81 82 // UnmarshalText implements encoding.TextUnmarshaler. 83 // It will unmarshal to a null Float if the input is a blank or not an integer. 84 // It will return an error if the input is not an integer, blank, or "null". 85 func (f *Float) UnmarshalText(text []byte) error { 86 str := string(text) 87 if str == "" || str == "null" { 88 f.Valid = false 89 return nil 90 } 91 var err error 92 f.Float64, err = strconv.ParseFloat(string(text), 64) 93 f.Valid = err == nil 94 return err 95 } 96 97 // MarshalJSON implements json.Marshaler. 98 // It will encode null if this Float is null. 99 func (f Float) MarshalJSON() ([]byte, error) { 100 if !f.Valid { 101 return []byte("null"), nil 102 } 103 if math.IsInf(f.Float64, 0) || math.IsNaN(f.Float64) { 104 return nil, &json.UnsupportedValueError{ 105 Value: reflect.ValueOf(f.Float64), 106 Str: strconv.FormatFloat(f.Float64, 'g', -1, 64), 107 } 108 } 109 return []byte(strconv.FormatFloat(f.Float64, 'f', -1, 64)), nil 110 } 111 112 // MarshalText implements encoding.TextMarshaler. 113 // It will encode a blank string if this Float is null. 114 func (f Float) MarshalText() ([]byte, error) { 115 if !f.Valid { 116 return []byte{}, nil 117 } 118 return []byte(strconv.FormatFloat(f.Float64, 'f', -1, 64)), nil 119 } 120 121 // SetValid changes this Float's value and also sets it to be non-null. 122 func (f *Float) SetValid(n float64) { 123 f.Float64 = n 124 f.Valid = true 125 } 126 127 // Ptr returns a pointer to this Float's value, or a nil pointer if this Float is null. 128 func (f Float) Ptr() *float64 { 129 if !f.Valid { 130 return nil 131 } 132 return &f.Float64 133 } 134 135 // IsZero returns true for invalid Floats, for future omitempty support (Go 1.4?) 136 // A non-null Float with a 0 value will not be considered zero. 137 func (f Float) IsZero() bool { 138 return !f.Valid 139 }