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  }