-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support duration and time string format
- Loading branch information
1 parent
c330540
commit ef173c2
Showing
5 changed files
with
183 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
package types | ||
|
||
import ( | ||
"github.com/pkg/errors" | ||
"github.com/siyul-park/uniflow/pkg/encoding" | ||
"reflect" | ||
"time" | ||
"unsafe" | ||
) | ||
|
||
func newTimeEncoder() encoding.EncodeCompiler[any, Value] { | ||
typeTime := reflect.TypeOf((*time.Time)(nil)).Elem() | ||
|
||
return encoding.EncodeCompilerFunc[any, Value](func(typ reflect.Type) (encoding.Encoder[any, Value], error) { | ||
if typ != nil && typ == typeTime { | ||
return encoding.EncodeFunc(func(source any) (Value, error) { | ||
s := source.(time.Time) | ||
return NewInt64(s.UnixMilli()), nil | ||
}), nil | ||
} | ||
return nil, errors.WithStack(encoding.ErrUnsupportedType) | ||
}) | ||
} | ||
|
||
func newTimeDecoder() encoding.DecodeCompiler[Value] { | ||
typeTime := reflect.TypeOf((*time.Time)(nil)).Elem() | ||
|
||
return encoding.DecodeCompilerFunc[Value](func(typ reflect.Type) (encoding.Decoder[Value, unsafe.Pointer], error) { | ||
if typ != nil && typ.Kind() == reflect.Pointer { | ||
if typ.Elem() == typeTime { | ||
return encoding.DecodeFunc(func(source Value, target unsafe.Pointer) error { | ||
var v time.Time | ||
var err error | ||
if s, ok := source.(String); ok { | ||
v, err = time.Parse(time.RFC3339, s.String()) | ||
} else if s, ok := source.(Integer); ok { | ||
v = time.UnixMilli(s.Int()).UTC() | ||
} else if s, ok := source.(Float); ok { | ||
v = time.UnixMilli(int64(s.Float())).UTC() | ||
} else { | ||
err = errors.WithStack(encoding.ErrUnsupportedType) | ||
} | ||
if err != nil { | ||
return err | ||
} | ||
t := reflect.NewAt(typ.Elem(), target) | ||
t.Elem().Set(reflect.ValueOf(v)) | ||
return nil | ||
}), nil | ||
} | ||
} | ||
return nil, errors.WithStack(encoding.ErrUnsupportedType) | ||
}) | ||
} | ||
|
||
func newDurationEncoder() encoding.EncodeCompiler[any, Value] { | ||
typeDuration := reflect.TypeOf((*time.Duration)(nil)).Elem() | ||
|
||
return encoding.EncodeCompilerFunc[any, Value](func(typ reflect.Type) (encoding.Encoder[any, Value], error) { | ||
if typ != nil && typ == typeDuration { | ||
return encoding.EncodeFunc(func(source any) (Value, error) { | ||
s := source.(time.Duration) | ||
return NewInt64(s.Milliseconds()), nil | ||
}), nil | ||
} | ||
return nil, errors.WithStack(encoding.ErrUnsupportedType) | ||
}) | ||
} | ||
|
||
func newDurationDecoder() encoding.DecodeCompiler[Value] { | ||
typeDuration := reflect.TypeOf((*time.Duration)(nil)).Elem() | ||
|
||
return encoding.DecodeCompilerFunc[Value](func(typ reflect.Type) (encoding.Decoder[Value, unsafe.Pointer], error) { | ||
if typ != nil && typ.Kind() == reflect.Pointer { | ||
if typ.Elem() == typeDuration { | ||
return encoding.DecodeFunc(func(source Value, target unsafe.Pointer) error { | ||
var v time.Duration | ||
var err error | ||
if s, ok := source.(String); ok { | ||
v, err = time.ParseDuration(s.String()) | ||
} else if s, ok := source.(Integer); ok { | ||
v = time.Millisecond * (time.Duration)(s.Int()) | ||
} else if s, ok := source.(Float); ok { | ||
v = time.Millisecond * (time.Duration)(s.Float()) | ||
} else { | ||
err = errors.WithStack(encoding.ErrUnsupportedType) | ||
} | ||
if err != nil { | ||
return err | ||
} | ||
t := reflect.NewAt(typ.Elem(), target) | ||
t.Elem().Set(reflect.ValueOf(v)) | ||
return nil | ||
}), nil | ||
} | ||
} | ||
return nil, errors.WithStack(encoding.ErrUnsupportedType) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package types | ||
|
||
import ( | ||
"github.com/siyul-park/uniflow/pkg/encoding" | ||
"github.com/stretchr/testify/assert" | ||
"testing" | ||
"time" | ||
) | ||
|
||
func TestTime_Encode(t *testing.T) { | ||
enc := encoding.NewEncodeAssembler[any, Value]() | ||
enc.Add(newTimeEncoder()) | ||
|
||
timestamp := time.Date(2024, time.November, 16, 12, 0, 0, 0, time.UTC) | ||
|
||
encoded, err := enc.Encode(timestamp) | ||
assert.NoError(t, err) | ||
|
||
expected := NewInt64(timestamp.UnixMilli()) | ||
assert.Equal(t, expected, encoded) | ||
} | ||
|
||
func TestTime_Decode(t *testing.T) { | ||
dec := encoding.NewDecodeAssembler[Value, any]() | ||
dec.Add(newTimeDecoder()) | ||
|
||
timestamp := time.Date(2024, time.November, 16, 12, 0, 0, 0, time.UTC) | ||
encoded := NewInt64(timestamp.UnixMilli()) | ||
|
||
var decoded time.Time | ||
err := dec.Decode(encoded, &decoded) | ||
assert.NoError(t, err) | ||
assert.Equal(t, timestamp, decoded) | ||
} | ||
|
||
func TestDuration_Encode(t *testing.T) { | ||
enc := encoding.NewEncodeAssembler[any, Value]() | ||
enc.Add(newDurationEncoder()) | ||
|
||
duration := 1500 * time.Millisecond | ||
|
||
encoded, err := enc.Encode(duration) | ||
assert.NoError(t, err) | ||
|
||
expected := NewInt64(1500) | ||
assert.Equal(t, expected, encoded) | ||
} | ||
|
||
func TestDuration_Decode(t *testing.T) { | ||
dec := encoding.NewDecodeAssembler[Value, any]() | ||
dec.Add(newDurationDecoder()) | ||
|
||
duration := 1500 * time.Millisecond | ||
encoded := NewInt64(1500) | ||
|
||
var decoded time.Duration | ||
err := dec.Decode(encoded, &decoded) | ||
assert.NoError(t, err) | ||
assert.Equal(t, duration, decoded) | ||
} |