github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/kit/validator/errors/errors_set.go (about)

     1  package errors
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  
     7  	"github.com/machinefi/w3bstream/pkg/depends/kit/statusx"
     8  )
     9  
    10  func NewErrorSetWithRoot(root string) *ErrorSet { return &ErrorSet{root: root} }
    11  
    12  func NewErrorSet() *ErrorSet { return &ErrorSet{root: ""} }
    13  
    14  type ErrorSet struct {
    15  	root   string
    16  	errors []*FieldError
    17  }
    18  
    19  func (set *ErrorSet) AddErr(err error, keyPathNodes ...interface{}) {
    20  	if err == nil {
    21  		return
    22  	}
    23  	set.errors = append(set.errors, &FieldError{KeyPath(keyPathNodes), err})
    24  }
    25  
    26  func (set *ErrorSet) Each(cb func(*FieldError)) {
    27  	for _, fe := range set.errors {
    28  		cb(fe)
    29  	}
    30  }
    31  
    32  func (set *ErrorSet) Flatten() *ErrorSet {
    33  	ret := NewErrorSetWithRoot(set.root)
    34  
    35  	var walk func(*ErrorSet, ...interface{})
    36  
    37  	walk = func(es *ErrorSet, patterns ...interface{}) {
    38  		es.Each(func(fe *FieldError) {
    39  			if sub, ok := fe.Error.(*ErrorSet); ok {
    40  				walk(sub, append(patterns, fe.Field...)...)
    41  			} else {
    42  				ret.AddErr(fe.Error, append(patterns, fe.Field...)...)
    43  			}
    44  		})
    45  	}
    46  
    47  	walk(set)
    48  
    49  	return ret
    50  }
    51  func (set *ErrorSet) Len() int { return len(set.Flatten().errors) }
    52  
    53  func (set *ErrorSet) Err() error {
    54  	if len(set.errors) == 0 {
    55  		return nil
    56  	}
    57  	return set
    58  }
    59  
    60  func (set *ErrorSet) Error() string {
    61  	errs := set.Flatten()
    62  
    63  	buf := bytes.Buffer{}
    64  	errs.Each(
    65  		func(f *FieldError) {
    66  			buf.WriteString(fmt.Sprintf("%s %s", f.Field, f.Error))
    67  			buf.WriteRune('\n')
    68  		},
    69  	)
    70  
    71  	return buf.String()
    72  }
    73  
    74  type Location string
    75  
    76  func (set *ErrorSet) ToErrorFields() statusx.ErrorFields {
    77  	errorFields := make([]*statusx.ErrorField, 0)
    78  
    79  	set.Flatten().Each(func(fieldErr *FieldError) {
    80  		if len(fieldErr.Field) > 0 {
    81  			if l, ok := fieldErr.Field[0].(Location); ok {
    82  				errorFields = append(errorFields, &statusx.ErrorField{
    83  					In:    string(l),
    84  					Field: fieldErr.Field[1:].String(),
    85  					Msg:   fieldErr.Error.Error(),
    86  				})
    87  			}
    88  		}
    89  	})
    90  
    91  	return errorFields
    92  }
    93  
    94  type FieldError struct {
    95  	Field KeyPath
    96  	Error error `json:"msg"`
    97  }
    98  
    99  type KeyPath []interface{}
   100  
   101  func (keyPath KeyPath) String() string {
   102  	buf := &bytes.Buffer{}
   103  	for i := 0; i < len(keyPath); i++ {
   104  		switch keyOrIndex := keyPath[i].(type) {
   105  		case string:
   106  			if buf.Len() > 0 {
   107  				buf.WriteRune('.')
   108  			}
   109  			buf.WriteString(keyOrIndex)
   110  		case int:
   111  			buf.WriteString(fmt.Sprintf("[%d]", keyOrIndex))
   112  		}
   113  	}
   114  	return buf.String()
   115  }