mirror of
https://github.com/kataras/iris.git
synced 2025-02-09 02:34:55 +01:00
add '{date}' dynamic path parameter type
This commit is contained in:
parent
94447a2435
commit
90750d089d
|
@ -28,6 +28,8 @@ The codebase for Dependency Injection, Internationalization and localization and
|
||||||
|
|
||||||
## Fixes and Improvements
|
## Fixes and Improvements
|
||||||
|
|
||||||
|
- New `date` dynamic path parameter type. E.g. `/blog/{param:date}` matches to `"/blog/2022/04/21"`.
|
||||||
|
|
||||||
- Add `iris.AllowQuerySemicolons` and `iris.WithoutServerError(iris.ErrURLQuerySemicolon)` to handle golang.org/issue/25192 as reported at: https://github.com/kataras/iris/issues/1875.
|
- Add `iris.AllowQuerySemicolons` and `iris.WithoutServerError(iris.ErrURLQuerySemicolon)` to handle golang.org/issue/25192 as reported at: https://github.com/kataras/iris/issues/1875.
|
||||||
- Add new `Application.SetContextErrorHandler` to globally customize the default behavior (status code 500 without body) on `JSON`, `JSONP`, `Protobuf`, `MsgPack`, `XML`, `YAML` and `Markdown` method call write errors instead of catching the error on each handler.
|
- Add new `Application.SetContextErrorHandler` to globally customize the default behavior (status code 500 without body) on `JSON`, `JSONP`, `Protobuf`, `MsgPack`, `XML`, `YAML` and `Markdown` method call write errors instead of catching the error on each handler.
|
||||||
- Add new [x/pagination](x/pagination/pagination.go) sub-package which supports generics code (go 1.18+).
|
- Add new [x/pagination](x/pagination/pagination.go) sub-package which supports generics code (go 1.18+).
|
||||||
|
|
|
@ -125,8 +125,30 @@ func main() {
|
||||||
// anything, should be the last part, can be more than one path segment,
|
// anything, should be the last part, can be more than one path segment,
|
||||||
// i.e: "/test/{param:path}" and request: "/test/path1/path2/path3" , ctx.Params().Get("param") == "path1/path2/path3"
|
// i.e: "/test/{param:path}" and request: "/test/path1/path2/path3" , ctx.Params().Get("param") == "path1/path2/path3"
|
||||||
//
|
//
|
||||||
// if type is missing then parameter's type is defaulted to string, so
|
// +------------------------+
|
||||||
// {param} == {param:string}.
|
// | {param:uuid} |
|
||||||
|
// +------------------------+
|
||||||
|
// UUIDv4 (and v1) path parameter validation.
|
||||||
|
//
|
||||||
|
// +------------------------+
|
||||||
|
// | {param:mail} |
|
||||||
|
// +------------------------+
|
||||||
|
// Email without domain validation.
|
||||||
|
//
|
||||||
|
// +------------------------+
|
||||||
|
// | {param:email} |
|
||||||
|
// +------------------------+
|
||||||
|
// Email with domain validation.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// +------------------------+
|
||||||
|
// | {param:date} |
|
||||||
|
// +------------------------+
|
||||||
|
// yyyy/mm/dd format e.g. /blog/{param:date} matches /blog/2022/04/21.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// If type is missing then parameter's type is defaulted to string, so
|
||||||
|
// {param} is identical to {param:string}.
|
||||||
//
|
//
|
||||||
// If a function not found on that type then the `string` macro type's functions are being used.
|
// If a function not found on that type then the `string` macro type's functions are being used.
|
||||||
//
|
//
|
||||||
|
@ -147,10 +169,6 @@ func main() {
|
||||||
// app.Macros().String.RegisterFunc("equal", func(argument string) func(paramValue string) bool {
|
// app.Macros().String.RegisterFunc("equal", func(argument string) func(paramValue string) bool {
|
||||||
// return func(paramValue string) bool { return argument == paramValue }
|
// return func(paramValue string) bool { return argument == paramValue }
|
||||||
// })
|
// })
|
||||||
// +------------------------+
|
|
||||||
// | {param:uuid} |
|
|
||||||
// +------------------------+
|
|
||||||
// UUIDv4 (and v1) path parameter validation.
|
|
||||||
|
|
||||||
// Optionally, set custom handler on path parameter type error:
|
// Optionally, set custom handler on path parameter type error:
|
||||||
app.Macros().Get("uuid").HandleError(func(ctx iris.Context, paramIndex int, err error) {
|
app.Macros().Get("uuid").HandleError(func(ctx iris.Context, paramIndex int, err error) {
|
||||||
|
@ -185,6 +203,17 @@ func main() {
|
||||||
ctx.WriteString(email)
|
ctx.WriteString(email)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// http://localhost:8080/blog/2022/04/21
|
||||||
|
app.Get("/blog/{date:date}", func(ctx iris.Context) {
|
||||||
|
// rawTimeValue := ctx.Params().GetEntry("d").ValueRaw.(time.Time)
|
||||||
|
// OR
|
||||||
|
rawTimeValue, _ := ctx.Params().GetTime("date")
|
||||||
|
// yearMonthDay := rawTimeValue.Format("2006/01/02")
|
||||||
|
// OR
|
||||||
|
yearMonthDay := ctx.Params().SimpleDate("date")
|
||||||
|
ctx.Writef("Raw time.Time.String value: %v\nyyyy/mm/dd: %s\n", rawTimeValue, yearMonthDay)
|
||||||
|
})
|
||||||
|
|
||||||
// you can use the "string" type which is valid for a single path parameter that can be anything.
|
// you can use the "string" type which is valid for a single path parameter that can be anything.
|
||||||
app.Get("/username/{name}", func(ctx iris.Context) {
|
app.Get("/username/{name}", func(ctx iris.Context) {
|
||||||
ctx.Writef("Hello %s", ctx.Params().Get("name"))
|
ctx.Writef("Hello %s", ctx.Params().Get("name"))
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/kataras/iris/v12/core/memstore"
|
"github.com/kataras/iris/v12/core/memstore"
|
||||||
)
|
)
|
||||||
|
@ -240,6 +241,20 @@ var ParamResolvers = map[reflect.Type]func(paramIndex int) interface{}{
|
||||||
return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(bool)
|
return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(bool)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
reflect.TypeOf(time.Time{}): func(paramIndex int) interface{} {
|
||||||
|
return func(ctx *Context) time.Time {
|
||||||
|
if ctx.Params().Len() <= paramIndex {
|
||||||
|
return unixEpochTime
|
||||||
|
}
|
||||||
|
|
||||||
|
v, ok := ctx.Params().GetEntryAt(paramIndex).ValueRaw.(time.Time)
|
||||||
|
if !ok {
|
||||||
|
return unixEpochTime
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParamResolverByTypeAndIndex will return a function that can be used to bind path parameter's exact value by its Go std type
|
// ParamResolverByTypeAndIndex will return a function that can be used to bind path parameter's exact value by its Go std type
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
@ -120,10 +121,11 @@ func (e Entry) StringTrim() string {
|
||||||
type ErrEntryNotFound struct {
|
type ErrEntryNotFound struct {
|
||||||
Key string // the entry's key.
|
Key string // the entry's key.
|
||||||
Kind reflect.Kind // i.e bool, int, string...
|
Kind reflect.Kind // i.e bool, int, string...
|
||||||
|
Type reflect.Type // i.e time.Time{} or custom struct.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ErrEntryNotFound) Error() string {
|
func (e *ErrEntryNotFound) Error() string {
|
||||||
return fmt.Sprintf("not found: %s as %s", e.Key, e.Kind.String())
|
return fmt.Sprintf("not found: %s as %s (%s)", e.Key, e.Kind.String(), e.Type.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// As can be used to manually check if the error came from the memstore
|
// As can be used to manually check if the error came from the memstore
|
||||||
|
@ -151,16 +153,18 @@ func (e *ErrEntryNotFound) As(target interface{}) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Entry) notFound(kind reflect.Kind) *ErrEntryNotFound {
|
func (e Entry) notFound(typ reflect.Type) *ErrEntryNotFound {
|
||||||
return &ErrEntryNotFound{Key: e.Key, Kind: kind}
|
return &ErrEntryNotFound{Key: e.Key, Kind: typ.Kind(), Type: typ}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var intType = reflect.TypeOf(int(0))
|
||||||
|
|
||||||
// IntDefault returns the entry's value as int.
|
// IntDefault returns the entry's value as int.
|
||||||
// If not found returns "def" and a non-nil error.
|
// If not found returns "def" and a non-nil error.
|
||||||
func (e Entry) IntDefault(def int) (int, error) {
|
func (e Entry) IntDefault(def int) (int, error) {
|
||||||
v := e.ValueRaw
|
v := e.ValueRaw
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return def, e.notFound(reflect.Int)
|
return def, e.notFound(intType)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch vv := v.(type) {
|
switch vv := v.(type) {
|
||||||
|
@ -193,15 +197,17 @@ func (e Entry) IntDefault(def int) (int, error) {
|
||||||
return int(vv), nil
|
return int(vv), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return def, e.notFound(reflect.Int)
|
return def, e.notFound(intType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var int8Type = reflect.TypeOf(int8(0))
|
||||||
|
|
||||||
// Int8Default returns the entry's value as int8.
|
// Int8Default returns the entry's value as int8.
|
||||||
// If not found returns "def" and a non-nil error.
|
// If not found returns "def" and a non-nil error.
|
||||||
func (e Entry) Int8Default(def int8) (int8, error) {
|
func (e Entry) Int8Default(def int8) (int8, error) {
|
||||||
v := e.ValueRaw
|
v := e.ValueRaw
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return def, e.notFound(reflect.Int8)
|
return def, e.notFound(int8Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch vv := v.(type) {
|
switch vv := v.(type) {
|
||||||
|
@ -234,15 +240,17 @@ func (e Entry) Int8Default(def int8) (int8, error) {
|
||||||
return int8(vv), nil
|
return int8(vv), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return def, e.notFound(reflect.Int8)
|
return def, e.notFound(int8Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var int16Type = reflect.TypeOf(int16(0))
|
||||||
|
|
||||||
// Int16Default returns the entry's value as int16.
|
// Int16Default returns the entry's value as int16.
|
||||||
// If not found returns "def" and a non-nil error.
|
// If not found returns "def" and a non-nil error.
|
||||||
func (e Entry) Int16Default(def int16) (int16, error) {
|
func (e Entry) Int16Default(def int16) (int16, error) {
|
||||||
v := e.ValueRaw
|
v := e.ValueRaw
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return def, e.notFound(reflect.Int16)
|
return def, e.notFound(int16Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch vv := v.(type) {
|
switch vv := v.(type) {
|
||||||
|
@ -275,15 +283,17 @@ func (e Entry) Int16Default(def int16) (int16, error) {
|
||||||
return int16(vv), nil
|
return int16(vv), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return def, e.notFound(reflect.Int16)
|
return def, e.notFound(int16Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var int32Type = reflect.TypeOf(int32(0))
|
||||||
|
|
||||||
// Int32Default returns the entry's value as int32.
|
// Int32Default returns the entry's value as int32.
|
||||||
// If not found returns "def" and a non-nil error.
|
// If not found returns "def" and a non-nil error.
|
||||||
func (e Entry) Int32Default(def int32) (int32, error) {
|
func (e Entry) Int32Default(def int32) (int32, error) {
|
||||||
v := e.ValueRaw
|
v := e.ValueRaw
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return def, e.notFound(reflect.Int32)
|
return def, e.notFound(int32Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch vv := v.(type) {
|
switch vv := v.(type) {
|
||||||
|
@ -305,15 +315,17 @@ func (e Entry) Int32Default(def int32) (int32, error) {
|
||||||
return int32(vv), nil
|
return int32(vv), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return def, e.notFound(reflect.Int32)
|
return def, e.notFound(int32Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var int64Type = reflect.TypeOf(int64(0))
|
||||||
|
|
||||||
// Int64Default returns the entry's value as int64.
|
// Int64Default returns the entry's value as int64.
|
||||||
// If not found returns "def" and a non-nil error.
|
// If not found returns "def" and a non-nil error.
|
||||||
func (e Entry) Int64Default(def int64) (int64, error) {
|
func (e Entry) Int64Default(def int64) (int64, error) {
|
||||||
v := e.ValueRaw
|
v := e.ValueRaw
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return def, e.notFound(reflect.Int64)
|
return def, e.notFound(int64Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch vv := v.(type) {
|
switch vv := v.(type) {
|
||||||
|
@ -340,15 +352,17 @@ func (e Entry) Int64Default(def int64) (int64, error) {
|
||||||
return int64(vv), nil
|
return int64(vv), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return def, e.notFound(reflect.Int64)
|
return def, e.notFound(int64Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var uintType = reflect.TypeOf(uint(0))
|
||||||
|
|
||||||
// UintDefault returns the entry's value as uint.
|
// UintDefault returns the entry's value as uint.
|
||||||
// If not found returns "def" and a non-nil error.
|
// If not found returns "def" and a non-nil error.
|
||||||
func (e Entry) UintDefault(def uint) (uint, error) {
|
func (e Entry) UintDefault(def uint) (uint, error) {
|
||||||
v := e.ValueRaw
|
v := e.ValueRaw
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return def, e.notFound(reflect.Uint)
|
return def, e.notFound(uintType)
|
||||||
}
|
}
|
||||||
|
|
||||||
x64 := strconv.IntSize == 64
|
x64 := strconv.IntSize == 64
|
||||||
|
@ -374,12 +388,12 @@ func (e Entry) UintDefault(def uint) (uint, error) {
|
||||||
return uint(vv), nil
|
return uint(vv), nil
|
||||||
case uint64:
|
case uint64:
|
||||||
if vv > uint64(maxValue) {
|
if vv > uint64(maxValue) {
|
||||||
return def, e.notFound(reflect.Uint)
|
return def, e.notFound(uintType)
|
||||||
}
|
}
|
||||||
return uint(vv), nil
|
return uint(vv), nil
|
||||||
case int:
|
case int:
|
||||||
if vv < 0 || vv > int(maxValue) {
|
if vv < 0 || vv > int(maxValue) {
|
||||||
return def, e.notFound(reflect.Uint)
|
return def, e.notFound(uintType)
|
||||||
}
|
}
|
||||||
return uint(vv), nil
|
return uint(vv), nil
|
||||||
case int8:
|
case int8:
|
||||||
|
@ -392,15 +406,17 @@ func (e Entry) UintDefault(def uint) (uint, error) {
|
||||||
return uint(vv), nil
|
return uint(vv), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return def, e.notFound(reflect.Uint)
|
return def, e.notFound(uintType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var uint8Type = reflect.TypeOf(uint8(0))
|
||||||
|
|
||||||
// Uint8Default returns the entry's value as uint8.
|
// Uint8Default returns the entry's value as uint8.
|
||||||
// If not found returns "def" and a non-nil error.
|
// If not found returns "def" and a non-nil error.
|
||||||
func (e Entry) Uint8Default(def uint8) (uint8, error) {
|
func (e Entry) Uint8Default(def uint8) (uint8, error) {
|
||||||
v := e.ValueRaw
|
v := e.ValueRaw
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return def, e.notFound(reflect.Uint8)
|
return def, e.notFound(uint8Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch vv := v.(type) {
|
switch vv := v.(type) {
|
||||||
|
@ -412,42 +428,44 @@ func (e Entry) Uint8Default(def uint8) (uint8, error) {
|
||||||
return uint8(val), nil
|
return uint8(val), nil
|
||||||
case uint:
|
case uint:
|
||||||
if vv > math.MaxUint8 {
|
if vv > math.MaxUint8 {
|
||||||
return def, e.notFound(reflect.Uint8)
|
return def, e.notFound(uint8Type)
|
||||||
}
|
}
|
||||||
return uint8(vv), nil
|
return uint8(vv), nil
|
||||||
case uint8:
|
case uint8:
|
||||||
return vv, nil
|
return vv, nil
|
||||||
case uint16:
|
case uint16:
|
||||||
if vv > math.MaxUint8 {
|
if vv > math.MaxUint8 {
|
||||||
return def, e.notFound(reflect.Uint8)
|
return def, e.notFound(uint8Type)
|
||||||
}
|
}
|
||||||
return uint8(vv), nil
|
return uint8(vv), nil
|
||||||
case uint32:
|
case uint32:
|
||||||
if vv > math.MaxUint8 {
|
if vv > math.MaxUint8 {
|
||||||
return def, e.notFound(reflect.Uint8)
|
return def, e.notFound(uint8Type)
|
||||||
}
|
}
|
||||||
return uint8(vv), nil
|
return uint8(vv), nil
|
||||||
case uint64:
|
case uint64:
|
||||||
if vv > math.MaxUint8 {
|
if vv > math.MaxUint8 {
|
||||||
return def, e.notFound(reflect.Uint8)
|
return def, e.notFound(uint8Type)
|
||||||
}
|
}
|
||||||
return uint8(vv), nil
|
return uint8(vv), nil
|
||||||
case int:
|
case int:
|
||||||
if vv < 0 || vv > math.MaxUint8 {
|
if vv < 0 || vv > math.MaxUint8 {
|
||||||
return def, e.notFound(reflect.Uint8)
|
return def, e.notFound(uint8Type)
|
||||||
}
|
}
|
||||||
return uint8(vv), nil
|
return uint8(vv), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return def, e.notFound(reflect.Uint8)
|
return def, e.notFound(uint8Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var uint16Type = reflect.TypeOf(uint16(0))
|
||||||
|
|
||||||
// Uint16Default returns the entry's value as uint16.
|
// Uint16Default returns the entry's value as uint16.
|
||||||
// If not found returns "def" and a non-nil error.
|
// If not found returns "def" and a non-nil error.
|
||||||
func (e Entry) Uint16Default(def uint16) (uint16, error) {
|
func (e Entry) Uint16Default(def uint16) (uint16, error) {
|
||||||
v := e.ValueRaw
|
v := e.ValueRaw
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return def, e.notFound(reflect.Uint16)
|
return def, e.notFound(uint16Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch vv := v.(type) {
|
switch vv := v.(type) {
|
||||||
|
@ -459,7 +477,7 @@ func (e Entry) Uint16Default(def uint16) (uint16, error) {
|
||||||
return uint16(val), nil
|
return uint16(val), nil
|
||||||
case uint:
|
case uint:
|
||||||
if vv > math.MaxUint16 {
|
if vv > math.MaxUint16 {
|
||||||
return def, e.notFound(reflect.Uint16)
|
return def, e.notFound(uint16Type)
|
||||||
}
|
}
|
||||||
return uint16(vv), nil
|
return uint16(vv), nil
|
||||||
case uint8:
|
case uint8:
|
||||||
|
@ -468,30 +486,32 @@ func (e Entry) Uint16Default(def uint16) (uint16, error) {
|
||||||
return vv, nil
|
return vv, nil
|
||||||
case uint32:
|
case uint32:
|
||||||
if vv > math.MaxUint16 {
|
if vv > math.MaxUint16 {
|
||||||
return def, e.notFound(reflect.Uint16)
|
return def, e.notFound(uint16Type)
|
||||||
}
|
}
|
||||||
return uint16(vv), nil
|
return uint16(vv), nil
|
||||||
case uint64:
|
case uint64:
|
||||||
if vv > math.MaxUint16 {
|
if vv > math.MaxUint16 {
|
||||||
return def, e.notFound(reflect.Uint16)
|
return def, e.notFound(uint16Type)
|
||||||
}
|
}
|
||||||
return uint16(vv), nil
|
return uint16(vv), nil
|
||||||
case int:
|
case int:
|
||||||
if vv < 0 || vv > math.MaxUint16 {
|
if vv < 0 || vv > math.MaxUint16 {
|
||||||
return def, e.notFound(reflect.Uint16)
|
return def, e.notFound(uint16Type)
|
||||||
}
|
}
|
||||||
return uint16(vv), nil
|
return uint16(vv), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return def, e.notFound(reflect.Uint16)
|
return def, e.notFound(uint16Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var uint32Type = reflect.TypeOf(uint32(0))
|
||||||
|
|
||||||
// Uint32Default returns the entry's value as uint32.
|
// Uint32Default returns the entry's value as uint32.
|
||||||
// If not found returns "def" and a non-nil error.
|
// If not found returns "def" and a non-nil error.
|
||||||
func (e Entry) Uint32Default(def uint32) (uint32, error) {
|
func (e Entry) Uint32Default(def uint32) (uint32, error) {
|
||||||
v := e.ValueRaw
|
v := e.ValueRaw
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return def, e.notFound(reflect.Uint32)
|
return def, e.notFound(uint32Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch vv := v.(type) {
|
switch vv := v.(type) {
|
||||||
|
@ -503,7 +523,7 @@ func (e Entry) Uint32Default(def uint32) (uint32, error) {
|
||||||
return uint32(val), nil
|
return uint32(val), nil
|
||||||
case uint:
|
case uint:
|
||||||
if vv > math.MaxUint32 {
|
if vv > math.MaxUint32 {
|
||||||
return def, e.notFound(reflect.Uint32)
|
return def, e.notFound(uint32Type)
|
||||||
}
|
}
|
||||||
return uint32(vv), nil
|
return uint32(vv), nil
|
||||||
case uint8:
|
case uint8:
|
||||||
|
@ -514,27 +534,29 @@ func (e Entry) Uint32Default(def uint32) (uint32, error) {
|
||||||
return vv, nil
|
return vv, nil
|
||||||
case uint64:
|
case uint64:
|
||||||
if vv > math.MaxUint32 {
|
if vv > math.MaxUint32 {
|
||||||
return def, e.notFound(reflect.Uint32)
|
return def, e.notFound(uint32Type)
|
||||||
}
|
}
|
||||||
return uint32(vv), nil
|
return uint32(vv), nil
|
||||||
case int32:
|
case int32:
|
||||||
return uint32(vv), nil
|
return uint32(vv), nil
|
||||||
case int64:
|
case int64:
|
||||||
if vv < 0 || vv > math.MaxUint32 {
|
if vv < 0 || vv > math.MaxUint32 {
|
||||||
return def, e.notFound(reflect.Uint32)
|
return def, e.notFound(uint32Type)
|
||||||
}
|
}
|
||||||
return uint32(vv), nil
|
return uint32(vv), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return def, e.notFound(reflect.Uint32)
|
return def, e.notFound(uint32Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var uint64Type = reflect.TypeOf(uint64(0))
|
||||||
|
|
||||||
// Uint64Default returns the entry's value as uint64.
|
// Uint64Default returns the entry's value as uint64.
|
||||||
// If not found returns "def" and a non-nil error.
|
// If not found returns "def" and a non-nil error.
|
||||||
func (e Entry) Uint64Default(def uint64) (uint64, error) {
|
func (e Entry) Uint64Default(def uint64) (uint64, error) {
|
||||||
v := e.ValueRaw
|
v := e.ValueRaw
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return def, e.notFound(reflect.Uint64)
|
return def, e.notFound(uint64Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch vv := v.(type) {
|
switch vv := v.(type) {
|
||||||
|
@ -558,15 +580,17 @@ func (e Entry) Uint64Default(def uint64) (uint64, error) {
|
||||||
return uint64(vv), nil
|
return uint64(vv), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return def, e.notFound(reflect.Uint64)
|
return def, e.notFound(uint64Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var float32Type = reflect.TypeOf(float32(0))
|
||||||
|
|
||||||
// Float32Default returns the entry's value as float32.
|
// Float32Default returns the entry's value as float32.
|
||||||
// If not found returns "def" and a non-nil error.
|
// If not found returns "def" and a non-nil error.
|
||||||
func (e Entry) Float32Default(key string, def float32) (float32, error) {
|
func (e Entry) Float32Default(key string, def float32) (float32, error) {
|
||||||
v := e.ValueRaw
|
v := e.ValueRaw
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return def, e.notFound(reflect.Float32)
|
return def, e.notFound(float32Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch vv := v.(type) {
|
switch vv := v.(type) {
|
||||||
|
@ -580,22 +604,24 @@ func (e Entry) Float32Default(key string, def float32) (float32, error) {
|
||||||
return vv, nil
|
return vv, nil
|
||||||
case float64:
|
case float64:
|
||||||
if vv > math.MaxFloat32 {
|
if vv > math.MaxFloat32 {
|
||||||
return def, e.notFound(reflect.Float32)
|
return def, e.notFound(float32Type)
|
||||||
}
|
}
|
||||||
return float32(vv), nil
|
return float32(vv), nil
|
||||||
case int:
|
case int:
|
||||||
return float32(vv), nil
|
return float32(vv), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return def, e.notFound(reflect.Float32)
|
return def, e.notFound(float32Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var float64Type = reflect.TypeOf(float64(0))
|
||||||
|
|
||||||
// Float64Default returns the entry's value as float64.
|
// Float64Default returns the entry's value as float64.
|
||||||
// If not found returns "def" and a non-nil error.
|
// If not found returns "def" and a non-nil error.
|
||||||
func (e Entry) Float64Default(def float64) (float64, error) {
|
func (e Entry) Float64Default(def float64) (float64, error) {
|
||||||
v := e.ValueRaw
|
v := e.ValueRaw
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return def, e.notFound(reflect.Float64)
|
return def, e.notFound(float64Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch vv := v.(type) {
|
switch vv := v.(type) {
|
||||||
|
@ -619,9 +645,11 @@ func (e Entry) Float64Default(def float64) (float64, error) {
|
||||||
return float64(vv), nil
|
return float64(vv), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return def, e.notFound(reflect.Float64)
|
return def, e.notFound(float64Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var boolType = reflect.TypeOf(false)
|
||||||
|
|
||||||
// BoolDefault returns the user's value as bool.
|
// BoolDefault returns the user's value as bool.
|
||||||
// a string which is "1" or "t" or "T" or "TRUE" or "true" or "True"
|
// a string which is "1" or "t" or "T" or "TRUE" or "true" or "True"
|
||||||
// or "0" or "f" or "F" or "FALSE" or "false" or "False".
|
// or "0" or "f" or "F" or "FALSE" or "false" or "False".
|
||||||
|
@ -631,7 +659,7 @@ func (e Entry) Float64Default(def float64) (float64, error) {
|
||||||
func (e Entry) BoolDefault(def bool) (bool, error) {
|
func (e Entry) BoolDefault(def bool) (bool, error) {
|
||||||
v := e.ValueRaw
|
v := e.ValueRaw
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return def, e.notFound(reflect.Bool)
|
return def, e.notFound(boolType)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch vv := v.(type) {
|
switch vv := v.(type) {
|
||||||
|
@ -650,7 +678,26 @@ func (e Entry) BoolDefault(def bool) (bool, error) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return def, e.notFound(reflect.Bool)
|
return def, e.notFound(boolType)
|
||||||
|
}
|
||||||
|
|
||||||
|
var timeType = reflect.TypeOf(time.Time{})
|
||||||
|
|
||||||
|
// TimeDefault returns the stored time.Time value based on its "key".
|
||||||
|
// If does not exist or the stored key's value is not a time
|
||||||
|
// it returns the "def" time value and a not found error.
|
||||||
|
func (e Entry) TimeDefault(def time.Time) (time.Time, error) {
|
||||||
|
v := e.ValueRaw
|
||||||
|
if v == nil {
|
||||||
|
return def, e.notFound(timeType)
|
||||||
|
}
|
||||||
|
|
||||||
|
vv, ok := v.(time.Time)
|
||||||
|
if !ok {
|
||||||
|
return def, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return vv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value returns the value of the entry,
|
// Value returns the value of the entry,
|
||||||
|
@ -862,7 +909,7 @@ func (r *Store) GetStringTrim(name string) string {
|
||||||
func (r *Store) GetInt(key string) (int, error) {
|
func (r *Store) GetInt(key string) (int, error) {
|
||||||
v, ok := r.GetEntry(key)
|
v, ok := r.GetEntry(key)
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, v.notFound(reflect.Int)
|
return 0, v.notFound(intType)
|
||||||
}
|
}
|
||||||
return v.IntDefault(-1)
|
return v.IntDefault(-1)
|
||||||
}
|
}
|
||||||
|
@ -882,7 +929,7 @@ func (r *Store) GetIntDefault(key string, def int) int {
|
||||||
func (r *Store) GetInt8(key string) (int8, error) {
|
func (r *Store) GetInt8(key string) (int8, error) {
|
||||||
v, ok := r.GetEntry(key)
|
v, ok := r.GetEntry(key)
|
||||||
if !ok {
|
if !ok {
|
||||||
return -1, v.notFound(reflect.Int8)
|
return -1, v.notFound(int8Type)
|
||||||
}
|
}
|
||||||
return v.Int8Default(-1)
|
return v.Int8Default(-1)
|
||||||
}
|
}
|
||||||
|
@ -902,7 +949,7 @@ func (r *Store) GetInt8Default(key string, def int8) int8 {
|
||||||
func (r *Store) GetInt16(key string) (int16, error) {
|
func (r *Store) GetInt16(key string) (int16, error) {
|
||||||
v, ok := r.GetEntry(key)
|
v, ok := r.GetEntry(key)
|
||||||
if !ok {
|
if !ok {
|
||||||
return -1, v.notFound(reflect.Int16)
|
return -1, v.notFound(int16Type)
|
||||||
}
|
}
|
||||||
return v.Int16Default(-1)
|
return v.Int16Default(-1)
|
||||||
}
|
}
|
||||||
|
@ -922,7 +969,7 @@ func (r *Store) GetInt16Default(key string, def int16) int16 {
|
||||||
func (r *Store) GetInt32(key string) (int32, error) {
|
func (r *Store) GetInt32(key string) (int32, error) {
|
||||||
v, ok := r.GetEntry(key)
|
v, ok := r.GetEntry(key)
|
||||||
if !ok {
|
if !ok {
|
||||||
return -1, v.notFound(reflect.Int32)
|
return -1, v.notFound(int32Type)
|
||||||
}
|
}
|
||||||
return v.Int32Default(-1)
|
return v.Int32Default(-1)
|
||||||
}
|
}
|
||||||
|
@ -942,7 +989,7 @@ func (r *Store) GetInt32Default(key string, def int32) int32 {
|
||||||
func (r *Store) GetInt64(key string) (int64, error) {
|
func (r *Store) GetInt64(key string) (int64, error) {
|
||||||
v, ok := r.GetEntry(key)
|
v, ok := r.GetEntry(key)
|
||||||
if !ok {
|
if !ok {
|
||||||
return -1, v.notFound(reflect.Int64)
|
return -1, v.notFound(int64Type)
|
||||||
}
|
}
|
||||||
return v.Int64Default(-1)
|
return v.Int64Default(-1)
|
||||||
}
|
}
|
||||||
|
@ -962,7 +1009,7 @@ func (r *Store) GetInt64Default(key string, def int64) int64 {
|
||||||
func (r *Store) GetUint(key string) (uint, error) {
|
func (r *Store) GetUint(key string) (uint, error) {
|
||||||
v, ok := r.GetEntry(key)
|
v, ok := r.GetEntry(key)
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, v.notFound(reflect.Uint)
|
return 0, v.notFound(uintType)
|
||||||
}
|
}
|
||||||
return v.UintDefault(0)
|
return v.UintDefault(0)
|
||||||
}
|
}
|
||||||
|
@ -982,7 +1029,7 @@ func (r *Store) GetUintDefault(key string, def uint) uint {
|
||||||
func (r *Store) GetUint8(key string) (uint8, error) {
|
func (r *Store) GetUint8(key string) (uint8, error) {
|
||||||
v, ok := r.GetEntry(key)
|
v, ok := r.GetEntry(key)
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, v.notFound(reflect.Uint8)
|
return 0, v.notFound(uint8Type)
|
||||||
}
|
}
|
||||||
return v.Uint8Default(0)
|
return v.Uint8Default(0)
|
||||||
}
|
}
|
||||||
|
@ -1002,7 +1049,7 @@ func (r *Store) GetUint8Default(key string, def uint8) uint8 {
|
||||||
func (r *Store) GetUint16(key string) (uint16, error) {
|
func (r *Store) GetUint16(key string) (uint16, error) {
|
||||||
v, ok := r.GetEntry(key)
|
v, ok := r.GetEntry(key)
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, v.notFound(reflect.Uint16)
|
return 0, v.notFound(uint16Type)
|
||||||
}
|
}
|
||||||
return v.Uint16Default(0)
|
return v.Uint16Default(0)
|
||||||
}
|
}
|
||||||
|
@ -1022,7 +1069,7 @@ func (r *Store) GetUint16Default(key string, def uint16) uint16 {
|
||||||
func (r *Store) GetUint32(key string) (uint32, error) {
|
func (r *Store) GetUint32(key string) (uint32, error) {
|
||||||
v, ok := r.GetEntry(key)
|
v, ok := r.GetEntry(key)
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, v.notFound(reflect.Uint32)
|
return 0, v.notFound(uint32Type)
|
||||||
}
|
}
|
||||||
return v.Uint32Default(0)
|
return v.Uint32Default(0)
|
||||||
}
|
}
|
||||||
|
@ -1042,7 +1089,7 @@ func (r *Store) GetUint32Default(key string, def uint32) uint32 {
|
||||||
func (r *Store) GetUint64(key string) (uint64, error) {
|
func (r *Store) GetUint64(key string) (uint64, error) {
|
||||||
v, ok := r.GetEntry(key)
|
v, ok := r.GetEntry(key)
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, v.notFound(reflect.Uint64)
|
return 0, v.notFound(uint64Type)
|
||||||
}
|
}
|
||||||
return v.Uint64Default(0)
|
return v.Uint64Default(0)
|
||||||
}
|
}
|
||||||
|
@ -1062,7 +1109,7 @@ func (r *Store) GetUint64Default(key string, def uint64) uint64 {
|
||||||
func (r *Store) GetFloat64(key string) (float64, error) {
|
func (r *Store) GetFloat64(key string) (float64, error) {
|
||||||
v, ok := r.GetEntry(key)
|
v, ok := r.GetEntry(key)
|
||||||
if !ok {
|
if !ok {
|
||||||
return -1, v.notFound(reflect.Float64)
|
return -1, v.notFound(float64Type)
|
||||||
}
|
}
|
||||||
return v.Float64Default(-1)
|
return v.Float64Default(-1)
|
||||||
}
|
}
|
||||||
|
@ -1086,7 +1133,7 @@ func (r *Store) GetFloat64Default(key string, def float64) float64 {
|
||||||
func (r *Store) GetBool(key string) (bool, error) {
|
func (r *Store) GetBool(key string) (bool, error) {
|
||||||
v, ok := r.GetEntry(key)
|
v, ok := r.GetEntry(key)
|
||||||
if !ok {
|
if !ok {
|
||||||
return false, v.notFound(reflect.Bool)
|
return false, v.notFound(boolType)
|
||||||
}
|
}
|
||||||
|
|
||||||
return v.BoolDefault(false)
|
return v.BoolDefault(false)
|
||||||
|
@ -1105,6 +1152,39 @@ func (r *Store) GetBoolDefault(key string, def bool) bool {
|
||||||
return def
|
return def
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var zeroTime = time.Time{}
|
||||||
|
|
||||||
|
// GetTime returns the stored time.Time value based on its "key".
|
||||||
|
// If does not exist or the stored key's value is not a time
|
||||||
|
// it returns a zero time value and a not found error.
|
||||||
|
func (r *Store) GetTime(key string) (time.Time, error) {
|
||||||
|
v, ok := r.GetEntry(key)
|
||||||
|
if !ok {
|
||||||
|
return zeroTime, v.notFound(timeType)
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.TimeDefault(zeroTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
const simpleDateLayout = "2006/01/02"
|
||||||
|
|
||||||
|
// SimpleDate calls GetTime and formats the time as "yyyyy/mm/dd".
|
||||||
|
// It returns an empty string if the key does not exist or the
|
||||||
|
// stored value on "key" is not a time.Time type.
|
||||||
|
func (r *Store) SimpleDate(key string) string {
|
||||||
|
v, ok := r.GetEntry(key)
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
tt, err := v.TimeDefault(zeroTime)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return tt.Format(simpleDateLayout)
|
||||||
|
}
|
||||||
|
|
||||||
// Remove deletes an entry linked to that "key",
|
// Remove deletes an entry linked to that "key",
|
||||||
// returns true if an entry is actually removed.
|
// returns true if an entry is actually removed.
|
||||||
func (r *Store) Remove(key string) bool {
|
func (r *Store) Remove(key string) bool {
|
||||||
|
|
|
@ -207,7 +207,6 @@ func convertBuilderFunc(fn interface{}) ParamFuncBuilder {
|
||||||
val = strings.Split(arg[1:len(arg)-1], ",") // only string slices.
|
val = strings.Split(arg[1:len(arg)-1], ",") // only string slices.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
val = arg
|
val = arg
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Most important tests to look:
|
// Most important tests to look:
|
||||||
|
@ -484,6 +485,35 @@ func TestEmailEvaluatorRaw(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDateEvaluatorRaw(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
pass bool
|
||||||
|
input string
|
||||||
|
timeStringValue string
|
||||||
|
}{
|
||||||
|
{true, "2022/04/21", "2022-04-21 00:00:00 +0000 UTC"}, // 0
|
||||||
|
{true, "2022/12/05", "2022-12-05 00:00:00 +0000 UTC"}, // 1
|
||||||
|
{false, "2022/4", ""}, // 2
|
||||||
|
{false, "1/4/1", ""}, // 3
|
||||||
|
{false, "2022/4/", ""}, // 4
|
||||||
|
{false, "2022/4/21/0", ""}, // 5
|
||||||
|
{false, "1993", ""}, // 6
|
||||||
|
}
|
||||||
|
for i, tt := range tests {
|
||||||
|
testEvaluatorRaw(t, Date, tt.input, reflect.TypeOf(time.Time{}).Kind(), tt.pass, i)
|
||||||
|
|
||||||
|
if v, ok := Date.Evaluator(tt.input); ok {
|
||||||
|
if value, ok := v.(time.Time); ok {
|
||||||
|
if expected, got := tt.timeStringValue, value.String(); expected != got {
|
||||||
|
t.Fatalf("[%d] expected: %s but got: %s", i, expected, got)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Fatalf("[%d] expected to be able to cast as time.Time directly", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestConvertBuilderFunc(t *testing.T) {
|
func TestConvertBuilderFunc(t *testing.T) {
|
||||||
fn := func(min uint64, slice []string) func(string) bool {
|
fn := func(min uint64, slice []string) func(string) bool {
|
||||||
return func(paramValue string) bool {
|
return func(paramValue string) bool {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"net/mail"
|
"net/mail"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/kataras/iris/v12/macro/interpreter/ast"
|
"github.com/kataras/iris/v12/macro/interpreter/ast"
|
||||||
|
|
||||||
|
@ -431,6 +432,18 @@ var (
|
||||||
return paramValue, true
|
return paramValue, true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
simpleDateLayout = "2006/01/02"
|
||||||
|
|
||||||
|
// Date type.
|
||||||
|
Date = NewMacro("date", "", false, true, func(paramValue string) (interface{}, bool) {
|
||||||
|
tt, err := time.Parse(simpleDateLayout, paramValue)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%s: %w", paramValue, err), false
|
||||||
|
}
|
||||||
|
|
||||||
|
return tt, true
|
||||||
|
})
|
||||||
|
|
||||||
// Defaults contains the defaults macro and parameters types for the router.
|
// Defaults contains the defaults macro and parameters types for the router.
|
||||||
//
|
//
|
||||||
// Read https://github.com/kataras/iris/tree/master/_examples/routing/macros for more details.
|
// Read https://github.com/kataras/iris/tree/master/_examples/routing/macros for more details.
|
||||||
|
@ -453,6 +466,7 @@ var (
|
||||||
UUID,
|
UUID,
|
||||||
Mail,
|
Mail,
|
||||||
Email,
|
Email,
|
||||||
|
Date,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user