From 07daaf4e563562e18240031d27d8936d45d0af2d Mon Sep 17 00:00:00 2001 From: "marko.tikvic" Date: Wed, 15 Apr 2020 12:56:19 +0200 Subject: [PATCH] separate nullable time, date and timedate structs --- nullables.go | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- pdfhelper/pdf.go | 1 + 2 files changed, 224 insertions(+), 13 deletions(-) diff --git a/nullables.go b/nullables.go index a580559..1bed7d6 100644 --- a/nullables.go +++ b/nullables.go @@ -54,8 +54,8 @@ func (nb *NullBool) UnmarshalJSON(b []byte) error { return nil } -// SQLCast ... -func (nb *NullBool) SQLCast() sql.NullBool { +// CastToSQL ... +func (nb *NullBool) CastToSQL() sql.NullBool { return sql.NullBool(*nb) } @@ -104,8 +104,8 @@ func (ns *NullString) UnmarshalJSON(b []byte) error { return nil } -// SQLCast ... -func (ns *NullString) SQLCast() sql.NullString { +// CastToSQL ... +func (ns *NullString) CastToSQL() sql.NullString { return sql.NullString(*ns) } @@ -177,8 +177,8 @@ func (ni *NullInt64) UnmarshalJSON(b []byte) error { return nil } -// SQLCast ... -func (ni *NullInt64) SQLCast() sql.NullInt64 { +// CastToSQL ... +func (ni *NullInt64) CastToSQL() sql.NullInt64 { return sql.NullInt64(*ni) } @@ -251,11 +251,169 @@ func (nf *NullFloat64) UnmarshalJSON(b []byte) error { return nil } -// SQLCast ... -func (nf *NullFloat64) SQLCast() sql.NullFloat64 { +// CastToSQL ... +func (nf *NullFloat64) CastToSQL() sql.NullFloat64 { return sql.NullFloat64(*nf) } +// NullDateTime ... +type NullDateTime struct { + Time time.Time + Valid bool // Valid is true if Time is not NULL +} + +// Scan ... +func (nt *NullDateTime) Scan(value interface{}) (err error) { + if value == nil { + nt.Time, nt.Valid = time.Time{}, false + return + } + + switch v := value.(type) { + case time.Time: + nt.Time, nt.Valid = v, true + return + case []byte: + nt.Time, err = parseSQLDateTime(string(v), time.UTC) + nt.Valid = (err == nil) + return + case string: + nt.Time, err = parseSQLDateTime(v, time.UTC) + nt.Valid = (err == nil) + return + } + + nt.Valid = false + return fmt.Errorf("Can't convert %T to time.Time", value) +} + +// Value implements the driver Valuer interface. +func (nt NullDateTime) Value() (driver.Value, error) { + if !nt.Valid { + return nil, nil + } + return nt.Time, nil +} + +// MarshalJSON ... +func (nt NullDateTime) MarshalJSON() ([]byte, error) { + if nt.Valid { + format := nt.Time.Format("2006-01-02 15:04:05") + return json.Marshal(format) + } + return json.Marshal(nil) +} + +// UnmarshalJSON ... +func (nt *NullDateTime) UnmarshalJSON(b []byte) error { + var temp *time.Time + var t1 time.Time + var err error + + s1 := string(b) + s2 := s1[1 : len(s1)-1] + if s1 == "null" { + temp = nil + } else { + t1, err = time.Parse("2006-01-02 15:04:05", s2) + if err != nil { + return err + } + temp = &t1 + } + + if temp != nil { + nt.Valid = true + nt.Time = *temp + } else { + nt.Valid = false + } + return nil +} + +func (nt *NullDateTime) CastToSQL() NullDateTime { + return *nt +} + +// NullDate ... +type NullDate struct { + Time time.Time + Valid bool // Valid is true if Time is not NULL +} + +// Scan ... +func (nt *NullDate) Scan(value interface{}) (err error) { + if value == nil { + nt.Time, nt.Valid = time.Time{}, false + return + } + + switch v := value.(type) { + case time.Time: + nt.Time, nt.Valid = v, true + return + case []byte: + nt.Time, err = parseSQLDate(string(v), time.UTC) + nt.Valid = (err == nil) + return + case string: + nt.Time, err = parseSQLDate(v, time.UTC) + nt.Valid = (err == nil) + return + } + + nt.Valid = false + return fmt.Errorf("Can't convert %T to time.Time", value) +} + +// Value implements the driver Valuer interface. +func (nt NullDate) Value() (driver.Value, error) { + if !nt.Valid { + return nil, nil + } + return nt.Time, nil +} + +// MarshalJSON ... +func (nt NullDate) MarshalJSON() ([]byte, error) { + if nt.Valid { + format := nt.Time.Format("2006-01-02") + return json.Marshal(format) + } + return json.Marshal(nil) +} + +// UnmarshalJSON ... +func (nt *NullDate) UnmarshalJSON(b []byte) error { + var temp *time.Time + var t1 time.Time + var err error + + s1 := string(b) + s2 := s1[1 : len(s1)-1] + if s1 == "null" { + temp = nil + } else { + t1, err = time.Parse("2006-01-02", s2) + if err != nil { + return err + } + temp = &t1 + } + + if temp != nil { + nt.Valid = true + nt.Time = *temp + } else { + nt.Valid = false + } + return nil +} + +func (nt *NullDate) CastToSQL() NullDate { + return *nt +} + // NullTime ... type NullTime struct { Time time.Time @@ -274,11 +432,11 @@ func (nt *NullTime) Scan(value interface{}) (err error) { nt.Time, nt.Valid = v, true return case []byte: - nt.Time, err = parseDateTime(string(v), time.UTC) + nt.Time, err = parseSQLTime(string(v), time.UTC) nt.Valid = (err == nil) return case string: - nt.Time, err = parseDateTime(v, time.UTC) + nt.Time, err = parseSQLTime(v, time.UTC) nt.Valid = (err == nil) return } @@ -298,7 +456,7 @@ func (nt NullTime) Value() (driver.Value, error) { // MarshalJSON ... func (nt NullTime) MarshalJSON() ([]byte, error) { if nt.Valid { - format := nt.Time.Format("2006-01-02 15:04:05") + format := nt.Time.Format("15:04:05") return json.Marshal(format) } return json.Marshal(nil) @@ -315,7 +473,7 @@ func (nt *NullTime) UnmarshalJSON(b []byte) error { if s1 == "null" { temp = nil } else { - t1, err = time.Parse("2006-01-02 15:04:05", s2) + t1, err = time.Parse("15:04:05", s2) if err != nil { return err } @@ -331,7 +489,11 @@ func (nt *NullTime) UnmarshalJSON(b []byte) error { return nil } -func parseDateTime(str string, loc *time.Location) (t time.Time, err error) { +func (nt *NullTime) CastToSQL() NullTime { + return *nt +} + +func parseSQLDateTime(str string, loc *time.Location) (t time.Time, err error) { base := "0000-00-00 00:00:00.0000000" timeFormat := "2006-01-02 15:04:05.999999" switch len(str) { @@ -354,3 +516,51 @@ func parseDateTime(str string, loc *time.Location) (t time.Time, err error) { return } + +func parseSQLDate(str string, loc *time.Location) (t time.Time, err error) { + base := "0000-00-00" + timeFormat := "2006-01-02" + switch len(str) { + case 10: // up to "YYYY-MM-DD HH:MM:SS.MMMMMM" + if str == base[:len(str)] { + return + } + t, err = time.Parse(timeFormat[:len(str)], str) + default: + err = fmt.Errorf("invalid time string: %s", str) + return + } + + // Adjust location + if err == nil && loc != time.UTC { + y, mo, d := t.Date() + h, mi, s := t.Clock() + t, err = time.Date(y, mo, d, h, mi, s, t.Nanosecond(), loc), nil + } + + return +} + +func parseSQLTime(str string, loc *time.Location) (t time.Time, err error) { + base := "00:00:00.0000000" + timeFormat := "15:04:05.999999" + switch len(str) { + case 12, 15: // up to "YYYY-MM-DD HH:MM:SS.MMMMMM" + if str == base[:len(str)] { + return + } + t, err = time.Parse(timeFormat[:len(str)], str) + default: + err = fmt.Errorf("invalid time string: %s", str) + return + } + + // Adjust location + if err == nil && loc != time.UTC { + y, mo, d := t.Date() + h, mi, s := t.Clock() + t, err = time.Date(y, mo, d, h, mi, s, t.Nanosecond(), loc), nil + } + + return +} diff --git a/pdfhelper/pdf.go b/pdfhelper/pdf.go index dd9caad..adf63d4 100644 --- a/pdfhelper/pdf.go +++ b/pdfhelper/pdf.go @@ -10,6 +10,7 @@ import ( // Block ... const ( CENTER = "C" + MIDDLE = "M" LEFT = "L" RIGHT = "R" TOP = "T" -- 1.8.1.2