Skip to content

Commit 892f312

Browse files
committed
add untagged fields for no validation
1 parent 4977ddd commit 892f312

4 files changed

Lines changed: 130 additions & 136 deletions

File tree

model/validation.go

Lines changed: 0 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
package model
22

3-
import (
4-
"fmt"
5-
"reflect"
6-
"strings"
7-
8-
"github.com/siherrmann/validator/helper"
9-
)
10-
113
// Default tag type.
124
const VLD string = "vld"
135

@@ -22,83 +14,6 @@ type Validation struct {
2214
InnerValidation []Validation
2315
}
2416

25-
// GetValidationsFromStruct extracts validation rules from a struct based on the provided tag type.
26-
// It iterates over the struct fields, checks for the specified tag type, and constructs Validation.
27-
func GetValidationsFromStruct(in any, tagType string) ([]Validation, error) {
28-
err := helper.CheckValidPointerToStruct(in)
29-
if err != nil {
30-
return nil, err
31-
}
32-
33-
validations := []Validation{}
34-
35-
structFull := reflect.ValueOf(in).Elem()
36-
for i := 0; i < structFull.Type().NumField(); i++ {
37-
field := structFull.Field(i)
38-
fieldType := structFull.Type().Field(i)
39-
40-
validation, err := GetValidationFromStructField(tagType, field, fieldType)
41-
if err != nil {
42-
return nil, err
43-
}
44-
45-
if len(validation.Requirement) > 0 {
46-
validations = append(validations, validation)
47-
}
48-
}
49-
return validations, nil
50-
}
51-
52-
// GetValidationFromStructField extracts validation rules from a struct field based on the provided tag type.
53-
// It checks the field's tag for the specified tag type and constructs a Validation object.
54-
// If no json tag is found, it uses the field name as the key.
55-
func GetValidationFromStructField(tagType string, fieldValue reflect.Value, fieldType reflect.StructField) (Validation, error) {
56-
validation := Validation{}
57-
validation.Key = fieldType.Name
58-
if len(fieldType.Tag.Get("json")) > 0 {
59-
validation.Key = fieldType.Tag.Get("json")
60-
}
61-
validation.Type = ReflectKindToValidatorType(fieldValue.Type().Kind())
62-
validation.Requirement = "-"
63-
64-
tagIndex := 0
65-
tagSplit := strings.Split(fieldType.Tag.Get(string(tagType)), ", ")
66-
67-
if len(tagSplit) > tagIndex {
68-
if len(tagSplit[tagIndex]) <= 3 && tagSplit[tagIndex] != "-" {
69-
return Validation{}, fmt.Errorf("invalid requirement %v for field %v", tagSplit[tagIndex], fieldType.Name)
70-
}
71-
validation.Requirement = tagSplit[tagIndex]
72-
tagIndex++
73-
}
74-
75-
if len(tagSplit) > tagIndex {
76-
var err error
77-
validation.Groups, err = GetGroups(tagSplit[tagIndex])
78-
if err != nil {
79-
return Validation{}, fmt.Errorf("error extracting group: %v", err)
80-
}
81-
}
82-
83-
if helper.IsArrayOfStruct(fieldValue.Interface()) {
84-
innerStruct := reflect.New(fieldValue.Type().Elem()).Interface()
85-
innerValidation, err := GetValidationsFromStruct(innerStruct, string(tagType))
86-
if err != nil {
87-
return Validation{}, fmt.Errorf("error getting inner validation from array: %v", err)
88-
}
89-
validation.InnerValidation = append(validation.InnerValidation, innerValidation...)
90-
} else if helper.IsStruct(fieldValue.Interface()) {
91-
innerStruct := reflect.New(fieldValue.Type()).Interface()
92-
innerValidation, err := GetValidationsFromStruct(innerStruct, string(tagType))
93-
if err != nil {
94-
return Validation{}, fmt.Errorf("error getting inner validation from struct: %v", err)
95-
}
96-
validation.InnerValidation = append(validation.InnerValidation, innerValidation...)
97-
}
98-
99-
return validation, nil
100-
}
101-
10217
// ValidatorMap is a map of validation keys to Validation objects.
10318
// It is used to store and manage multiple validation rules for different struct fields.
10419
type ValidatorMap map[string]Validation
Lines changed: 38 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
package model
1+
package validator
22

