Skip to content

Commit 7e32ac4

Browse files
committed
Add new value binding methods (UnixTimeMilli,TextUnmarshaler,JSONUnmarshaler) to ValueBinder
1 parent 3f5b733 commit 7e32ac4

File tree

2 files changed

+385
-10
lines changed

2 files changed

+385
-10
lines changed

binder.go

Lines changed: 111 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package echo
22

33
import (
4+
"encoding"
5+
"encoding/json"
46
"fmt"
57
"net/http"
68
"strconv"
@@ -52,8 +54,11 @@ import (
5254
* time
5355
* duration
5456
* BindUnmarshaler() interface
57+
* TextUnmarshaler() interface
58+
* JSONUnmarshaler() interface
5559
* UnixTime() - converts unix time (integer) to time.Time
56-
* UnixTimeNano() - converts unix time with nano second precision (integer) to time.Time
60+
* UnixTimeMilli() - converts unix time with millisecond precision (integer) to time.Time
61+
* UnixTimeNano() - converts unix time with nanosecond precision (integer) to time.Time
5762
* CustomFunc() - callback function for your custom conversion logic. Signature `func(values []string) []error`
5863
*/
5964

@@ -321,6 +326,78 @@ func (b *ValueBinder) MustBindUnmarshaler(sourceParam string, dest BindUnmarshal
321326
return b
322327
}
323328

329+
// JSONUnmarshaler binds parameter to destination implementing json.Unmarshaler interface
330+
func (b *ValueBinder) JSONUnmarshaler(sourceParam string, dest json.Unmarshaler) *ValueBinder {
331+
if b.failFast && b.errors != nil {
332+
return b
333+
}
334+
335+
tmp := b.ValueFunc(sourceParam)
336+
if tmp == "" {
337+
return b
338+
}
339+
340+
if err := dest.UnmarshalJSON([]byte(tmp)); err != nil {
341+
b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "failed to bind field value to json.Unmarshaler interface", err))
342+
}
343+
return b
344+
}
345+
346+
// MustJSONUnmarshaler requires parameter value to exist to be bind to destination implementing json.Unmarshaler interface.
347+
// Returns error when value does not exist
348+
func (b *ValueBinder) MustJSONUnmarshaler(sourceParam string, dest json.Unmarshaler) *ValueBinder {
349+
if b.failFast && b.errors != nil {
350+
return b
351+
}
352+
353+
tmp := b.ValueFunc(sourceParam)
354+
if tmp == "" {
355+
b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "required field value is empty", nil))
356+
return b
357+
}
358+
359+
if err := dest.UnmarshalJSON([]byte(tmp)); err != nil {
360+
b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "failed to bind field value to json.Unmarshaler interface", err))
361+
}
362+
return b
363+
}
364+
365+
// TextUnmarshaler binds parameter to destination implementing encoding.TextUnmarshaler interface
366+
func (b *ValueBinder) TextUnmarshaler(sourceParam string, dest encoding.TextUnmarshaler) *ValueBinder {
367+
if b.failFast && b.errors != nil {
368+
return b
369+
}
370+
371+
tmp := b.ValueFunc(sourceParam)
372+
if tmp == "" {
373+
return b
374+
}
375+
376+
if err := dest.UnmarshalText([]byte(tmp)); err != nil {
377+
b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "failed to bind field value to encoding.TextUnmarshaler interface", err))
378+
}
379+
return b
380+
}
381+
382+
// MustTextUnmarshaler requires parameter value to exist to be bind to destination implementing encoding.TextUnmarshaler interface.
383+
// Returns error when value does not exist
384+
func (b *ValueBinder) MustTextUnmarshaler(sourceParam string, dest encoding.TextUnmarshaler) *ValueBinder {
385+
if b.failFast && b.errors != nil {
386+
return b
387+
}
388+
389+
tmp := b.ValueFunc(sourceParam)
390+
if tmp == "" {
391+
b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "required field value is empty", nil))
392+
return b
393+
}
394+
395+
if err := dest.UnmarshalText([]byte(tmp)); err != nil {
396+
b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "failed to bind field value to encoding.TextUnmarshaler interface", err))
397+
}
398+
return b
399+
}
400+
324401
// BindWithDelimiter binds parameter to destination by suitable conversion function.
325402
// Delimiter is used before conversion to split parameter value to separate values
326403
func (b *ValueBinder) BindWithDelimiter(sourceParam string, dest interface{}, delimiter string) *ValueBinder {
@@ -1161,7 +1238,7 @@ func (b *ValueBinder) durations(sourceParam string, values []string, dest *[]tim
11611238
// Note:
11621239
// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
11631240
func (b *ValueBinder) UnixTime(sourceParam string, dest *time.Time) *ValueBinder {
1164-
return b.unixTime(sourceParam, dest, false, false)
1241+
return b.unixTime(sourceParam, dest, false, time.Second)
11651242
}
11661243

11671244
// MustUnixTime requires parameter value to exist to be bind to time.Duration variable (in local Time corresponding
@@ -1172,10 +1249,31 @@ func (b *ValueBinder) UnixTime(sourceParam string, dest *time.Time) *ValueBinder
11721249
// Note:
11731250
// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
11741251
func (b *ValueBinder) MustUnixTime(sourceParam string, dest *time.Time) *ValueBinder {
1175-
return b.unixTime(sourceParam, dest, true, false)
1252+
return b.unixTime(sourceParam, dest, true, time.Second)
1253+
}
1254+
1255+
// UnixTimeMilli binds parameter to time.Time variable (in local Time corresponding to the given Unix time in millisecond precision).
1256+
//
1257+
// Example: 1647184410140 bind to 2022-03-13T15:13:30.140000000+00:00
1258+
//
1259+
// Note:
1260+
// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
1261+
func (b *ValueBinder) UnixTimeMilli(sourceParam string, dest *time.Time) *ValueBinder {
1262+
return b.unixTime(sourceParam, dest, false, time.Millisecond)
11761263
}
11771264

1178-
// UnixTimeNano binds parameter to time.Time variable (in local Time corresponding to the given Unix time in nano second precision).
1265+
// MustUnixTimeMilli requires parameter value to exist to be bind to time.Duration variable (in local Time corresponding
1266+
// to the given Unix time in millisecond precision). Returns error when value does not exist.
1267+
//
1268+
// Example: 1647184410140 bind to 2022-03-13T15:13:30.140000000+00:00
1269+
//
1270+
// Note:
1271+
// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
1272+
func (b *ValueBinder) MustUnixTimeMilli(sourceParam string, dest *time.Time) *ValueBinder {
1273+
return b.unixTime(sourceParam, dest, true, time.Millisecond)
1274+
}
1275+
1276+
// UnixTimeNano binds parameter to time.Time variable (in local Time corresponding to the given Unix time in nanosecond precision).
11791277
//
11801278
// Example: 1609180603123456789 binds to 2020-12-28T18:36:43.123456789+00:00
11811279
// Example: 1000000000 binds to 1970-01-01T00:00:01.000000000+00:00
@@ -1185,7 +1283,7 @@ func (b *ValueBinder) MustUnixTime(sourceParam string, dest *time.Time) *ValueBi
11851283
// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
11861284
// * Javascript's Number type only has about 53 bits of precision (Number.MAX_SAFE_INTEGER = 9007199254740991). Compare it to 1609180603123456789 in example.
11871285
func (b *ValueBinder) UnixTimeNano(sourceParam string, dest *time.Time) *ValueBinder {
1188-
return b.unixTime(sourceParam, dest, false, true)
1286+
return b.unixTime(sourceParam, dest, false, time.Nanosecond)
11891287
}
11901288

11911289
// MustUnixTimeNano requires parameter value to exist to be bind to time.Duration variable (in local Time corresponding
@@ -1199,10 +1297,10 @@ func (b *ValueBinder) UnixTimeNano(sourceParam string, dest *time.Time) *ValueBi
11991297
// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
12001298
// * Javascript's Number type only has about 53 bits of precision (Number.MAX_SAFE_INTEGER = 9007199254740991). Compare it to 1609180603123456789 in example.
12011299
func (b *ValueBinder) MustUnixTimeNano(sourceParam string, dest *time.Time) *ValueBinder {
1202-
return b.unixTime(sourceParam, dest, true, true)
1300+
return b.unixTime(sourceParam, dest, true, time.Nanosecond)
12031301
}
12041302

1205-
func (b *ValueBinder) unixTime(sourceParam string, dest *time.Time, valueMustExist bool, isNano bool) *ValueBinder {
1303+
func (b *ValueBinder) unixTime(sourceParam string, dest *time.Time, valueMustExist bool, precision time.Duration) *ValueBinder {
12061304
if b.failFast && b.errors != nil {
12071305
return b
12081306
}
@@ -1221,10 +1319,13 @@ func (b *ValueBinder) unixTime(sourceParam string, dest *time.Time, valueMustExi
12211319
return b
12221320
}
12231321

1224-
if isNano {
1225-
*dest = time.Unix(0, n)
1226-
} else {
1322+
switch precision {
1323+
case time.Second:
12271324
*dest = time.Unix(n, 0)
1325+
case time.Millisecond:
1326+
*dest = time.Unix(n/1e3, (n%1e3)*1e6) // TODO: time.UnixMilli(n) exists since Go1.17 switch to that when min version allows
1327+
case time.Nanosecond:
1328+
*dest = time.Unix(0, n)
12281329
}
12291330
return b
12301331
}

0 commit comments

Comments
 (0)