-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathobject.go
99 lines (74 loc) · 1.95 KB
/
object.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package schema
import (
"fmt"
"reflect"
)
type ObjectSchema struct {
value map[string]ISchema
Schema[map[string]interface{}]
}
var _ ISchema = (*ObjectSchema)(nil)
func Object(obj map[string]ISchema) *ObjectSchema {
return &ObjectSchema{value: obj}
}
func (s *ObjectSchema) Refine(predicate func(map[string]interface{}) bool) *ObjectSchema {
validator := Validator[map[string]interface{}]{
MessageFunc: func(value map[string]interface{}) string {
return "Invalid input"
},
ValidateFunc: predicate,
}
s.validators = append(s.validators, validator)
return s
}
func (s *ObjectSchema) Parse(value any) *ValidationResult {
t := reflect.TypeOf(value)
if t == nil || t.Kind() != reflect.Struct {
return &ValidationResult{Errors: []ValidationError{{Path: "", Message: fmt.Sprintf("Expected struct, got %T", value)}}}
}
val := reflect.ValueOf(value)
res := &ValidationResult{}
for key, schema := range s.value {
if _, ok := t.FieldByName(key); !ok {
err := ValidationError{
Path: key,
Message: "Required",
}
res.Errors = append(res.Errors, err)
continue
}
str := val.FieldByName(key).Interface()
result := schema.Parse(str)
if !result.IsValid() {
for _, err := range result.Errors {
newError := ValidationError{
Path: formatPath(key, err.Path),
Message: err.Message,
}
res.Errors = append(res.Errors, newError)
}
}
}
valueMap := structToMap(value)
for _, validator := range s.validators {
if !validator.ValidateFunc(valueMap) {
err := ValidationError{
Path: "",
Message: validator.MessageFunc(valueMap),
}
res.Errors = append(res.Errors, err)
}
}
return res
}
func structToMap(item interface{}) map[string]interface{} {
result := map[string]interface{}{}
val := reflect.ValueOf(item)
typ := reflect.TypeOf(item)
for i := 0; i < val.NumField(); i++ {
field := typ.Field(i)
value := val.Field(i).Interface()
result[field.Name] = value
}
return result
}