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

     1  package null
     2  
     3  import (
     4  	"database/sql/driver"
     5  	"encoding/json"
     6  	"fmt"
     7  	"reflect"
     8  	"time"
     9  )
    10  
    11  // Time is a nullable time.Time. It supports SQL and JSON serialization.
    12  // It will marshal to null if null.
    13  type Time struct {
    14  	Time  time.Time
    15  	Valid bool
    16  }
    17  
    18  // Scan implements the Scanner interface.
    19  func (t *Time) Scan(value interface{}) error {
    20  	var err error
    21  	switch x := value.(type) {
    22  	case time.Time:
    23  		t.Time = x
    24  	case nil:
    25  		t.Valid = false
    26  		return nil
    27  	default:
    28  		err = fmt.Errorf("null: cannot scan type %T into null.Time: %v", value, value)
    29  	}
    30  	t.Valid = err == nil
    31  	return err
    32  }
    33  
    34  // Value implements the driver Valuer interface.
    35  func (t Time) Value() (driver.Value, error) {
    36  	if !t.Valid {
    37  		return nil, nil
    38  	}
    39  	return t.Time, nil
    40  }
    41  
    42  // NewTime creates a new Time.
    43  func NewTime(t time.Time, valid bool) Time {
    44  	return Time{
    45  		Time:  t,
    46  		Valid: valid,
    47  	}
    48  }
    49  
    50  // NewTimeAuto creates a new Time setting valid to false if t.IsZero()
    51  func NewTimeAuto(t time.Time) Time {
    52  	return NewTime(t, !t.IsZero())
    53  }
    54  
    55  // TimeFrom creates a new Time that will always be valid.
    56  func TimeFrom(t time.Time) Time {
    57  	return NewTime(t, true)
    58  }
    59  
    60  // TimeFromPtr creates a new Time that will be null if t is nil.
    61  func TimeFromPtr(t *time.Time) Time {
    62  	if t == nil {
    63  		return NewTime(time.Time{}, false)
    64  	}
    65  	return NewTime(*t, true)
    66  }
    67  
    68  // ValueOrZero returns the inner value if valid, otherwise zero.
    69  func (t Time) ValueOrZero() time.Time {
    70  	if !t.Valid {
    71  		return time.Time{}
    72  	}
    73  	return t.Time
    74  }
    75  
    76  // MarshalJSON implements json.Marshaler.
    77  // It will encode null if this time is null.
    78  func (t Time) MarshalJSON() ([]byte, error) {
    79  	if !t.Valid {
    80  		return []byte("null"), nil
    81  	}
    82  	return t.Time.MarshalJSON()
    83  }
    84  
    85  // UnmarshalJSON implements json.Unmarshaler.
    86  // It supports string, object (e.g. pq.NullTime and friends)
    87  // and null input.
    88  func (t *Time) UnmarshalJSON(data []byte) error {
    89  	var err error
    90  	var v interface{}
    91  	if err = json.Unmarshal(data, &v); err != nil {
    92  		return err
    93  	}
    94  	switch x := v.(type) {
    95  	case string:
    96  		err = t.Time.UnmarshalJSON(data)
    97  	case map[string]interface{}:
    98  		ti, tiOK := x["Time"].(string)
    99  		valid, validOK := x["Valid"].(bool)
   100  		if !tiOK || !validOK {
   101  			return fmt.Errorf(`json: unmarshalling object into Go value of type null.Time requires key "Time" to be of type string and key "Valid" to be of type bool; found %T and %T, respectively`, x["Time"], x["Valid"])
   102  		}
   103  		err = t.Time.UnmarshalText([]byte(ti))
   104  		t.Valid = valid
   105  		return err
   106  	case nil:
   107  		t.Valid = false
   108  		return nil
   109  	default:
   110  		err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Time", reflect.TypeOf(v).Name())
   111  	}
   112  	t.Valid = err == nil
   113  	return err
   114  }
   115  
   116  func (t Time) MarshalText() ([]byte, error) {
   117  	if !t.Valid {
   118  		return []byte("null"), nil
   119  	}
   120  	return t.Time.MarshalText()
   121  }
   122  
   123  func (t *Time) UnmarshalText(text []byte) error {
   124  	str := string(text)
   125  	if str == "" || str == "null" {
   126  		t.Valid = false
   127  		return nil
   128  	}
   129  	if err := t.Time.UnmarshalText(text); err != nil {
   130  		return err
   131  	}
   132  	t.Valid = true
   133  	return nil
   134  }
   135  
   136  // SetValid changes this Time's value and sets it to be non-null.
   137  func (t *Time) SetValid(v time.Time) {
   138  	t.Time = v
   139  	t.Valid = true
   140  }
   141  
   142  // Ptr returns a pointer to this Time's value, or a nil pointer if this Time is null.
   143  func (t Time) Ptr() *time.Time {
   144  	if !t.Valid {
   145  		return nil
   146  	}
   147  	return &t.Time
   148  }
   149  
   150  // IsZero returns true for invalid Times, hopefully for future omitempty support.
   151  // A non-null Time with a zero value will not be considered zero.
   152  func (t Time) IsZero() bool {
   153  	return !t.Valid
   154  }