33
import (
44
"testing"
55

6+
"github.com/siherrmann/validator/model"
67
"github.com/stretchr/testify/assert"
78
)
89

@@ -14,7 +15,7 @@ func TestGetValidationsFromStruct(t *testing.T) {
1415
tests := []struct {
1516
name string
1617
args args
17-
expected []Validation
18+
expected []model.Validation
1819
expectedError bool
1920
}{
2021
{
@@ -24,11 +25,11 @@ func TestGetValidationsFromStruct(t *testing.T) {
2425
Field1 string `vld:"equ1, gr1min1"`
2526
Field2 int `vld:"min2, gr1min1"`
2627
}{},
27-
tagType: VLD,
28+
tagType: model.VLD,
2829
},
29-
expected: []Validation{
30-
{Key: "Field1", Type: String, Requirement: "equ1", Groups: []*Group{{Name: "gr1", ConditionType: "min", ConditionValue: "1"}}},
31-
{Key: "Field2", Type: Int, Requirement: "min2", Groups: []*Group{{Name: "gr1", ConditionType: "min", ConditionValue: "1"}}},
30+
expected: []model.Validation{
31+
{Key: "Field1", Type: model.String, Requirement: "equ1", Groups: []*model.Group{{Name: "gr1", ConditionType: "min", ConditionValue: "1"}}},
32+
{Key: "Field2", Type: model.Int, Requirement: "min2", Groups: []*model.Group{{Name: "gr1", ConditionType: "min", ConditionValue: "1"}}},
3233
},
3334
expectedError: false,
3435
},
@@ -41,9 +42,9 @@ func TestGetValidationsFromStruct(t *testing.T) {
4142
}{},
4243
tagType: "upd",
4344
},
44-
expected: []Validation{
45-
{Key: "Field1", Type: String, Requirement: "equ1"},
46-
{Key: "Field2", Type: Int, Requirement: "min2"},
45+
expected: []model.Validation{
46+
{Key: "Field1", Type: model.String, Requirement: "equ1"},
47+
{Key: "Field2", Type: model.Int, Requirement: "min2"},
4748
},
4849
expectedError: false,
4950
},
@@ -54,11 +55,11 @@ func TestGetValidationsFromStruct(t *testing.T) {
5455
Field1 string `json:"field1" vld:"equ1"`
5556
Field2 int `json:"field2" vld:"min2"`
5657
}{},
57-
tagType: VLD,
58+
tagType: model.VLD,
5859
},
59-
expected: []Validation{
60-
{Key: "field1", Type: String, Requirement: "equ1"},
61-
{Key: "field2", Type: Int, Requirement: "min2"},
60+
expected: []model.Validation{
61+
{Key: "field1", Type: model.String, Requirement: "equ1"},
62+
{Key: "field2", Type: model.Int, Requirement: "min2"},
6263
},
6364
expectedError: false,
6465
},
@@ -70,11 +71,11 @@ func TestGetValidationsFromStruct(t *testing.T) {
7071
Name string `json:"name" vld:"equ1"`
7172
} `json:"field1" vld:"-"`
7273
}{},
73-
tagType: VLD,
74+
tagType: model.VLD,
7475
},
75-
expected: []Validation{
76-
{Key: "field1", Type: Struct, Requirement: "-", InnerValidation: []Validation{
77-
{Key: "name", Type: String, Requirement: "equ1"},
76+
expected: []model.Validation{
77+
{Key: "field1", Type: model.Struct, Requirement: "-", InnerValidation: []model.Validation{
78+
{Key: "name", Type: model.String, Requirement: "equ1"},
7879
}},
7980
},
8081
expectedError: false,
@@ -87,28 +88,15 @@ func TestGetValidationsFromStruct(t *testing.T) {
8788
Name string `json:"name" vld:"equ1"`
8889
} `json:"field1" vld:"min1"`
8990
}{},
90-
tagType: VLD,
91+
tagType: model.VLD,
9192
},
92-
expected: []Validation{
93-
{Key: "field1", Type: Array, Requirement: "min1", InnerValidation: []Validation{
94-
{Key: "name", Type: String, Requirement: "equ1"},
93+
expected: []model.Validation{
94+
{Key: "field1", Type: model.Array, Requirement: "min1", InnerValidation: []model.Validation{
95+
{Key: "name", Type: model.String, Requirement: "equ1"},
9596
}},
9697
},
9798
expectedError: false,
9899
},
99-
{
100-
name: "Valid struct with invalid struct validation",
101-
args: args{
102-
input: &struct {
103-
Field1 []struct {
104-
Name string `json:"name" vld:"equ"`
105-
} `json:"field1" vld:"min1"`
106-
}{},
107-
tagType: VLD,
108-
},
109-
expected: []Validation{},
110-
expectedError: true,
111-
},
112100
{
113101
name: "Valid struct with invalid inner group",
114102
args: args{
@@ -117,31 +105,32 @@ func TestGetValidationsFromStruct(t *testing.T) {
117105
Name string `json:"name" vld:"equ1, gr"`
118106
} `json:"field1" vld:"min1"`
119107
}{},
120-
tagType: VLD,
108+
tagType: model.VLD,
121109
},
122-
expected: []Validation{},
110+
expected: []model.Validation{},
123111
expectedError: true,
124112
},
125113
{
126-
name: "Valid struct with invalid inner struct validation",
114+
name: "Valid struct with valid ignored field",
127115
args: args{
128116
input: &struct {
129-
Field1 struct {
130-
Name string `json:"name" vld:"equ"`
131-
} `json:"field1" vld:"-"`
117+
Name string `json:"name"`
118+
Field1 string `json:"field1" vld:"-"`
132119
}{},
133-
tagType: VLD,
120+
tagType: model.VLD,
134121
},
135-
expected: []Validation{},
136-
expectedError: true,
122+
expected: []model.Validation{
123+
{Key: "field1", Type: model.String, Requirement: "-"},
124+
},
125+
expectedError: false,
137126
},
138127
{
139128
name: "Empty struct",
140129
args: args{
141130
input: &struct{}{},
142-
tagType: VLD,
131+
tagType: model.VLD,
143132
},
144-
expected: []Validation{},
133+
expected: []model.Validation{},
145134
expectedError: false,
146135
},
147136
{
@@ -150,18 +139,18 @@ func TestGetValidationsFromStruct(t *testing.T) {
150139
input: &struct {
151140
Field1 string `vld:"equ1, gr"`
152141
}{},
153-
tagType: VLD,
142+
tagType: model.VLD,
154143
},
155-
expected: []Validation{},
144+
expected: []model.Validation{},
156145
expectedError: true,
157146
},
158147
{
159148
name: "Invalid struct type",
160149
args: args{
161150
input: struct{}{},
162-
tagType: VLD,
151+
tagType: model.VLD,
163152
},
164-
expected: []Validation{},
153+
expected: []model.Validation{},
165154
expectedError: true,
166155
},
167156
}

validator.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func (r *Validator) Validate(v any, tagType ...string) error {
4646
return fmt.Errorf("error unmapping struct to json map: %v", err)
4747
}
4848

49-
validations, err := model.GetValidationsFromStruct(v, tagTypeSet)
49+
validations, err := GetValidationsFromStruct(v, tagTypeSet)
5050
if err != nil {
5151
return fmt.Errorf("error getting validations from struct: %v", err)
5252
}
@@ -68,7 +68,7 @@ func (r *Validator) ValidateAndUpdate(jsonInput map[string]any, structToUpdate a
6868
tagTypeSet = tagType[0]
6969
}
7070

71-
validations, err := model.GetValidationsFromStruct(structToUpdate, tagTypeSet)
71+
validations, err := GetValidationsFromStruct(structToUpdate, tagTypeSet)
7272
if err != nil {
7373
return fmt.Errorf("error getting validations from struct: %v", err)
7474
}

validatorExtract.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package validator
2+
3+
import (
4+
"fmt"
5+
"reflect"
6+
"strings"
7+
8+
"github.com/siherrmann/validator/helper"
9+
"github.com/siherrmann/validator/model"
10+
)
11+
12+
// GetValidationsFromStruct extracts validation rules from a struct based on the provided tag type.
13+
// It iterates over the struct fields, checks for the specified tag type, and constructs Validation.
14+
func GetValidationsFromStruct(in any, tagType string) ([]model.Validation, error) {
15+
err := helper.CheckValidPointerToStruct(in)
16+
if err != nil {
17+
return nil, err
18+
}
19+
20+
validations := []model.Validation{}
21+
22+
structFull := reflect.ValueOf(in).Elem()
23+
for i := 0; i < structFull.Type().NumField(); i++ {
24+
field := structFull.Field(i)
25+
fieldType := structFull.Type().Field(i)
26+
27+
validation, err := GetValidationFromStructField(tagType, field, fieldType)
28+
if err != nil {
29+
return nil, err
30+
} else if validation == nil {
31+
continue
32+
}
33+
34+
if len(validation.Requirement) > 0 {
35+
validations = append(validations, *validation)
36+
}
37+
}
38+
return validations, nil
39+
}
40+
41+
// GetValidationFromStructField extracts validation rules from a struct field based on the provided tag type.
42+
// It checks the field's tag for the specified tag type and constructs a Validation object.
43+
// If no json tag is found, it uses the field name as the key.
44+
func GetValidationFromStructField(tagType string, fieldValue reflect.Value, fieldType reflect.StructField) (*model.Validation, error) {
45+
validation := &model.Validation{}
46+
validation.Key = fieldType.Name
47+
if len(fieldType.Tag.Get("json")) > 0 {
48+
validation.Key = fieldType.Tag.Get("json")
49+
}
50+
validation.Type = model.ReflectKindToValidatorType(fieldValue.Type().Kind())
51+
validation.Requirement = "-"
52+
53+
tagIndex := 0
54+
tagSplit := strings.Split(fieldType.Tag.Get(string(tagType)), ", ")
55+
56+
if len(tagSplit) > tagIndex {
57+
// Ignore if tag is empty, we do not want to validate this field at all
58+
if len(tagSplit[tagIndex]) <= 3 && tagSplit[tagIndex] != "-" {
59+
return nil, nil
60+
}
61+
validation.Requirement = tagSplit[tagIndex]
62+
tagIndex++
63+
}
64+
65+
if len(tagSplit) > tagIndex {
66+
var err error
67+
validation.Groups, err = model.GetGroups(tagSplit[tagIndex])
68+
if err != nil {
69+
return nil, fmt.Errorf("error extracting group: %v", err)
70+
}
71+
}
72+
73+
if helper.IsArrayOfStruct(fieldValue.Interface()) {
74+
innerStruct := reflect.New(fieldValue.Type().Elem()).Interface()
75+
innerValidation, err := GetValidationsFromStruct(innerStruct, string(tagType))
76+
if err != nil {
77+
return nil, fmt.Errorf("error getting inner validation from array: %v", err)
78+
}
79+
validation.InnerValidation = append(validation.InnerValidation, innerValidation...)
80+
} else if helper.IsStruct(fieldValue.Interface()) {
81+
innerStruct := reflect.New(fieldValue.Type()).Interface()
82+
innerValidation, err := GetValidationsFromStruct(innerStruct, string(tagType))
83+
if err != nil {
84+
return nil, fmt.Errorf("error getting inner validation from struct: %v", err)
85+
}
86+
validation.InnerValidation = append(validation.InnerValidation, innerValidation...)
87+
}
88+
89+
return validation, nil
90+
}

0 commit comments

Comments
 (0)