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

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