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  }