add x/jsonx.DayTime type

This commit is contained in:
Gerasimos (Makis) Maropoulos 2022-02-27 22:38:09 +02:00
parent b4b1f73df6
commit 5844eaef24
No known key found for this signature in database
GPG Key ID: 66FCC29BD385FCA6
5 changed files with 156 additions and 2 deletions

View File

@ -28,6 +28,8 @@ The codebase for Dependency Injection, Internationalization and localization and
## Fixes and Improvements
- Add [x/jsonx: DayTime](/x/jsonx/day_time.go) for JSON marshal and unmarshal of "15:04:05" (hour, minute, second).
- Fix a bug of `WithoutBodyConsumptionOnUnmarshal` configurator and a minor dependency injection issue caused by the previous alpha version between 20 and 26 February of 2022.
- New basic [cors middleware](middleware/cors).

View File

@ -121,7 +121,7 @@ func (c *Client) emitEndRequest(ctx context.Context, resp *http.Response, err er
// RequestOption declares the type of option one can pass
// to the Do methods(JSON, Form, ReadJSON...).
// Request options run before request constructed.
type RequestOption func(*http.Request) error
type RequestOption = func(*http.Request) error
// We always add the following request headers, unless they're removed by custom ones.
var defaultRequestOptions = []RequestOption{

View File

@ -13,7 +13,7 @@ import (
// All the builtin client options should live here, for easy discovery.
type Option func(*Client)
type Option = func(*Client)
// BaseURL registers the base URL of this client.
// All of its methods will prepend this url.

100
x/jsonx/day_time.go Normal file
View File

@ -0,0 +1,100 @@
package jsonx
import (
"fmt"
"strconv"
"strings"
"time"
)
const (
// DayTimeLayout holds the time layout for the the format of "hour:minute:second", hour can be 15, meaning 3 PM.
DayTimeLayout = "15:04:05"
)
// DayTime describes a time compatible with DayTimeLayout.
type DayTime time.Time
// ParseDayTime reads from "s" and returns the DayTime time.
func ParseDayTime(s string) (DayTime, error) {
if s == "" || s == "null" {
return DayTime{}, nil
}
tt, err := time.Parse(DayTimeLayout, s)
if err != nil {
return DayTime{}, err
}
return DayTime(tt), nil
}
// UnmarshalJSON parses the "b" into DayTime time.
func (t *DayTime) UnmarshalJSON(b []byte) error {
if len(b) == 0 {
return nil
}
s := strings.Trim(string(b), `"`)
tt, err := ParseDayTime(s)
if err != nil {
return err
}
*t = tt
return nil
}
// MarshalJSON writes a quoted string in the DayTime time format.
func (t DayTime) MarshalJSON() ([]byte, error) {
if s := t.String(); s != "" {
s = strconv.Quote(s)
return []byte(s), nil
}
return nullLiteral, nil // Note: if the front-end wants an empty string instead I must change that.
}
// ToTime returns the unwrapped *t to time.Time.
func (t *DayTime) ToTime() time.Time {
tt := time.Time(*t)
return tt
}
// IsZero reports whether "t" is zero time.
func (t DayTime) IsZero() bool {
return time.Time(t).IsZero()
}
// String returns the text representation of the "t" using the DayTime time layout.
func (t DayTime) String() string {
tt := t.ToTime()
if tt.IsZero() {
return ""
}
return tt.Format(DayTimeLayout)
}
// Scan completes the sql driver.Scanner interface.
func (t *DayTime) Scan(src interface{}) error {
switch v := src.(type) {
case time.Time: // type was set to timestamp
if v.IsZero() {
return nil // don't set zero, ignore it.
}
*t = DayTime(v)
case string:
tt, err := ParseDayTime(v)
if err != nil {
return err
}
*t = tt
case nil:
*t = DayTime(time.Time{})
default:
return fmt.Errorf("DayTime: unknown type of: %T", v)
}
return nil
}

52
x/jsonx/day_time_test.go Normal file
View File

@ -0,0 +1,52 @@
package jsonx
import (
"encoding/json"
"testing"
"time"
)
func TestDayTime(t *testing.T) {
tests := []struct {
rawData string
}{
{
rawData: `{"start": "8:33:00", "end": "15:00:42", "nothing": null, "empty": ""}`,
},
{
rawData: `{"start": "8:33:00", "end": "15:00:42", "nothing": null, "empty": ""}`,
},
}
for _, tt := range tests {
v := struct {
Start DayTime `json:"start"`
End DayTime `json:"end"`
Nothing DayTime `json:"nothing"`
Empty DayTime `json:"empty"`
}{}
err := json.Unmarshal([]byte(tt.rawData), &v)
if err != nil {
t.Fatal(err)
}
if !v.Nothing.IsZero() {
t.Fatalf("expected 'nothing' to be zero but got: %v", v.Nothing)
}
if !v.Empty.IsZero() {
t.Fatalf("expected 'empty' to be zero but got: %v", v.Empty)
}
loc := time.UTC
if expected, got := time.Date(0, time.January, 1, 8, 33, 0, 0, loc), v.Start.ToTime(); expected != got {
t.Fatalf("expected 'start' to be: %v but got: %v", expected, got)
}
if expected, got := time.Date(0, time.January, 1, 15, 0, 42, 0, loc), v.End.ToTime(); expected != got {
t.Fatalf("expected 'start' to be: %v but got: %v", expected, got)
}
}
}