mirror of
https://github.com/kataras/iris.git
synced 2025-03-14 11:06:27 +01:00
dynamic param types part 1
Former-commit-id: 5829d53de848c0ea4491b53e4798f6c9cdf8d9a7
This commit is contained in:
parent
91fe161e90
commit
efa17e8899
|
@ -2,154 +2,63 @@ package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ParamType is a specific uint8 type
|
// ParamType holds the necessary information about a parameter type.
|
||||||
// which holds the parameter types' type.
|
type ParamType struct {
|
||||||
type ParamType uint8
|
Indent string // the name of the parameter type.
|
||||||
|
Aliases []string // any aliases, can be empty.
|
||||||
|
|
||||||
const (
|
GoType reflect.Kind // the go type useful for "mvc" and "hero" bindings.
|
||||||
// ParamTypeUnExpected is an unexpected parameter type.
|
|
||||||
ParamTypeUnExpected ParamType = iota
|
|
||||||
// ParamTypeString is the string type.
|
|
||||||
// If parameter type is missing then it defaults to String type.
|
|
||||||
// Allows anything
|
|
||||||
// Declaration: /mypath/{myparam:string} or {myparam}
|
|
||||||
ParamTypeString
|
|
||||||
|
|
||||||
// ParamTypeNumber is the integer, a number type.
|
Default bool // if true then empty type param will target this and its functions will be available to the rest of the param type's funcs.
|
||||||
// Allows both positive and negative numbers, any number of digits.
|
End bool // if true then it should be declared at the end of a route path and can accept any trailing path segment as one parameter.
|
||||||
// Declaration: /mypath/{myparam:number} or {myparam:int} for backwards-compatibility
|
|
||||||
ParamTypeNumber
|
|
||||||
|
|
||||||
// ParamTypeInt64 is a number type.
|
invalid bool // only true if returned by the parser via `LookupParamType`.
|
||||||
// Allows only -9223372036854775808 to 9223372036854775807.
|
}
|
||||||
// Declaration: /mypath/{myparam:int64} or {myparam:long}
|
|
||||||
ParamTypeInt64
|
|
||||||
// ParamTypeUint8 a number type.
|
|
||||||
// Allows only 0 to 255.
|
|
||||||
// Declaration: /mypath/{myparam:uint8}
|
|
||||||
ParamTypeUint8
|
|
||||||
// ParamTypeUint64 a number type.
|
|
||||||
// Allows only 0 to 18446744073709551615.
|
|
||||||
// Declaration: /mypath/{myparam:uint64}
|
|
||||||
ParamTypeUint64
|
|
||||||
|
|
||||||
// ParamTypeBoolean is the bool type.
|
// ParamTypeUnExpected is the unexpected parameter type.
|
||||||
// Allows only "1" or "t" or "T" or "TRUE" or "true" or "True"
|
var ParamTypeUnExpected = ParamType{invalid: true}
|
||||||
// or "0" or "f" or "F" or "FALSE" or "false" or "False".
|
|
||||||
// Declaration: /mypath/{myparam:bool} or {myparam:boolean}
|
|
||||||
ParamTypeBoolean
|
|
||||||
// ParamTypeAlphabetical is the alphabetical/letter type type.
|
|
||||||
// Allows letters only (upper or lowercase)
|
|
||||||
// Declaration: /mypath/{myparam:alphabetical}
|
|
||||||
ParamTypeAlphabetical
|
|
||||||
// ParamTypeFile is the file single path type.
|
|
||||||
// Allows:
|
|
||||||
// letters (upper or lowercase)
|
|
||||||
// numbers (0-9)
|
|
||||||
// underscore (_)
|
|
||||||
// dash (-)
|
|
||||||
// point (.)
|
|
||||||
// no spaces! or other character
|
|
||||||
// Declaration: /mypath/{myparam:file}
|
|
||||||
ParamTypeFile
|
|
||||||
// ParamTypePath is the multi path (or wildcard) type.
|
|
||||||
// Allows anything, should be the last part
|
|
||||||
// Declaration: /mypath/{myparam:path}
|
|
||||||
ParamTypePath
|
|
||||||
)
|
|
||||||
|
|
||||||
func (pt ParamType) String() string {
|
func (pt ParamType) String() string {
|
||||||
for k, v := range paramTypes {
|
return pt.Indent
|
||||||
if v == pt {
|
|
||||||
return k
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "unexpected"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not because for a single reason
|
|
||||||
// a string may be a
|
|
||||||
// ParamTypeString or a ParamTypeFile
|
|
||||||
// or a ParamTypePath or ParamTypeAlphabetical.
|
|
||||||
//
|
|
||||||
// func ParamTypeFromStd(k reflect.Kind) ParamType {
|
|
||||||
|
|
||||||
// Kind returns the std kind of this param type.
|
|
||||||
func (pt ParamType) Kind() reflect.Kind {
|
|
||||||
switch pt {
|
|
||||||
case ParamTypeAlphabetical:
|
|
||||||
fallthrough
|
|
||||||
case ParamTypeFile:
|
|
||||||
fallthrough
|
|
||||||
case ParamTypePath:
|
|
||||||
fallthrough
|
|
||||||
case ParamTypeString:
|
|
||||||
return reflect.String
|
|
||||||
case ParamTypeNumber:
|
|
||||||
return reflect.Int
|
|
||||||
case ParamTypeInt64:
|
|
||||||
return reflect.Int64
|
|
||||||
case ParamTypeUint8:
|
|
||||||
return reflect.Uint8
|
|
||||||
case ParamTypeUint64:
|
|
||||||
return reflect.Uint64
|
|
||||||
case ParamTypeBoolean:
|
|
||||||
return reflect.Bool
|
|
||||||
}
|
|
||||||
return reflect.Invalid // 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidKind will return true if at least one param type is supported
|
|
||||||
// for this std kind.
|
|
||||||
func ValidKind(k reflect.Kind) bool {
|
|
||||||
switch k {
|
|
||||||
case reflect.String:
|
|
||||||
fallthrough
|
|
||||||
case reflect.Int:
|
|
||||||
fallthrough
|
|
||||||
case reflect.Int64:
|
|
||||||
fallthrough
|
|
||||||
case reflect.Uint8:
|
|
||||||
fallthrough
|
|
||||||
case reflect.Uint64:
|
|
||||||
fallthrough
|
|
||||||
case reflect.Bool:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assignable returns true if the "k" standard type
|
// Assignable returns true if the "k" standard type
|
||||||
// is assignabled to this ParamType.
|
// is assignabled to this ParamType.
|
||||||
func (pt ParamType) Assignable(k reflect.Kind) bool {
|
func (pt ParamType) Assignable(k reflect.Kind) bool {
|
||||||
return pt.Kind() == k
|
return pt.GoType == k
|
||||||
}
|
}
|
||||||
|
|
||||||
var paramTypes = map[string]ParamType{
|
// GetDefaultParamType accepts a list of ParamType and returns its default.
|
||||||
"string": ParamTypeString,
|
// If no `Default` specified:
|
||||||
|
// and len(paramTypes) > 0 then it will return the first one,
|
||||||
|
// otherwise it returns a "string" parameter type.
|
||||||
|
func GetDefaultParamType(paramTypes ...ParamType) ParamType {
|
||||||
|
for _, pt := range paramTypes {
|
||||||
|
if pt.Default == true {
|
||||||
|
return pt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
"number": ParamTypeNumber,
|
if len(paramTypes) > 0 {
|
||||||
"int": ParamTypeNumber, // same as number.
|
return paramTypes[0]
|
||||||
"long": ParamTypeInt64,
|
}
|
||||||
"int64": ParamTypeInt64, // same as long.
|
|
||||||
"uint8": ParamTypeUint8,
|
|
||||||
"uint64": ParamTypeUint64,
|
|
||||||
|
|
||||||
"boolean": ParamTypeBoolean,
|
return ParamType{Indent: "string", GoType: reflect.String, Default: true}
|
||||||
"bool": ParamTypeBoolean, // same as boolean.
|
}
|
||||||
|
|
||||||
"alphabetical": ParamTypeAlphabetical,
|
// ValidKind will return true if at least one param type is supported
|
||||||
"file": ParamTypeFile,
|
// for this std kind.
|
||||||
"path": ParamTypePath,
|
func ValidKind(k reflect.Kind, paramTypes ...ParamType) bool {
|
||||||
// could be named also:
|
for _, pt := range paramTypes {
|
||||||
// "tail":
|
if pt.GoType == k {
|
||||||
// "wild"
|
return true
|
||||||
// "wildcard"
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// LookupParamType accepts the string
|
// LookupParamType accepts the string
|
||||||
|
@ -164,11 +73,20 @@ var paramTypes = map[string]ParamType{
|
||||||
// "alphabetical"
|
// "alphabetical"
|
||||||
// "file"
|
// "file"
|
||||||
// "path"
|
// "path"
|
||||||
func LookupParamType(ident string) ParamType {
|
func LookupParamType(indent string, paramTypes ...ParamType) (ParamType, bool) {
|
||||||
if typ, ok := paramTypes[ident]; ok {
|
for _, pt := range paramTypes {
|
||||||
return typ
|
if pt.Indent == indent {
|
||||||
|
return pt, true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, alias := range pt.Aliases {
|
||||||
|
if alias == indent {
|
||||||
|
return pt, true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ParamTypeUnExpected
|
|
||||||
|
return ParamTypeUnExpected, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// LookupParamTypeFromStd accepts the string representation of a standard go type.
|
// LookupParamTypeFromStd accepts the string representation of a standard go type.
|
||||||
|
@ -181,23 +99,15 @@ func LookupParamType(ident string) ParamType {
|
||||||
// int64 matches to int64/long
|
// int64 matches to int64/long
|
||||||
// uint64 matches to uint64
|
// uint64 matches to uint64
|
||||||
// bool matches to bool/boolean
|
// bool matches to bool/boolean
|
||||||
func LookupParamTypeFromStd(goType string) ParamType {
|
func LookupParamTypeFromStd(goType string, paramTypes ...ParamType) (ParamType, bool) {
|
||||||
switch goType {
|
goType = strings.ToLower(goType)
|
||||||
case "string":
|
for _, pt := range paramTypes {
|
||||||
return ParamTypeString
|
if strings.ToLower(pt.GoType.String()) == goType {
|
||||||
case "int":
|
return pt, true
|
||||||
return ParamTypeNumber
|
}
|
||||||
case "int64":
|
|
||||||
return ParamTypeInt64
|
|
||||||
case "uint8":
|
|
||||||
return ParamTypeUint8
|
|
||||||
case "uint64":
|
|
||||||
return ParamTypeUint64
|
|
||||||
case "bool":
|
|
||||||
return ParamTypeBoolean
|
|
||||||
default:
|
|
||||||
return ParamTypeUnExpected
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ParamTypeUnExpected, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParamStatement is a struct
|
// ParamStatement is a struct
|
||||||
|
|
|
@ -2,6 +2,7 @@ package parser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -10,10 +11,69 @@ import (
|
||||||
"github.com/kataras/iris/core/router/macro/interpreter/token"
|
"github.com/kataras/iris/core/router/macro/interpreter/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// paramTypeString is the string type.
|
||||||
|
// If parameter type is missing then it defaults to String type.
|
||||||
|
// Allows anything
|
||||||
|
// Declaration: /mypath/{myparam:string} or {myparam}
|
||||||
|
paramTypeString = ast.ParamType{Indent: "string", GoType: reflect.String, Default: true}
|
||||||
|
// ParamTypeNumber is the integer, a number type.
|
||||||
|
// Allows both positive and negative numbers, any number of digits.
|
||||||
|
// Declaration: /mypath/{myparam:number} or {myparam:int} for backwards-compatibility
|
||||||
|
paramTypeNumber = ast.ParamType{Indent: "number", Aliases: []string{"int"}, GoType: reflect.Int}
|
||||||
|
// ParamTypeInt64 is a number type.
|
||||||
|
// Allows only -9223372036854775808 to 9223372036854775807.
|
||||||
|
// Declaration: /mypath/{myparam:int64} or {myparam:long}
|
||||||
|
paramTypeInt64 = ast.ParamType{Indent: "int64", Aliases: []string{"long"}, GoType: reflect.Int64}
|
||||||
|
// ParamTypeUint8 a number type.
|
||||||
|
// Allows only 0 to 255.
|
||||||
|
// Declaration: /mypath/{myparam:uint8}
|
||||||
|
paramTypeUint8 = ast.ParamType{Indent: "uint8", GoType: reflect.Uint8}
|
||||||
|
// ParamTypeUint64 a number type.
|
||||||
|
// Allows only 0 to 18446744073709551615.
|
||||||
|
// Declaration: /mypath/{myparam:uint64}
|
||||||
|
paramTypeUint64 = ast.ParamType{Indent: "uint64", GoType: reflect.Uint64}
|
||||||
|
// ParamTypeBool is the bool type.
|
||||||
|
// Allows only "1" or "t" or "T" or "TRUE" or "true" or "True"
|
||||||
|
// or "0" or "f" or "F" or "FALSE" or "false" or "False".
|
||||||
|
// Declaration: /mypath/{myparam:bool} or {myparam:boolean}
|
||||||
|
paramTypeBool = ast.ParamType{Indent: "bool", Aliases: []string{"boolean"}, GoType: reflect.Bool}
|
||||||
|
// ParamTypeAlphabetical is the alphabetical/letter type type.
|
||||||
|
// Allows letters only (upper or lowercase)
|
||||||
|
// Declaration: /mypath/{myparam:alphabetical}
|
||||||
|
paramTypeAlphabetical = ast.ParamType{Indent: "alphabetical", GoType: reflect.String}
|
||||||
|
// ParamTypeFile is the file single path type.
|
||||||
|
// Allows:
|
||||||
|
// letters (upper or lowercase)
|
||||||
|
// numbers (0-9)
|
||||||
|
// underscore (_)
|
||||||
|
// dash (-)
|
||||||
|
// point (.)
|
||||||
|
// no spaces! or other character
|
||||||
|
// Declaration: /mypath/{myparam:file}
|
||||||
|
paramTypeFile = ast.ParamType{Indent: "file", GoType: reflect.String}
|
||||||
|
// ParamTypePath is the multi path (or wildcard) type.
|
||||||
|
// Allows anything, should be the last part
|
||||||
|
// Declaration: /mypath/{myparam:path}
|
||||||
|
paramTypePath = ast.ParamType{Indent: "path", GoType: reflect.String, End: true}
|
||||||
|
)
|
||||||
|
|
||||||
|
// DefaultParamTypes are the built'n parameter types.
|
||||||
|
var DefaultParamTypes = []ast.ParamType{
|
||||||
|
paramTypeString,
|
||||||
|
paramTypeNumber, paramTypeInt64, paramTypeUint8, paramTypeUint64,
|
||||||
|
paramTypeBool,
|
||||||
|
paramTypeAlphabetical, paramTypeFile, paramTypePath,
|
||||||
|
}
|
||||||
|
|
||||||
// Parse takes a route "fullpath"
|
// Parse takes a route "fullpath"
|
||||||
// and returns its param statements
|
// and returns its param statements
|
||||||
// and an error on failure.
|
// and an error on failure.
|
||||||
func Parse(fullpath string) ([]*ast.ParamStatement, error) {
|
func Parse(fullpath string, paramTypes ...ast.ParamType) ([]*ast.ParamStatement, error) {
|
||||||
|
if len(paramTypes) == 0 {
|
||||||
|
paramTypes = DefaultParamTypes
|
||||||
|
}
|
||||||
|
|
||||||
pathParts := strings.SplitN(fullpath, "/", -1)
|
pathParts := strings.SplitN(fullpath, "/", -1)
|
||||||
p := new(ParamParser)
|
p := new(ParamParser)
|
||||||
statements := make([]*ast.ParamStatement, 0)
|
statements := make([]*ast.ParamStatement, 0)
|
||||||
|
@ -28,14 +88,14 @@ func Parse(fullpath string) ([]*ast.ParamStatement, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
p.Reset(s)
|
p.Reset(s)
|
||||||
stmt, err := p.Parse()
|
stmt, err := p.Parse(paramTypes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// exit on first error
|
// exit on first error
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// if we have param type path but it's not the last path part
|
// if we have param type path but it's not the last path part
|
||||||
if stmt.Type == ast.ParamTypePath && i < len(pathParts)-1 {
|
if stmt.Type.End && i < len(pathParts)-1 {
|
||||||
return nil, fmt.Errorf("param type 'path' should be lived only inside the last path segment, but was inside: %s", s)
|
return nil, fmt.Errorf("param type '%s' should be lived only inside the last path segment, but was inside: %s", stmt.Type, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
statements = append(statements, stmt)
|
statements = append(statements, stmt)
|
||||||
|
@ -77,9 +137,6 @@ const (
|
||||||
// per-parameter. An error code can be setted via
|
// per-parameter. An error code can be setted via
|
||||||
// the "else" keyword inside a route's path.
|
// the "else" keyword inside a route's path.
|
||||||
DefaultParamErrorCode = 404
|
DefaultParamErrorCode = 404
|
||||||
// DefaultParamType when parameter type is missing use this param type, defaults to string
|
|
||||||
// and it should be remains unless earth split in two.
|
|
||||||
DefaultParamType = ast.ParamTypeString
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// func parseParamFuncArg(t token.Token) (a ast.ParamFuncArg, err error) {
|
// func parseParamFuncArg(t token.Token) (a ast.ParamFuncArg, err error) {
|
||||||
|
@ -102,14 +159,14 @@ func (p ParamParser) Error() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse parses the p.src and returns its param statement
|
// Parse parses the p.src based on the given param types and returns its param statement
|
||||||
// and an error on failure.
|
// and an error on failure.
|
||||||
func (p *ParamParser) Parse() (*ast.ParamStatement, error) {
|
func (p *ParamParser) Parse(paramTypes []ast.ParamType) (*ast.ParamStatement, error) {
|
||||||
l := lexer.New(p.src)
|
l := lexer.New(p.src)
|
||||||
|
|
||||||
stmt := &ast.ParamStatement{
|
stmt := &ast.ParamStatement{
|
||||||
ErrorCode: DefaultParamErrorCode,
|
ErrorCode: DefaultParamErrorCode,
|
||||||
Type: DefaultParamType,
|
Type: ast.GetDefaultParamType(paramTypes...),
|
||||||
Src: p.src,
|
Src: p.src,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,8 +189,8 @@ func (p *ParamParser) Parse() (*ast.ParamStatement, error) {
|
||||||
case token.COLON:
|
case token.COLON:
|
||||||
// type can accept both letters and numbers but not symbols ofc.
|
// type can accept both letters and numbers but not symbols ofc.
|
||||||
nextTok := l.NextToken()
|
nextTok := l.NextToken()
|
||||||
paramType := ast.LookupParamType(nextTok.Literal)
|
paramType, found := ast.LookupParamType(nextTok.Literal, paramTypes...)
|
||||||
if paramType == ast.ParamTypeUnExpected {
|
if !found {
|
||||||
p.appendErr("[%d:%d] unexpected parameter type: %s", t.Start, t.End, nextTok.Literal)
|
p.appendErr("[%d:%d] unexpected parameter type: %s", t.Start, t.End, nextTok.Literal)
|
||||||
}
|
}
|
||||||
stmt.Type = paramType
|
stmt.Type = paramType
|
||||||
|
|
|
@ -16,7 +16,7 @@ func TestParseParamError(t *testing.T) {
|
||||||
input := "{id" + string(illegalChar) + "int range(1,5) else 404}"
|
input := "{id" + string(illegalChar) + "int range(1,5) else 404}"
|
||||||
p := NewParamParser(input)
|
p := NewParamParser(input)
|
||||||
|
|
||||||
_, err := p.Parse()
|
_, err := p.Parse(DefaultParamTypes)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("expecting not empty error on input '%s'", input)
|
t.Fatalf("expecting not empty error on input '%s'", input)
|
||||||
|
@ -32,7 +32,7 @@ func TestParseParamError(t *testing.T) {
|
||||||
// success
|
// success
|
||||||
input2 := "{id:uint64 range(1,5) else 404}"
|
input2 := "{id:uint64 range(1,5) else 404}"
|
||||||
p.Reset(input2)
|
p.Reset(input2)
|
||||||
_, err = p.Parse()
|
_, err = p.Parse(DefaultParamTypes)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expecting empty error on input '%s', but got: %s", input2, err.Error())
|
t.Fatalf("expecting empty error on input '%s', but got: %s", input2, err.Error())
|
||||||
|
@ -40,6 +40,16 @@ func TestParseParamError(t *testing.T) {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mustLookupParamType same as `ast.LookupParamType` but it panics if "indent" does not match with a valid Param Type.
|
||||||
|
func mustLookupParamType(indent string) ast.ParamType {
|
||||||
|
pt, found := ast.LookupParamType(indent, DefaultParamTypes...)
|
||||||
|
if !found {
|
||||||
|
panic("param type '" + indent + "' is not part of the provided param types")
|
||||||
|
}
|
||||||
|
|
||||||
|
return pt
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseParam(t *testing.T) {
|
func TestParseParam(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
valid bool
|
valid bool
|
||||||
|
@ -49,7 +59,7 @@ func TestParseParam(t *testing.T) {
|
||||||
ast.ParamStatement{
|
ast.ParamStatement{
|
||||||
Src: "{id:number min(1) max(5) else 404}",
|
Src: "{id:number min(1) max(5) else 404}",
|
||||||
Name: "id",
|
Name: "id",
|
||||||
Type: ast.ParamTypeNumber,
|
Type: mustLookupParamType("number"),
|
||||||
Funcs: []ast.ParamFunc{
|
Funcs: []ast.ParamFunc{
|
||||||
{
|
{
|
||||||
Name: "min",
|
Name: "min",
|
||||||
|
@ -65,7 +75,7 @@ func TestParseParam(t *testing.T) {
|
||||||
ast.ParamStatement{
|
ast.ParamStatement{
|
||||||
Src: "{id:number range(1,5)}",
|
Src: "{id:number range(1,5)}",
|
||||||
Name: "id",
|
Name: "id",
|
||||||
Type: ast.ParamTypeNumber,
|
Type: mustLookupParamType("number"),
|
||||||
Funcs: []ast.ParamFunc{
|
Funcs: []ast.ParamFunc{
|
||||||
{
|
{
|
||||||
Name: "range",
|
Name: "range",
|
||||||
|
@ -77,7 +87,7 @@ func TestParseParam(t *testing.T) {
|
||||||
ast.ParamStatement{
|
ast.ParamStatement{
|
||||||
Src: "{file:path contains(.)}",
|
Src: "{file:path contains(.)}",
|
||||||
Name: "file",
|
Name: "file",
|
||||||
Type: ast.ParamTypePath,
|
Type: mustLookupParamType("path"),
|
||||||
Funcs: []ast.ParamFunc{
|
Funcs: []ast.ParamFunc{
|
||||||
{
|
{
|
||||||
Name: "contains",
|
Name: "contains",
|
||||||
|
@ -89,14 +99,14 @@ func TestParseParam(t *testing.T) {
|
||||||
ast.ParamStatement{
|
ast.ParamStatement{
|
||||||
Src: "{username:alphabetical}",
|
Src: "{username:alphabetical}",
|
||||||
Name: "username",
|
Name: "username",
|
||||||
Type: ast.ParamTypeAlphabetical,
|
Type: mustLookupParamType("alphabetical"),
|
||||||
ErrorCode: 404,
|
ErrorCode: 404,
|
||||||
}}, // 3
|
}}, // 3
|
||||||
{true,
|
{true,
|
||||||
ast.ParamStatement{
|
ast.ParamStatement{
|
||||||
Src: "{myparam}",
|
Src: "{myparam}",
|
||||||
Name: "myparam",
|
Name: "myparam",
|
||||||
Type: ast.ParamTypeString,
|
Type: mustLookupParamType("string"),
|
||||||
ErrorCode: 404,
|
ErrorCode: 404,
|
||||||
}}, // 4
|
}}, // 4
|
||||||
{false,
|
{false,
|
||||||
|
@ -110,14 +120,14 @@ func TestParseParam(t *testing.T) {
|
||||||
ast.ParamStatement{
|
ast.ParamStatement{
|
||||||
Src: "{myparam2}",
|
Src: "{myparam2}",
|
||||||
Name: "myparam2", // we now allow integers to the parameter names.
|
Name: "myparam2", // we now allow integers to the parameter names.
|
||||||
Type: ast.ParamTypeString,
|
Type: ast.GetDefaultParamType(DefaultParamTypes...),
|
||||||
ErrorCode: 404,
|
ErrorCode: 404,
|
||||||
}}, // 6
|
}}, // 6
|
||||||
{true,
|
{true,
|
||||||
ast.ParamStatement{
|
ast.ParamStatement{
|
||||||
Src: "{id:number even()}", // test param funcs without any arguments (LPAREN peek for RPAREN)
|
Src: "{id:number even()}", // test param funcs without any arguments (LPAREN peek for RPAREN)
|
||||||
Name: "id",
|
Name: "id",
|
||||||
Type: ast.ParamTypeNumber,
|
Type: mustLookupParamType("number"),
|
||||||
Funcs: []ast.ParamFunc{
|
Funcs: []ast.ParamFunc{
|
||||||
{
|
{
|
||||||
Name: "even"},
|
Name: "even"},
|
||||||
|
@ -128,37 +138,44 @@ func TestParseParam(t *testing.T) {
|
||||||
ast.ParamStatement{
|
ast.ParamStatement{
|
||||||
Src: "{id:int64 else 404}",
|
Src: "{id:int64 else 404}",
|
||||||
Name: "id",
|
Name: "id",
|
||||||
Type: ast.ParamTypeInt64,
|
Type: mustLookupParamType("int64"),
|
||||||
ErrorCode: 404,
|
ErrorCode: 404,
|
||||||
}}, // 8
|
}}, // 8
|
||||||
{true,
|
{true,
|
||||||
ast.ParamStatement{
|
ast.ParamStatement{
|
||||||
Src: "{id:long else 404}", // backwards-compatible test.
|
Src: "{id:long else 404}", // backwards-compatible test.
|
||||||
Name: "id",
|
Name: "id",
|
||||||
Type: ast.ParamTypeInt64,
|
Type: mustLookupParamType("int64"),
|
||||||
ErrorCode: 404,
|
ErrorCode: 404,
|
||||||
}}, // 9
|
}}, // 9
|
||||||
{true,
|
{true,
|
||||||
ast.ParamStatement{
|
ast.ParamStatement{
|
||||||
Src: "{has:bool else 404}",
|
Src: "{id:long else 404}",
|
||||||
Name: "has",
|
Name: "id",
|
||||||
Type: ast.ParamTypeBoolean,
|
Type: mustLookupParamType("long"), // backwards-compatible test of LookupParamType.
|
||||||
ErrorCode: 404,
|
ErrorCode: 404,
|
||||||
}}, // 10
|
}}, // 10
|
||||||
{true,
|
{true,
|
||||||
ast.ParamStatement{
|
ast.ParamStatement{
|
||||||
Src: "{has:boolean else 404}", // backwards-compatible test.
|
Src: "{has:bool else 404}",
|
||||||
Name: "has",
|
Name: "has",
|
||||||
Type: ast.ParamTypeBoolean,
|
Type: mustLookupParamType("bool"),
|
||||||
ErrorCode: 404,
|
ErrorCode: 404,
|
||||||
}}, // 11
|
}}, // 11
|
||||||
|
{true,
|
||||||
|
ast.ParamStatement{
|
||||||
|
Src: "{has:boolean else 404}", // backwards-compatible test.
|
||||||
|
Name: "has",
|
||||||
|
Type: mustLookupParamType("bool"),
|
||||||
|
ErrorCode: 404,
|
||||||
|
}}, // 12
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p := new(ParamParser)
|
p := new(ParamParser)
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
p.Reset(tt.expectedStatement.Src)
|
p.Reset(tt.expectedStatement.Src)
|
||||||
resultStmt, err := p.Parse()
|
resultStmt, err := p.Parse(DefaultParamTypes)
|
||||||
|
|
||||||
if tt.valid && err != nil {
|
if tt.valid && err != nil {
|
||||||
t.Fatalf("tests[%d] - error %s", i, err.Error())
|
t.Fatalf("tests[%d] - error %s", i, err.Error())
|
||||||
|
@ -185,7 +202,7 @@ func TestParse(t *testing.T) {
|
||||||
[]ast.ParamStatement{{
|
[]ast.ParamStatement{{
|
||||||
Src: "{id:number min(1) max(5) else 404}",
|
Src: "{id:number min(1) max(5) else 404}",
|
||||||
Name: "id",
|
Name: "id",
|
||||||
Type: ast.ParamTypeNumber,
|
Type: paramTypeNumber,
|
||||||
Funcs: []ast.ParamFunc{
|
Funcs: []ast.ParamFunc{
|
||||||
{
|
{
|
||||||
Name: "min",
|
Name: "min",
|
||||||
|
@ -201,7 +218,7 @@ func TestParse(t *testing.T) {
|
||||||
[]ast.ParamStatement{{
|
[]ast.ParamStatement{{
|
||||||
Src: "{id:uint64 range(1,5)}", // test alternative (backwards-compatibility) "int"
|
Src: "{id:uint64 range(1,5)}", // test alternative (backwards-compatibility) "int"
|
||||||
Name: "id",
|
Name: "id",
|
||||||
Type: ast.ParamTypeUint64,
|
Type: paramTypeUint64,
|
||||||
Funcs: []ast.ParamFunc{
|
Funcs: []ast.ParamFunc{
|
||||||
{
|
{
|
||||||
Name: "range",
|
Name: "range",
|
||||||
|
@ -214,7 +231,7 @@ func TestParse(t *testing.T) {
|
||||||
[]ast.ParamStatement{{
|
[]ast.ParamStatement{{
|
||||||
Src: "{file:path contains(.)}",
|
Src: "{file:path contains(.)}",
|
||||||
Name: "file",
|
Name: "file",
|
||||||
Type: ast.ParamTypePath,
|
Type: paramTypePath,
|
||||||
Funcs: []ast.ParamFunc{
|
Funcs: []ast.ParamFunc{
|
||||||
{
|
{
|
||||||
Name: "contains",
|
Name: "contains",
|
||||||
|
@ -227,7 +244,7 @@ func TestParse(t *testing.T) {
|
||||||
[]ast.ParamStatement{{
|
[]ast.ParamStatement{{
|
||||||
Src: "{username:alphabetical}",
|
Src: "{username:alphabetical}",
|
||||||
Name: "username",
|
Name: "username",
|
||||||
Type: ast.ParamTypeAlphabetical,
|
Type: paramTypeAlphabetical,
|
||||||
ErrorCode: 404,
|
ErrorCode: 404,
|
||||||
},
|
},
|
||||||
}}, // 3
|
}}, // 3
|
||||||
|
@ -235,7 +252,7 @@ func TestParse(t *testing.T) {
|
||||||
[]ast.ParamStatement{{
|
[]ast.ParamStatement{{
|
||||||
Src: "{myparam}",
|
Src: "{myparam}",
|
||||||
Name: "myparam",
|
Name: "myparam",
|
||||||
Type: ast.ParamTypeString,
|
Type: paramTypeString,
|
||||||
ErrorCode: 404,
|
ErrorCode: 404,
|
||||||
},
|
},
|
||||||
}}, // 4
|
}}, // 4
|
||||||
|
@ -251,7 +268,7 @@ func TestParse(t *testing.T) {
|
||||||
[]ast.ParamStatement{{
|
[]ast.ParamStatement{{
|
||||||
Src: "{myparam2}",
|
Src: "{myparam2}",
|
||||||
Name: "myparam2", // we now allow integers to the parameter names.
|
Name: "myparam2", // we now allow integers to the parameter names.
|
||||||
Type: ast.ParamTypeString,
|
Type: paramTypeString,
|
||||||
ErrorCode: 404,
|
ErrorCode: 404,
|
||||||
},
|
},
|
||||||
}}, // 6
|
}}, // 6
|
||||||
|
@ -259,7 +276,7 @@ func TestParse(t *testing.T) {
|
||||||
[]ast.ParamStatement{{
|
[]ast.ParamStatement{{
|
||||||
Src: "{file:path}",
|
Src: "{file:path}",
|
||||||
Name: "file",
|
Name: "file",
|
||||||
Type: ast.ParamTypePath,
|
Type: paramTypePath,
|
||||||
ErrorCode: 404,
|
ErrorCode: 404,
|
||||||
},
|
},
|
||||||
}}, // 7
|
}}, // 7
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
package iris
|
|
Loading…
Reference in New Issue
Block a user