github.com/wangyougui/gf/v2@v2.6.5/util/gvalid/gvalid_error.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/wangyougui/gf. 6 7 package gvalid 8 9 import ( 10 "strings" 11 12 "github.com/wangyougui/gf/v2/container/gset" 13 "github.com/wangyougui/gf/v2/errors/gcode" 14 "github.com/wangyougui/gf/v2/errors/gerror" 15 "github.com/wangyougui/gf/v2/text/gstr" 16 ) 17 18 // Error is the validation error for validation result. 19 type Error interface { 20 Code() gcode.Code 21 Current() error 22 Error() string 23 FirstItem() (key string, messages map[string]error) 24 FirstRule() (rule string, err error) 25 FirstError() (err error) 26 Items() (items []map[string]map[string]error) 27 Map() map[string]error 28 Maps() map[string]map[string]error 29 String() string 30 Strings() (errs []string) 31 } 32 33 // validationError is the validation error for validation result. 34 type validationError struct { 35 code gcode.Code // Error code. 36 rules []fieldRule // Rules by sequence, which is used for keeping error sequence only. 37 errors map[string]map[string]error // Error map:map[field]map[rule]message 38 firstKey string // The first error rule key(empty in default). 39 firstItem map[string]error // The first error rule value(nil in default). 40 } 41 42 // newValidationError creates and returns a validation error. 43 func newValidationError(code gcode.Code, rules []fieldRule, fieldRuleErrorMap map[string]map[string]error) *validationError { 44 for field, ruleErrorMap := range fieldRuleErrorMap { 45 for rule, err := range ruleErrorMap { 46 if !gerror.HasStack(err) { 47 ruleErrorMap[rule] = gerror.NewWithOption(gerror.Option{ 48 Stack: false, 49 Text: gstr.Trim(err.Error()), 50 Code: code, 51 }) 52 } 53 } 54 fieldRuleErrorMap[field] = ruleErrorMap 55 } 56 // Filter repeated sequence rules. 57 var ruleNameSet = gset.NewStrSet() 58 for i := 0; i < len(rules); { 59 if !ruleNameSet.AddIfNotExist(rules[i].Name) { 60 // Delete repeated rule. 61 rules = append(rules[:i], rules[i+1:]...) 62 continue 63 } 64 i++ 65 } 66 return &validationError{ 67 code: code, 68 rules: rules, 69 errors: fieldRuleErrorMap, 70 } 71 } 72 73 // newValidationErrorByStr creates and returns a validation error by string. 74 func newValidationErrorByStr(key string, err error) *validationError { 75 return newValidationError( 76 gcode.CodeInternalError, 77 nil, 78 map[string]map[string]error{ 79 internalErrorMapKey: { 80 key: err, 81 }, 82 }, 83 ) 84 } 85 86 // Code returns the error code of current validation error. 87 func (e *validationError) Code() gcode.Code { 88 if e == nil { 89 return gcode.CodeNil 90 } 91 return e.code 92 } 93 94 // Map returns the first error message as map. 95 func (e *validationError) Map() map[string]error { 96 if e == nil { 97 return map[string]error{} 98 } 99 _, m := e.FirstItem() 100 return m 101 } 102 103 // Maps returns all error messages as map. 104 func (e *validationError) Maps() map[string]map[string]error { 105 if e == nil { 106 return nil 107 } 108 return e.errors 109 } 110 111 // Items retrieves and returns error items array in sequence if possible, 112 // or else it returns error items with no sequence . 113 func (e *validationError) Items() (items []map[string]map[string]error) { 114 if e == nil { 115 return []map[string]map[string]error{} 116 } 117 items = make([]map[string]map[string]error, 0) 118 // By sequence. 119 if len(e.rules) > 0 { 120 for _, v := range e.rules { 121 if errorItemMap, ok := e.errors[v.Name]; ok { 122 items = append(items, map[string]map[string]error{ 123 v.Name: errorItemMap, 124 }) 125 } 126 } 127 return items 128 } 129 // No sequence. 130 for name, errorRuleMap := range e.errors { 131 items = append(items, map[string]map[string]error{ 132 name: errorRuleMap, 133 }) 134 } 135 return 136 } 137 138 // FirstItem returns the field name and error messages for the first validation rule error. 139 func (e *validationError) FirstItem() (key string, messages map[string]error) { 140 if e == nil { 141 return "", map[string]error{} 142 } 143 if e.firstItem != nil { 144 return e.firstKey, e.firstItem 145 } 146 // By sequence. 147 if len(e.rules) > 0 { 148 for _, v := range e.rules { 149 if errorItemMap, ok := e.errors[v.Name]; ok { 150 e.firstKey = v.Name 151 e.firstItem = errorItemMap 152 return v.Name, errorItemMap 153 } 154 } 155 } 156 // No sequence. 157 for k, m := range e.errors { 158 e.firstKey = k 159 e.firstItem = m 160 return k, m 161 } 162 return "", nil 163 } 164 165 // FirstRule returns the first error rule and message string. 166 func (e *validationError) FirstRule() (rule string, err error) { 167 if e == nil { 168 return "", nil 169 } 170 // By sequence. 171 if len(e.rules) > 0 { 172 for _, v := range e.rules { 173 if errorItemMap, ok := e.errors[v.Name]; ok { 174 for _, ruleItem := range strings.Split(v.Rule, "|") { 175 array := strings.Split(ruleItem, ":") 176 ruleItem = strings.TrimSpace(array[0]) 177 if err, ok = errorItemMap[ruleItem]; ok { 178 return ruleItem, err 179 } 180 } 181 } 182 } 183 } 184 // No sequence. 185 for _, errorItemMap := range e.errors { 186 for k, v := range errorItemMap { 187 return k, v 188 } 189 } 190 return "", nil 191 } 192 193 // FirstError returns the first error message as string. 194 // Note that the returned message might be different if it has no sequence. 195 func (e *validationError) FirstError() (err error) { 196 if e == nil { 197 return nil 198 } 199 _, err = e.FirstRule() 200 return 201 } 202 203 // Current is alis of FirstError, which implements interface gerror.iCurrent. 204 func (e *validationError) Current() error { 205 return e.FirstError() 206 } 207 208 // String returns all error messages as string, multiple error messages joined using char ';'. 209 func (e *validationError) String() string { 210 if e == nil { 211 return "" 212 } 213 return strings.Join(e.Strings(), "; ") 214 } 215 216 // Error implements interface of error.Error. 217 func (e *validationError) Error() string { 218 if e == nil { 219 return "" 220 } 221 return e.String() 222 } 223 224 // Strings returns all error messages as string array. 225 func (e *validationError) Strings() (errs []string) { 226 if e == nil { 227 return []string{} 228 } 229 errs = make([]string, 0) 230 // By sequence. 231 if len(e.rules) > 0 { 232 for _, v := range e.rules { 233 if errorItemMap, ok := e.errors[v.Name]; ok { 234 // validation error checks. 235 for _, ruleItem := range strings.Split(v.Rule, "|") { 236 ruleItem = strings.TrimSpace(strings.Split(ruleItem, ":")[0]) 237 if err, ok := errorItemMap[ruleItem]; ok { 238 errs = append(errs, err.Error()) 239 } 240 } 241 // internal error checks. 242 for k := range internalErrKeyMap { 243 if err, ok := errorItemMap[k]; ok { 244 errs = append(errs, err.Error()) 245 } 246 } 247 } 248 } 249 return errs 250 } 251 // No sequence. 252 for _, errorItemMap := range e.errors { 253 for _, err := range errorItemMap { 254 errs = append(errs, err.Error()) 255 } 256 } 257 return 258 }