github.com/seeker-insurance/kit@v0.0.13/db/null/string.go (about)

     1  // Package null contains SQL types that consider zero input and null input as separate values,
     2  // with convenient support for JSON and text marshaling.
     3  // Types in this package will always encode to their null value if null.
     4  // Use the zero subpackage if you want zero values and null to be treated the same.
     5  package null
     6  
     7  import (
     8  	"database/sql"
     9  	"encoding/json"
    10  	"fmt"
    11  	"reflect"
    12  )
    13  
    14  // String is a nullable string. It supports SQL and JSON serialization.
    15  // It will marshal to null if null. Blank string input will be considered null.
    16  type String struct {
    17  	sql.NullString
    18  }
    19  
    20  // StringFrom creates a new String that will never be blank.
    21  func StringFrom(s string) String {
    22  	return NewString(s, true)
    23  }
    24  
    25  // StringFromPtr creates a new String that be null if s is nil.
    26  func StringFromPtr(s *string) String {
    27  	if s == nil {
    28  		return NewString("", false)
    29  	}
    30  	return NewString(*s, true)
    31  }
    32  
    33  // ValueOrZero returns the inner value if valid, otherwise zero.
    34  func (s String) ValueOrZero() string {
    35  	if !s.Valid {
    36  		return ""
    37  	}
    38  	return s.String
    39  }
    40  
    41  // NewString creates a new String
    42  func NewString(s string, valid bool) String {
    43  	return String{
    44  		NullString: sql.NullString{
    45  			String: s,
    46  			Valid:  valid,
    47  		},
    48  	}
    49  }
    50  
    51  // NewStringAuto creates a new String setting valid to false if s is ""
    52  func NewStringAuto(s string) String {
    53  	return NewString(s, s != "")
    54  }
    55  
    56  // UnmarshalJSON implements json.Unmarshaler.
    57  // It supports string and null input. Blank string input does not produce a null String.
    58  // It also supports unmarshalling a sql.NullString.
    59  func (s *String) UnmarshalJSON(data []byte) error {
    60  	var err error
    61  	var v interface{}
    62  	if err = json.Unmarshal(data, &v); err != nil {
    63  		return err
    64  	}
    65  	switch x := v.(type) {
    66  	case string:
    67  		s.String = x
    68  	case map[string]interface{}:
    69  		err = json.Unmarshal(data, &s.NullString)
    70  	case nil:
    71  		s.Valid = false
    72  		return nil
    73  	default:
    74  		err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.String", reflect.TypeOf(v).Name())
    75  	}
    76  	s.Valid = err == nil
    77  	return err
    78  }
    79  
    80  // MarshalJSON implements json.Marshaler.
    81  // It will encode null if this String is null.
    82  func (s String) MarshalJSON() ([]byte, error) {
    83  	if !s.Valid {
    84  		return []byte("null"), nil
    85  	}
    86  	return json.Marshal(s.String)
    87  }
    88  
    89  // MarshalText implements encoding.TextMarshaler.
    90  // It will encode a blank string when this String is null.
    91  func (s String) MarshalText() ([]byte, error) {
    92  	if !s.Valid {
    93  		return []byte{}, nil
    94  	}
    95  	return []byte(s.String), nil
    96  }
    97  
    98  // UnmarshalText implements encoding.TextUnmarshaler.
    99  // It will unmarshal to a null String if the input is a blank string.
   100  func (s *String) UnmarshalText(text []byte) error {
   101  	s.String = string(text)
   102  	s.Valid = s.String != ""
   103  	return nil
   104  }
   105  
   106  // SetValid changes this String's value and also sets it to be non-null.
   107  func (s *String) SetValid(v string) {
   108  	s.String = v
   109  	s.Valid = true
   110  }
   111  
   112  // Ptr returns a pointer to this String's value, or a nil pointer if this String is null.
   113  func (s String) Ptr() *string {
   114  	if !s.Valid {
   115  		return nil
   116  	}
   117  	return &s.String
   118  }
   119  
   120  // IsZero returns true for null strings, for potential future omitempty support.
   121  func (s String) IsZero() bool {
   122  	return !s.Valid
   123  }