11package null
22
33import (
4+ "bytes"
45 "database/sql"
56 "encoding/json"
7+ "errors"
68 "fmt"
7- "reflect"
89 "strconv"
910)
1011
@@ -47,40 +48,42 @@ func (i Int) ValueOrZero() int64 {
4748}
4849
4950// UnmarshalJSON implements json.Unmarshaler.
50- // It supports number and null input.
51+ // It supports number, string, and null input.
5152// 0 will not be considered a null Int.
52- // It also supports unmarshalling a sql.NullInt64.
5353func (i * Int ) UnmarshalJSON (data []byte ) error {
54- var err error
55- var v interface {}
56- if err = json .Unmarshal (data , & v ); err != nil {
57- return err
54+ if bytes .Equal (data , nullBytes ) {
55+ i .Valid = false
56+ return nil
5857 }
59- switch x := v .(type ) {
60- case float64 :
61- // Unmarshal again, directly to int64, to avoid intermediate float64
62- err = json .Unmarshal (data , & i .Int64 )
63- case string :
64- str := string (x )
65- if len (str ) == 0 {
66- i .Valid = false
58+
59+ if err := json .Unmarshal (data , & i .Int64 ); err != nil {
60+ var typeError * json.UnmarshalTypeError
61+ if errors .As (err , & typeError ) {
62+ // special case: accept string input
63+ if typeError .Value != "string" {
64+ return fmt .Errorf ("null: JSON input is invalid type (need int or string): %w" , err )
65+ }
66+ var str string
67+ if err := json .Unmarshal (data , & str ); err != nil {
68+ return fmt .Errorf ("null: couldn't unmarshal number string: %w" , err )
69+ }
70+ n , err := strconv .ParseInt (str , 10 , 64 )
71+ if err != nil {
72+ return fmt .Errorf ("null: couldn't convert string to int: %w" , err )
73+ }
74+ i .Int64 = n
75+ i .Valid = true
6776 return nil
6877 }
69- i .Int64 , err = strconv .ParseInt (str , 10 , 64 )
70- case map [string ]interface {}:
71- err = json .Unmarshal (data , & i .NullInt64 )
72- case nil :
73- i .Valid = false
74- return nil
75- default :
76- err = fmt .Errorf ("json: cannot unmarshal %v into Go value of type null.Int" , reflect .TypeOf (v ).Name ())
78+ return fmt .Errorf ("null: couldn't unmarshal JSON: %w" , err )
7779 }
78- i .Valid = err == nil
79- return err
80+
81+ i .Valid = true
82+ return nil
8083}
8184
8285// UnmarshalText implements encoding.TextUnmarshaler.
83- // It will unmarshal to a null Int if the input is a blank or not an integer .
86+ // It will unmarshal to a null Int if the input is blank.
8487// It will return an error if the input is not an integer, blank, or "null".
8588func (i * Int ) UnmarshalText (text []byte ) error {
8689 str := string (text )
@@ -90,8 +93,11 @@ func (i *Int) UnmarshalText(text []byte) error {
9093 }
9194 var err error
9295 i .Int64 , err = strconv .ParseInt (string (text ), 10 , 64 )
93- i .Valid = err == nil
94- return err
96+ if err != nil {
97+ return fmt .Errorf ("null: couldn't unmarshal text: %w" , err )
98+ }
99+ i .Valid = true
100+ return nil
95101}
96102
97103// MarshalJSON implements json.Marshaler.
0 commit comments