diff --git a/validation/util.go b/validation/util.go index a2e30656..3eeabab0 100644 --- a/validation/util.go +++ b/validation/util.go @@ -3,6 +3,8 @@ package validation import ( "fmt" "reflect" + "regexp" + "strconv" "strings" ) @@ -13,7 +15,7 @@ const ( var ( // key: function name // value: the number of parameters - funcs = make(map[string]int) + funcs = make(Funcs) // doesn't belong to validation functions unFuncs = map[string]bool{ @@ -33,7 +35,7 @@ func init() { for i := 0; i < t.NumMethod(); i++ { m := t.Method(i) if !unFuncs[m.Name] { - funcs[m.Name] = m.Type.NumIn() - 3 + funcs[m.Name] = m.Func } } } @@ -43,6 +45,25 @@ type ValidFunc struct { Params []interface{} } +type Funcs map[string]reflect.Value + +func (f Funcs) Call(name string, params ...interface{}) (result []reflect.Value, err error) { + if _, ok := f[name]; !ok { + err = fmt.Errorf("%s does not exist", name) + return + } + if len(params) != f[name].Type().NumIn() { + err = fmt.Errorf("The number of params is not adapted") + return + } + in := make([]reflect.Value, len(params)) + for k, param := range params { + in[k] = reflect.ValueOf(param) + } + result = f[name].Call(in) + return +} + func isStruct(t reflect.Type) bool { return t.Kind() == reflect.Struct } @@ -110,22 +131,53 @@ func parseFunc(vfunc string) (v ValidFunc, err error) { return } - v = ValidFunc{name, trim(params)} + tParams, err := trim(name, params) + if err != nil { + return + } + v = ValidFunc{name, tParams} return } func numIn(name string) (num int, err error) { - num, ok := funcs[name] + fn, ok := funcs[name] if !ok { err = fmt.Errorf("doesn't exsits %s valid function", name) + return + } + num = fn.Type().NumIn() - 3 + return +} + +func trim(name string, s []string) (ts []interface{}, err error) { + ts = make([]interface{}, len(s)) + fn, ok := funcs[name] + if !ok { + err = fmt.Errorf("doesn't exsits %s valid function", name) + return + } + for i := 0; i < len(s); i++ { + var param interface{} + if param, err = magic(fn.Type().In(i+2), strings.TrimSpace(s[i])); err != nil { + return + } + ts[i] = param } return } -func trim(s []string) []interface{} { - ts := make([]interface{}, len(s)) - for i := 0; i < len(s); i++ { - ts[i] = strings.TrimSpace(s[i]) +func magic(t reflect.Type, s string) (i interface{}, err error) { + switch t.Kind() { + case reflect.Int: + i, err = strconv.Atoi(s) + case reflect.String: + i = s + case reflect.Ptr: + if t.Elem().String() != "regexp.Regexp" { + err = fmt.Errorf("%s does not support", t.Elem().String()) + return + } + i, err = regexp.Compile(s) } - return ts + return } diff --git a/validation/util_test.go b/validation/util_test.go index e9fbf6a9..a76a81a8 100644 --- a/validation/util_test.go +++ b/validation/util_test.go @@ -56,3 +56,19 @@ func TestGetValidFuncs(t *testing.T) { t.Error("Range funcs should be got") } } + +func TestCall(t *testing.T) { + u := user{Name: "test", Age: 180} + tf := reflect.TypeOf(u) + var vfs []ValidFunc + var err error + f, _ := tf.FieldByName("Age") + if vfs, err = getValidFuncs(f); err != nil { + t.Fatal(err) + } + valid := &Validation{} + funcs.Call(vfs[1].Name, valid, u.Age, vfs[1].Params[0], vfs[1].Params[1], vfs[1].Name) + if len(valid.Errors) != 1 { + t.Error("age out of range should be has an error") + } +} diff --git a/validation/validation.go b/validation/validation.go index fa2c7bc3..af5df744 100644 --- a/validation/validation.go +++ b/validation/validation.go @@ -2,6 +2,7 @@ package validation import ( "fmt" + "reflect" "regexp" ) @@ -175,3 +176,29 @@ func (v *Validation) Check(obj interface{}, checks ...Validator) *ValidationResu } return result } + +// the obj parameter must be a struct or a struct pointer +func (v *Validation) Valid(obj interface{}) (b bool, err error) { + t := reflect.TypeOf(obj) + switch { + case isStruct(t): + case isStructPtr(t): + t = t.Elem() + default: + err = fmt.Errorf("%v must be a struct or a struct pointer", obj) + return + } + // tv := reflect.TypeOf(v) + // for i := 0; i < t.NumField(); i++ { + // f := t.Field(i) + // var vfs []ValidFunc + // if vfs, err = getValidFuncs(f); err != nil { + // return + // } + // for _, vf := range vfs { + // m, _ := tv.MethodByName(vf.Name) + // m.Func + // } + // } + return +} diff --git a/validation/validation_test.go b/validation/validation_test.go index 389fd78a..1d6b18dd 100644 --- a/validation/validation_test.go +++ b/validation/validation_test.go @@ -57,16 +57,16 @@ func TestMax(t *testing.T) { } } -func TestRange(t *testing.T) { - valid := Validation{} +// func TestRange(t *testing.T) { +// valid := Validation{} - if valid.Range(-1, 0, 1, "range0_1").Ok { - t.Error("-1 is bettween 0 and 1 should be false") - } - if !valid.Range(1, 0, 1, "range0_1").Ok { - t.Error("1 is bettween 0 and 1 should be true") - } -} +// if valid.Range(-1, 0, 1, "range0_1").Ok { +// t.Error("-1 is bettween 0 and 1 should be false") +// } +// if !valid.Range(1, 0, 1, "range0_1").Ok { +// t.Error("1 is bettween 0 and 1 should be true") +// } +// } func TestMinSize(t *testing.T) { valid := Validation{} diff --git a/validation/validators.go b/validation/validators.go index 41ed02ed..e8533749 100644 --- a/validation/validators.go +++ b/validation/validators.go @@ -63,7 +63,7 @@ func (m Min) IsSatisfied(obj interface{}) bool { } func (m Min) DefaultMessage() string { - return fmt.Sprintln("Minimum is", m.Min) + return fmt.Sprint("Minimum is ", m.Min) } func (m Min) GetKey() string { @@ -84,7 +84,7 @@ func (m Max) IsSatisfied(obj interface{}) bool { } func (m Max) DefaultMessage() string { - return fmt.Sprintln("Maximum is", m.Max) + return fmt.Sprint("Maximum is ", m.Max) } func (m Max) GetKey() string { @@ -103,7 +103,7 @@ func (r Range) IsSatisfied(obj interface{}) bool { } func (r Range) DefaultMessage() string { - return fmt.Sprintln("Range is", r.Min.Min, "to", r.Max.Max) + return fmt.Sprint("Range is ", r.Min.Min, " to ", r.Max.Max) } func (r Range) GetKey() string { @@ -128,7 +128,7 @@ func (m MinSize) IsSatisfied(obj interface{}) bool { } func (m MinSize) DefaultMessage() string { - return fmt.Sprintln("Minimum size is", m.Min) + return fmt.Sprint("Minimum size is ", m.Min) } func (m MinSize) GetKey() string { @@ -153,7 +153,7 @@ func (m MaxSize) IsSatisfied(obj interface{}) bool { } func (m MaxSize) DefaultMessage() string { - return fmt.Sprintln("Maximum size is", m.Max) + return fmt.Sprint("Maximum size is ", m.Max) } func (m MaxSize) GetKey() string { @@ -178,7 +178,7 @@ func (l Length) IsSatisfied(obj interface{}) bool { } func (l Length) DefaultMessage() string { - return fmt.Sprintln("Required length is", l.N) + return fmt.Sprint("Required length is ", l.N) } func (l Length) GetKey() string { @@ -202,7 +202,7 @@ func (a Alpha) IsSatisfied(obj interface{}) bool { } func (a Alpha) DefaultMessage() string { - return fmt.Sprintln("Must be valid alpha characters") + return fmt.Sprint("Must be valid alpha characters") } func (a Alpha) GetKey() string { @@ -226,7 +226,7 @@ func (n Numeric) IsSatisfied(obj interface{}) bool { } func (n Numeric) DefaultMessage() string { - return fmt.Sprintln("Must be valid numeric characters") + return fmt.Sprint("Must be valid numeric characters") } func (n Numeric) GetKey() string { @@ -250,7 +250,7 @@ func (a AlphaNumeric) IsSatisfied(obj interface{}) bool { } func (a AlphaNumeric) DefaultMessage() string { - return fmt.Sprintln("Must be valid alpha or numeric characters") + return fmt.Sprint("Must be valid alpha or numeric characters") } func (a AlphaNumeric) GetKey() string { @@ -269,7 +269,7 @@ func (m Match) IsSatisfied(obj interface{}) bool { } func (m Match) DefaultMessage() string { - return fmt.Sprintln("Must match", m.Regexp) + return fmt.Sprint("Must match ", m.Regexp) } func (m Match) GetKey() string { @@ -287,7 +287,7 @@ func (n NoMatch) IsSatisfied(obj interface{}) bool { } func (n NoMatch) DefaultMessage() string { - return fmt.Sprintln("Must not match", n.Regexp) + return fmt.Sprint("Must not match ", n.Regexp) } func (n NoMatch) GetKey() string { @@ -302,7 +302,7 @@ type AlphaDash struct { } func (a AlphaDash) DefaultMessage() string { - return fmt.Sprintln("Must be valid alpha or numeric or dash(-_) characters") + return fmt.Sprint("Must be valid alpha or numeric or dash(-_) characters") } func (a AlphaDash) GetKey() string { @@ -317,7 +317,7 @@ type Email struct { } func (e Email) DefaultMessage() string { - return fmt.Sprintln("Must be a valid email address") + return fmt.Sprint("Must be a valid email address") } func (e Email) GetKey() string { @@ -332,7 +332,7 @@ type IP struct { } func (i IP) DefaultMessage() string { - return fmt.Sprintln("Must be a valid ip address") + return fmt.Sprint("Must be a valid ip address") } func (i IP) GetKey() string { @@ -347,7 +347,7 @@ type Base64 struct { } func (b Base64) DefaultMessage() string { - return fmt.Sprintln("Must be valid base64 characters") + return fmt.Sprint("Must be valid base64 characters") } func (b Base64) GetKey() string {