github.com/gocaveman/caveman@v0.0.0-20191211162744-0ddf99dbdf6e/valid/structtags.go (about) 1 package valid 2 3 import ( 4 "fmt" 5 "net/url" 6 "reflect" 7 "regexp" 8 "strconv" 9 "strings" 10 ) 11 12 // SUGGESTED STRUCT TAG EXAMPLES SHOWING FORMAT: 13 // 14 // Field1 string `valid:"required,minlen=6"` 15 // Field2 interface{} `valid:"type=int,minval=10,maxval=1000"` 16 17 // type StructTagRuleFunc func(fieldName string, part string) (Rules, error) 18 19 // // StructTagInfo is a package global var so if an application wants to register 20 // // it's own struct tag parsing rules it can 21 // var StructTagInfo []StructTagRuleFunc 22 23 var DefaultTagRuleGenerators []TagRuleGenerator 24 25 func init() { 26 27 DefaultTagRuleGenerators = append(DefaultTagRuleGenerators, TagRuleGeneratorFunc(func(t reflect.Type, goFieldName string, tagValues url.Values) (Rules, error) { 28 if len(tagValues["notnil"]) > 0 { 29 fieldName := MakeRuleFieldName(goFieldName, tagValues) 30 return Rules{NewNotNilRule(fieldName)}, nil 31 } 32 return nil, nil 33 })) 34 35 DefaultTagRuleGenerators = append(DefaultTagRuleGenerators, TagRuleGeneratorFunc(func(t reflect.Type, goFieldName string, tagValues url.Values) (Rules, error) { 36 i, _ := strconv.Atoi(tagValues.Get("minlen")) 37 if i > 0 { 38 fieldName := MakeRuleFieldName(goFieldName, tagValues) 39 return Rules{NewMinLenRule(fieldName, i)}, nil 40 } 41 return nil, nil 42 })) 43 44 DefaultTagRuleGenerators = append(DefaultTagRuleGenerators, TagRuleGeneratorFunc(func(t reflect.Type, goFieldName string, tagValues url.Values) (Rules, error) { 45 i, _ := strconv.Atoi(tagValues.Get("maxlen")) 46 if i > 0 { 47 fieldName := MakeRuleFieldName(goFieldName, tagValues) 48 return Rules{NewMaxLenRule(fieldName, i)}, nil 49 } 50 return nil, nil 51 })) 52 53 DefaultTagRuleGenerators = append(DefaultTagRuleGenerators, TagRuleGeneratorFunc(func(t reflect.Type, goFieldName string, tagValues url.Values) (Rules, error) { 54 re := tagValues.Get("regexp") 55 if re != "" { 56 fieldName := MakeRuleFieldName(goFieldName, tagValues) 57 rec, err := regexp.Compile(re) 58 if err != nil { 59 return nil, err 60 } 61 return Rules{NewRegexpRule(fieldName, rec)}, nil 62 } 63 return nil, nil 64 })) 65 66 DefaultTagRuleGenerators = append(DefaultTagRuleGenerators, TagRuleGeneratorFunc(func(t reflect.Type, goFieldName string, tagValues url.Values) (Rules, error) { 67 _, ok := tagValues["email"] 68 if ok { 69 fieldName := MakeRuleFieldName(goFieldName, tagValues) 70 return Rules{NewEmailRule(fieldName)}, nil 71 } 72 return nil, nil 73 })) 74 75 DefaultTagRuleGenerators = append(DefaultTagRuleGenerators, TagRuleGeneratorFunc(func(t reflect.Type, goFieldName string, tagValues url.Values) (Rules, error) { 76 77 mvstr, ok := tagValues["minval"] 78 if ok && len(mvstr) > 0 { 79 80 var mv float64 81 _, err := fmt.Sscanf(mvstr[0], "%f", &mv) 82 if err != nil { 83 return nil, fmt.Errorf("error parsing minval %q: %v", mvstr[0], err) 84 } 85 fieldName := MakeRuleFieldName(goFieldName, tagValues) 86 return Rules{NewMinValRule(fieldName, mv)}, nil 87 88 } 89 90 return nil, nil 91 })) 92 93 DefaultTagRuleGenerators = append(DefaultTagRuleGenerators, TagRuleGeneratorFunc(func(t reflect.Type, goFieldName string, tagValues url.Values) (Rules, error) { 94 95 mvstr, ok := tagValues["maxval"] 96 if ok && len(mvstr) > 0 { 97 98 var mv float64 99 _, err := fmt.Sscanf(mvstr[0], "%f", &mv) 100 if err != nil { 101 return nil, fmt.Errorf("error parsing maxval %q: %v", mvstr[0], err) 102 } 103 fieldName := MakeRuleFieldName(goFieldName, tagValues) 104 return Rules{NewMaxValRule(fieldName, mv)}, nil 105 106 } 107 108 return nil, nil 109 })) 110 111 } 112 113 type TagRuleGenerator interface { 114 // Generate one or more rules from the Go struct field name, the name inside 115 // the 'valid' part of the struct tag and it's value(s). 116 TagRuleGenerate(t reflect.Type, goFieldName string, tagValues url.Values) (Rules, error) 117 } 118 119 type TagRuleGeneratorFunc func(t reflect.Type, goFieldName string, tagValues url.Values) (Rules, error) 120 121 func (f TagRuleGeneratorFunc) TagRuleGenerate(t reflect.Type, goFieldName string, tagValues url.Values) (Rules, error) { 122 return f(t, goFieldName, tagValues) 123 } 124 125 func StructRules(t reflect.Type, gens []TagRuleGenerator) (Rules, error) { 126 127 if gens == nil { 128 gens = DefaultTagRuleGenerators 129 } 130 131 var rules Rules 132 133 for t.Kind() == reflect.Ptr { 134 t = t.Elem() 135 } 136 137 for i := 0; i < t.NumField(); i++ { 138 sf := t.Field(i) 139 vstr := sf.Tag.Get("valid") 140 vvalues := StructTagToValues(vstr) 141 142 for _, gen := range gens { 143 rs, err := gen.TagRuleGenerate(t, sf.Name, vvalues) 144 if err != nil { 145 return nil, err 146 } 147 rules = append(rules, rs...) 148 } 149 150 } 151 152 return rules, nil 153 } 154 155 func MakeRuleFieldName(goFieldName string, tagValues url.Values) string { 156 name := tagValues.Get("name") 157 if name != "" { 158 return name 159 } 160 ret := goFieldName // use the go field name as-is 161 // ret := ToSnake(goFieldName) 162 // log.Printf("MakeRuleFieldName(goFieldName=%q) is returning %q", goFieldName, ret) 163 return ret 164 } 165 166 func StructTagToValues(st string) url.Values { 167 168 ret := make(url.Values) 169 170 parts := strings.Split(st, ",") 171 172 for _, part := range parts { 173 kvparts := strings.SplitN(part, "=", 2) 174 if len(kvparts) < 2 { 175 ret.Set(kvparts[0], "") 176 } else { 177 ret.Set(kvparts[0], kvparts[1]) 178 } 179 } 180 181 return ret 182 }