Skip to content

Commit

Permalink
Removed the necessity for validate:"required" [#9]
Browse files Browse the repository at this point in the history
  It was removed the necessity for validate:"<some-parameter>"
to validate Slice and Structs in others levels.
  • Loading branch information
guiferpa committed Apr 10, 2020
1 parent eaa6c3e commit c3dcd5a
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 30 deletions.
13 changes: 7 additions & 6 deletions examples/http_api.go
Expand Up @@ -16,7 +16,9 @@ func (err *ErrIsAdult) Error() string {
return "The client isn't a adult then it isn't allowed buy"
}

type IsAdultRule struct{}
type IsAdultRule struct {
adultAge int
}

func (r *IsAdultRule) Name() string {
return "is_adult"
Expand All @@ -27,13 +29,12 @@ func (r *IsAdultRule) Validate(_, value, _ string) (bool, error) {
return true, &ErrIsAdult{}
}

adultAge := 21
clientAge, err := strconv.Atoi(value)
if err != nil {
return false, err
}

if clientAge < adultAge {
if clientAge < r.adultAge {
return true, &ErrIsAdult{}
}

Expand All @@ -52,15 +53,15 @@ type Product struct {
}

type Cart struct {
Owner User `validate:"required"`
Products []Product `validate:"required"`
Owner User
Products []Product
}

func HTTPServerAPI() {
validator := gody.NewValidator()

rules := []gody.Rule{
&IsAdultRule{},
&IsAdultRule{adultAge: 21},
}
if err := validator.AddRules(rules); err != nil {
log.Fatalln(err)
Expand Down
42 changes: 23 additions & 19 deletions serialize.go
Expand Up @@ -48,7 +48,7 @@ func Serialize(b interface{}) ([]Field, error) {
for i := 0; i < typeOf.NumField(); i++ {
field := typeOf.Field(i)
tagString := field.Tag.Get("validate")
if tagString == "" {
if tagString == "" && field.Type.Kind() != reflect.Slice && field.Type.Kind() != reflect.Struct {
continue
}

Expand Down Expand Up @@ -81,35 +81,39 @@ func Serialize(b interface{}) ([]Field, error) {
fieldValue := valueOf.FieldByName(field.Name)
fieldNameToLower := strings.ToLower(field.Name)
if kindOfField := field.Type.Kind(); kindOfField == reflect.Struct {
payload := fieldValue.Convert(field.Type).Interface()
serialized, err := Serialize(payload)
if err != nil {
return nil, err
}
for _, item := range serialized {
fields = append(fields, Field{
Name: fmt.Sprintf("%s.%s", fieldNameToLower, item.Name),
Value: item.Value,
Tags: item.Tags,
})
}
} else if kindOfField := field.Type.Kind(); kindOfField == reflect.Slice {
j := fieldValue.Len()
for i := 0; i < j; i++ {
sliceFieldValue := fieldValue.Index(i)
payload := sliceFieldValue.Convert(sliceFieldValue.Type()).Interface()
if fieldConverted := fieldValue.Convert(fieldValue.Type()); fieldConverted.CanInterface() {
payload := fieldConverted.Interface()
serialized, err := Serialize(payload)
if err != nil {
return nil, err
}
for _, item := range serialized {
fields = append(fields, Field{
Name: fmt.Sprintf("%s[%v].%s", fieldNameToLower, i, item.Name),
Name: fmt.Sprintf("%s.%s", fieldNameToLower, item.Name),
Value: item.Value,
Tags: item.Tags,
})
}
}
} else if kindOfField := field.Type.Kind(); kindOfField == reflect.Slice {
j := fieldValue.Len()
for i := 0; i < j; i++ {
sliceFieldValue := fieldValue.Index(i)
if sliceFieldConverted := sliceFieldValue.Convert(sliceFieldValue.Type()); sliceFieldConverted.CanInterface() {
payload := sliceFieldValue.Convert(sliceFieldValue.Type()).Interface()
serialized, err := Serialize(payload)
if err != nil {
return nil, err
}
for _, item := range serialized {
fields = append(fields, Field{
Name: fmt.Sprintf("%s[%v].%s", fieldNameToLower, i, item.Name),
Value: item.Value,
Tags: item.Tags,
})
}
}
}
} else {
fieldValueString := fmt.Sprintf("%v", fieldValue)
fields = append(fields, Field{
Expand Down
42 changes: 37 additions & 5 deletions serialize_test.go
Expand Up @@ -16,8 +16,8 @@ type TestSerializeStructB struct {

type TestSerializeStructC struct {
c string
b TestSerializeStructB
a TestSerializeStructA
B TestSerializeStructB
A TestSerializeStructA
}

func TestSerializeBodyStruct(t *testing.T) {
Expand All @@ -28,7 +28,7 @@ func TestSerializeBodyStruct(t *testing.T) {
{map[string]string{"test-key": "test-value"}, false},
{TestSerializeStructA{a: "a"}, true},
{TestSerializeStructB{b: "b", a: TestSerializeStructA{a: "a"}}, true},
{TestSerializeStructC{c: "c", b: TestSerializeStructB{b: "b", a: TestSerializeStructA{a: "a"}}, a: TestSerializeStructA{a: "a"}}, true},
{TestSerializeStructC{c: "c", B: TestSerializeStructB{b: "b", a: TestSerializeStructA{a: "a"}}, A: TestSerializeStructA{a: "a"}}, true},
{10, false},
{struct{}{}, true},
{"", false},
Expand Down Expand Up @@ -110,8 +110,8 @@ type TestSerializeSliceA struct {

func TestSliceSerialize(t *testing.T) {
body := struct {
A string `validate:"test"`
B []TestSerializeSliceA `validate:"required"`
A string `validate:"test"`
B []TestSerializeSliceA
}{"a-value", []TestSerializeSliceA{{10}, {}}}

fields, err := Serialize(body)
Expand All @@ -136,6 +136,38 @@ func TestSliceSerialize(t *testing.T) {
}
}

type TestSerializeStructE struct {
a string `validate:"test-private-struct-field=300"`
}

type TestSerializeStructD struct {
J string `validate:"test-struct"`
I TestSerializeStructE
}

func TestStructSlice(t *testing.T) {
body := struct {
A string `validate:"test"`
B TestSerializeStructD
}{"a-value", TestSerializeStructD{J: "j-test-struct", I: TestSerializeStructE{a: "a-test-private-struct-field"}}}

fields, err := Serialize(body)
if err != nil {
t.Error(err)
return
}

wantedFields := []Field{
{Name: "a", Value: "a-value", Tags: map[string]string{"test": ""}},
{Name: "b.j", Value: "j-test-struct", Tags: map[string]string{"test-struct": ""}},
{Name: "b.i.a", Value: "a-test-private-struct-field", Tags: map[string]string{"test-private-struct-field": "300"}},
}
if got, want := fmt.Sprint(fields), fmt.Sprint(wantedFields); got != want {
t.Errorf("Serialized fields unexpected: got: %v want: %v", got, want)
return
}
}

func BenchmarkSerializeBodyStruct(b *testing.B) {
b.ResetTimer()
body := map[string]string{"test-key": "test-value"}
Expand Down

0 comments on commit c3dcd5a

Please sign in to comment.