-
Notifications
You must be signed in to change notification settings - Fork 3
/
orwell.go
108 lines (91 loc) · 2.25 KB
/
orwell.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
100
101
102
103
104
105
106
107
108
package orwell
import (
"reflect"
)
type (
//Rule interface
Rule interface {
Apply(v interface{}) error
}
// FieldableError interface
FieldableError interface {
error
FieldName() string
JSONName() string
}
// InternalError interface
InternalError interface {
error
InternalError() error
}
// IterableError interface
IterableError interface {
error
Len() int
ValueAt(int) error
}
// Orwell struct
Orwell struct{}
fieldRules struct {
fieldPtr interface{}
rules []Rule
}
)
// NewValidator func
func NewValidator() *Orwell {
return &Orwell{}
}
// Validate func
func (o *Orwell) Validate(v interface{}, rules ...Rule) error {
for _, r := range rules {
if err := r.Apply(v); err != nil {
return err
}
}
return nil
}
// ValidateStruct func
func (o *Orwell) ValidateStruct(structPtr interface{}, fieldRules ...*fieldRules) error {
structElem := reflect.ValueOf(structPtr).Elem()
var structValidationError structValidationError
for _, fieldRule := range fieldRules {
fieldValue := reflect.ValueOf(fieldRule.fieldPtr)
if err := o.Validate(fieldValue.Elem().Interface(), fieldRule.rules...); err != nil {
if ie, ok := err.(InternalError); ok {
return ie
}
fieldName, jsonName := names(structElem, fieldValue)
structValidationError.errors = append(structValidationError.errors, NewValidationError(fieldName, jsonName, err.Error()))
}
}
if len(structValidationError.errors) > 0 {
return &structValidationError
}
return nil
}
// FieldRules func
func (o *Orwell) FieldRules(field interface{}, rules ...Rule) *fieldRules {
return &fieldRules{
fieldPtr: field,
rules: rules,
}
}
var fieldName, jsonName string
func names(structElem reflect.Value, fieldValue reflect.Value) (string, string) {
fieldPointer := fieldValue.Pointer()
for i := 0; i < structElem.NumField(); i++ {
structField := structElem.Type().Field(i)
if (fieldPointer == structElem.Field(i).UnsafeAddr()) && (structField.Type == fieldValue.Elem().Type()) {
fieldName = structField.Name
if str, ok := structField.Tag.Lookup("json"); ok {
jsonName = str
}
return fieldName, jsonName
}
switch structElem.Field(i).Kind() {
case reflect.Struct:
names(structElem.Field(i), fieldValue)
}
}
return fieldName, jsonName
}