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 }