float.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package null
  2. import (
  3. "database/sql"
  4. "encoding/json"
  5. "fmt"
  6. "math"
  7. "reflect"
  8. "strconv"
  9. )
  10. const (
  11. nullString = "null"
  12. )
  13. // Float is a nullable float64.
  14. // It does not consider zero values to be null.
  15. // It will decode to null, not zero, if null.
  16. type Float struct {
  17. sql.NullFloat64
  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. // FloatFrom creates a new Float that will always be valid.
  29. func FloatFrom(f float64) Float {
  30. return NewFloat(f, true)
  31. }
  32. // FloatFromPtr creates a new Float that be null if f is nil.
  33. func FloatFromPtr(f *float64) Float {
  34. if f == nil {
  35. return NewFloat(0, false)
  36. }
  37. return NewFloat(*f, true)
  38. }
  39. // FloatFromString creates a new Float from string f.
  40. // If the string is equal to the value of nullString then the Float will be null.
  41. // An empty string f will return an error.
  42. func FloatFromString(f string, nullString string) (Float, error) {
  43. if f == nullString {
  44. return FloatFromPtr(nil), nil
  45. }
  46. fV, err := strconv.ParseFloat(f, 64)
  47. if err != nil {
  48. return Float{}, err
  49. }
  50. return FloatFrom(fV), nil
  51. }
  52. // UnmarshalJSON implements json.Unmarshaler.
  53. // It supports number and null input.
  54. // 0 will not be considered a null Float.
  55. // It also supports unmarshalling a sql.NullFloat64.
  56. func (f *Float) UnmarshalJSON(data []byte) error {
  57. var err error
  58. var v interface{}
  59. if err = json.Unmarshal(data, &v); err != nil {
  60. return err
  61. }
  62. switch x := v.(type) {
  63. case float64:
  64. f.Float64 = x
  65. case map[string]interface{}:
  66. err = json.Unmarshal(data, &f.NullFloat64)
  67. case nil:
  68. f.Valid = false
  69. return nil
  70. default:
  71. err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Float", reflect.TypeOf(v).Name())
  72. }
  73. f.Valid = err == nil
  74. return err
  75. }
  76. // UnmarshalText implements encoding.TextUnmarshaler.
  77. // It will unmarshal to a null Float if the input is a blank or not an integer.
  78. // It will return an error if the input is not an integer, blank, or "null".
  79. func (f *Float) UnmarshalText(text []byte) error {
  80. str := string(text)
  81. if str == "" || str == nullString {
  82. f.Valid = false
  83. return nil
  84. }
  85. var err error
  86. f.Float64, err = strconv.ParseFloat(string(text), 64)
  87. f.Valid = err == nil
  88. return err
  89. }
  90. // MarshalJSON implements json.Marshaler.
  91. // It will encode null if this Float is null.
  92. func (f Float) MarshalJSON() ([]byte, error) {
  93. if !f.Valid || math.IsNaN(f.Float64) {
  94. return []byte(nullString), nil
  95. }
  96. return []byte(strconv.FormatFloat(f.Float64, 'f', -1, 64)), nil
  97. }
  98. // MarshalText implements encoding.TextMarshaler.
  99. // It will encode a blank string if this Float is null.
  100. func (f Float) MarshalText() ([]byte, error) {
  101. if !f.Valid {
  102. return []byte{}, nil
  103. }
  104. return []byte(strconv.FormatFloat(f.Float64, 'f', -1, 64)), nil
  105. }
  106. // MarshalText implements encoding.TextMarshaler.
  107. // It will encode a blank string if this Float is null.
  108. func (f Float) String() string {
  109. if !f.Valid {
  110. return nullString
  111. }
  112. return fmt.Sprintf("%1.3f", f.Float64)
  113. }
  114. // FullString returns float as string in full precision
  115. func (f Float) FullString() string {
  116. if !f.Valid {
  117. return nullString
  118. }
  119. return fmt.Sprintf("%f", f.Float64)
  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. // Ptr returns a pointer to this Float's value, or a nil pointer if this Float is null.
  127. func (f Float) Ptr() *float64 {
  128. if !f.Valid {
  129. return nil
  130. }
  131. return &f.Float64
  132. }
  133. // IsZero returns true for invalid Floats, for future omitempty support (Go 1.4?)
  134. // A non-null Float with a 0 value will not be considered zero.
  135. func (f Float) IsZero() bool {
  136. return !f.Valid
  137. }