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

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