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  }