2015-09-08 23:28:31 +02:00
package null
import (
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"time"
)
// Time is a nullable time.Time. It supports SQL and JSON serialization.
// It will marshal to null if null.
type Time struct {
Time time . Time
Valid bool
}
// Scan implements the Scanner interface.
func ( t * Time ) Scan ( value interface { } ) error {
2015-09-10 16:56:15 +02:00
var err error
switch x := value . ( type ) {
case time . Time :
t . Time = x
2015-09-10 18:49:41 +02:00
case nil :
t . Valid = false
return nil
2015-09-10 16:56:15 +02:00
default :
err = fmt . Errorf ( "null: cannot scan type %T into null.Time: %v" , value , value )
}
t . Valid = err == nil
return err
2015-09-08 23:28:31 +02:00
}
// Value implements the driver Valuer interface.
func ( t Time ) Value ( ) ( driver . Value , error ) {
if ! t . Valid {
return nil , nil
}
return t . Time , nil
}
// NewTime creates a new Time.
func NewTime ( t time . Time , valid bool ) Time {
return Time {
Time : t ,
Valid : valid ,
}
}
// TimeFrom creates a new Time that will always be valid.
func TimeFrom ( t time . Time ) Time {
return NewTime ( t , true )
}
// TimeFromPtr creates a new Time that will be null if t is nil.
func TimeFromPtr ( t * time . Time ) Time {
if t == nil {
2015-09-13 22:07:53 +02:00
return NewTime ( time . Time { } , false )
2015-09-08 23:28:31 +02:00
}
return NewTime ( * t , true )
}
// MarshalJSON implements json.Marshaler.
// It will encode null if this time is null.
func ( t Time ) MarshalJSON ( ) ( [ ] byte , error ) {
if ! t . Valid {
return [ ] byte ( "null" ) , nil
}
2015-09-13 22:33:34 +02:00
return t . Time . MarshalJSON ( )
2015-09-08 23:28:31 +02:00
}
// UnmarshalJSON implements json.Unmarshaler.
2015-09-13 22:07:53 +02:00
// It supports string, object (e.g. pq.NullTime and friends)
2015-09-10 19:36:31 +02:00
// and null input.
2015-09-08 23:28:31 +02:00
func ( t * Time ) UnmarshalJSON ( data [ ] byte ) error {
var err error
var v interface { }
2015-09-10 19:36:31 +02:00
if err = json . Unmarshal ( data , & v ) ; err != nil {
return err
}
2015-09-08 23:28:31 +02:00
switch x := v . ( type ) {
case string :
2015-09-10 19:36:31 +02:00
err = t . Time . UnmarshalJSON ( data )
case map [ string ] interface { } :
ti , tiOK := x [ "Time" ] . ( string )
valid , validOK := x [ "Valid" ] . ( bool )
if ! tiOK || ! validOK {
2015-09-13 22:07:53 +02:00
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" ] )
2015-09-10 19:36:31 +02:00
}
2015-09-13 22:07:53 +02:00
err = t . Time . UnmarshalText ( [ ] byte ( ti ) )
2015-09-10 19:36:31 +02:00
t . Valid = valid
2015-09-13 00:48:38 +02:00
return err
2015-09-08 23:28:31 +02:00
case nil :
t . Valid = false
return nil
default :
err = fmt . Errorf ( "json: cannot unmarshal %v into Go value of type null.Time" , reflect . TypeOf ( v ) . Name ( ) )
}
t . Valid = err == nil
return err
}
2015-09-13 22:33:34 +02:00
func ( t Time ) MarshalText ( ) ( [ ] byte , error ) {
if ! t . Valid {
return [ ] byte ( "null" ) , nil
}
return t . Time . MarshalText ( )
}
func ( t * Time ) UnmarshalText ( text [ ] byte ) error {
str := string ( text )
if str == "" || str == "null" {
t . Valid = false
return nil
}
if err := t . Time . UnmarshalText ( text ) ; err != nil {
return err
}
t . Valid = true
return nil
}
2015-09-08 23:28:31 +02:00
// SetValid changes this Time's value and sets it to be non-null.
func ( t * Time ) SetValid ( v time . Time ) {
t . Time = v
t . Valid = true
}
// Ptr returns a pointer to this Time's value, or a nil pointer if this Time is null.
func ( t Time ) Ptr ( ) * time . Time {
if ! t . Valid {
return nil
}
return & t . Time
}