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

     1  package validator
     2  
     3  import (
     4  	"context"
     5  	"encoding"
     6  	"fmt"
     7  	"reflect"
     8  
     9  	"github.com/machinefi/w3bstream/pkg/depends/kit/validator/errors"
    10  	"github.com/machinefi/w3bstream/pkg/depends/kit/validator/rules"
    11  	"github.com/machinefi/w3bstream/pkg/depends/x/contextx"
    12  	"github.com/machinefi/w3bstream/pkg/depends/x/reflectx"
    13  	"github.com/machinefi/w3bstream/pkg/depends/x/textx"
    14  	"github.com/machinefi/w3bstream/pkg/depends/x/typesx"
    15  )
    16  
    17  // Validator can validate input value
    18  type Validator interface {
    19  	Validate(interface{}) error
    20  	String() string
    21  }
    22  
    23  type CanValidate interface {
    24  	Validate() error
    25  }
    26  
    27  // Creator interface can new a validator
    28  type Creator interface {
    29  	Names() []string
    30  	New(context.Context, *Rule) (Validator, error)
    31  }
    32  
    33  // Modifier can change rule's option
    34  type Modifier interface {
    35  	SetOptional(opt bool)
    36  	SetDefaultValue(dft []byte)
    37  	SetErrMsg(err []byte)
    38  }
    39  
    40  type Processor = func(rule Modifier)
    41  
    42  // Rule with internal error message and type identifier
    43  type Rule struct {
    44  	*rules.Rule
    45  	ErrMsg []byte
    46  	Type   typesx.Type
    47  }
    48  
    49  func ParseRuleByType(r []byte, t typesx.Type) (*Rule, error) {
    50  	rule := &rules.Rule{}
    51  	if len(r) != 0 {
    52  		parsed, err := rules.ParseRaw(r)
    53  		if err != nil {
    54  			return nil, err
    55  		}
    56  		rule = parsed
    57  	}
    58  	return &Rule{Rule: rule, Type: t}, nil
    59  }
    60  
    61  func ParseRuleStringByType(r string, t typesx.Type) (*Rule, error) {
    62  	return ParseRuleByType([]byte(r), t)
    63  }
    64  
    65  func MustParseRuleByType(r []byte, t typesx.Type) *Rule {
    66  	rule, err := ParseRuleByType(r, t)
    67  	if err != nil {
    68  		panic(err)
    69  	}
    70  	return rule
    71  }
    72  
    73  func MustParseRuleStringByType(r string, t typesx.Type) *Rule {
    74  	return MustParseRuleByType([]byte(r), t)
    75  }
    76  
    77  func (r *Rule) SetOptional(opt bool) { r.Optional = opt }
    78  
    79  func (r *Rule) SetDefaultValue(dft []byte) { r.DftValue = dft }
    80  
    81  func (r *Rule) SetErrMsg(msg []byte) { r.ErrMsg = msg }
    82  
    83  func (r *Rule) String() string {
    84  	return typesx.FullTypeName(r.Type) + string(r.Rule.Bytes())
    85  }
    86  
    87  type Factory interface {
    88  	Compile(context.Context, []byte, typesx.Type, ...Processor) (Validator, error)
    89  }
    90  
    91  type ckCompiler struct{}
    92  
    93  func ContextWithFactory(ctx context.Context, c Factory) context.Context {
    94  	return contextx.WithValue(ctx, ckCompiler{}, c)
    95  }
    96  
    97  func FactoryFromContext(ctx context.Context) Factory {
    98  	if f, ok := ctx.Value(ckCompiler{}).(Factory); ok {
    99  		return f
   100  	}
   101  	return DefaultFactory
   102  }
   103  
   104  type factory struct {
   105  	set map[string]Creator
   106  }
   107  
   108  var DefaultFactory = NewFactory()
   109  
   110  func NewFactory() *factory { return &factory{set: make(map[string]Creator)} }
   111  
   112  func (f *factory) Register(creators ...Creator) {
   113  	for i := range creators {
   114  		for _, name := range creators[i].Names() {
   115  			f.set[name] = creators[i]
   116  		}
   117  	}
   118  }
   119  
   120  func (f *factory) MustCompile(ctx context.Context, rule []byte, t typesx.Type, processors ...Processor) Validator {
   121  	v, err := f.Compile(ctx, rule, t, processors...)
   122  	if err != nil {
   123  		panic(err)
   124  	}
   125  	return v
   126  }
   127  
   128  func (f *factory) Compile(ctx context.Context, rule []byte, t typesx.Type, processors ...Processor) (Validator, error) {
   129  	if ctx == nil {
   130  		ctx = context.Background()
   131  	}
   132  	if len(rule) == 0 {
   133  		if _, ok := typesx.EncodingTextMarshalerTypeReplacer(t); !ok {
   134  			switch typesx.DeRef(t).Kind() {
   135  			case reflect.Struct:
   136  				rule = []byte("@struct")
   137  			case reflect.Slice:
   138  				rule = []byte("@slice")
   139  			case reflect.Map:
   140  				rule = []byte("@map")
   141  			}
   142  		}
   143  	}
   144  	r, err := ParseRuleByType(rule, t)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  	for _, proc := range processors {
   149  		if proc != nil {
   150  			proc(r)
   151  		}
   152  	}
   153  	creator, ok := f.set[r.Name]
   154  	if !ok && len(rule) > 0 {
   155  		return nil, fmt.Errorf("%s not match any validator", r.Name)
   156  	}
   157  	return NewLoader(creator).New(ContextWithFactory(ctx, f), r)
   158  }
   159  
   160  type PreprocessStage int
   161  
   162  const (
   163  	PreprocessSkip PreprocessStage = iota
   164  	PreprocessString
   165  	PreprocessPtr
   166  )
   167  
   168  // Loader load from creator
   169  type Loader struct {
   170  	Creator Creator
   171  	Validator
   172  	PreprocessStage
   173  
   174  	DftValue []byte
   175  	Optional bool
   176  	ErrMsg   []byte
   177  }
   178  
   179  func NewLoader(c Creator) *Loader { return &Loader{Creator: c} }
   180  
   181  func normalize(typ typesx.Type) (typesx.Type, PreprocessStage) {
   182  	if t, ok := typesx.EncodingTextMarshalerTypeReplacer(typ); ok {
   183  		return t, PreprocessString
   184  	}
   185  	if typ.Kind() == reflect.Ptr {
   186  		return typesx.DeRef(typ), PreprocessPtr
   187  	}
   188  	return typ, PreprocessSkip
   189  }
   190  
   191  func (l *Loader) String() string {
   192  	if l.Validator != nil {
   193  		v := l.Validator.String()
   194  
   195  		if l.Optional {
   196  			if l.DftValue != nil {
   197  				return v + " = " + string(rules.SingleQuote(l.DftValue))
   198  			}
   199  			return v + "?"
   200  		}
   201  
   202  		return v
   203  	}
   204  	return "nil"
   205  }
   206  
   207  func (l *Loader) New(ctx context.Context, rule *Rule) (Validator, error) {
   208  	ret := NewLoader(l.Creator)
   209  
   210  	ret.Optional = rule.Optional
   211  	ret.DftValue = rule.DftValue
   212  	ret.ErrMsg = rule.ErrMsg
   213  
   214  	typ := rule.Type
   215  	rule.Type, ret.PreprocessStage = normalize(rule.Type)
   216  
   217  	if l.Creator != nil {
   218  		v, err := l.Creator.New(ctx, rule)
   219  		if err != nil {
   220  			return nil, err
   221  		}
   222  		ret.Validator = v
   223  
   224  		if ret.DftValue != nil {
   225  			if rv, ok := typesx.TryNew(typ); ok {
   226  				if err := textx.UnmarshalText(rv, ret.DftValue); err != nil {
   227  					return nil, fmt.Errorf(
   228  						"default value `%s` can not unmarshal to %s: %s",
   229  						ret.DftValue, typ, err,
   230  					)
   231  				}
   232  				if err := ret.Validate(rv); err != nil {
   233  					return nil, fmt.Errorf(
   234  						"default value `%s` is not a valid value of %s: %s",
   235  						ret.DftValue, v, err,
   236  					)
   237  				}
   238  			}
   239  		}
   240  	}
   241  
   242  	return ret, nil
   243  }
   244  
   245  func (l *Loader) Validate(v interface{}) error {
   246  	err := l.validate(v)
   247  	if err == nil {
   248  		return nil
   249  	}
   250  	if l.ErrMsg != nil && len(l.ErrMsg) != 0 {
   251  		return fmt.Errorf(string(l.ErrMsg))
   252  	}
   253  	return err
   254  }
   255  
   256  func (l *Loader) validate(v interface{}) error {
   257  	rv, ok := v.(reflect.Value)
   258  	if !ok {
   259  		rv = reflect.ValueOf(v)
   260  	}
   261  
   262  	if reflectx.IsEmptyValue(rv) {
   263  		if !l.Optional {
   264  			return errors.MissingRequiredFieldError{}
   265  		}
   266  
   267  		if l.DftValue != nil && rv.CanSet() {
   268  			if err := textx.UnmarshalText(rv, l.DftValue); err != nil {
   269  				return fmt.Errorf("unmarshal default value failed")
   270  			}
   271  		}
   272  		// empty value should not to validate
   273  		return nil
   274  	}
   275  
   276  	if l.Validator == nil {
   277  		return nil
   278  	}
   279  
   280  	if l.PreprocessStage == PreprocessString {
   281  		// make sure value over reflect.Value
   282  		if rv.CanInterface() {
   283  			v = rv.Interface()
   284  		}
   285  
   286  		if marshaller, ok := v.(encoding.TextMarshaler); ok {
   287  			data, err := marshaller.MarshalText()
   288  			if err != nil {
   289  				return err
   290  			}
   291  			return l.Validator.Validate(string(data))
   292  		}
   293  	}
   294  
   295  	if rv.Kind() == reflect.Interface {
   296  		rv = rv.Elem()
   297  	}
   298  
   299  	return l.Validator.Validate(reflectx.Indirect(rv))
   300  }