Skip to content

Commit

Permalink
Merge pull request #98 from rezakhademix/add-custom-rule-method
Browse files Browse the repository at this point in the history
feat: custom rule method added
  • Loading branch information
rezakhademix authored May 30, 2024
2 parents 22232ad + 5b602dd commit bc079bd
Show file tree
Hide file tree
Showing 18 changed files with 123 additions and 27 deletions.
2 changes: 1 addition & 1 deletion after.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const (
// fmt.Printf("validation errors: %#v\n", v.Errors())
// }
func (v Validator) After(t, u time.Time, field, msg string) Validator {
v.Check(t.After(u), field, v.msg(After, msg, field, u))
v.check(t.After(u), field, v.msg(After, msg, field, u))

return v
}
2 changes: 1 addition & 1 deletion before.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const (
// fmt.Printf("validation errors: %#v\n", v.Errors())
// }
func (v Validator) Before(t, u time.Time, field, msg string) Validator {
v.Check(t.Before(u), field, v.msg(Before, msg, field, u))
v.check(t.Before(u), field, v.msg(Before, msg, field, u))

return v
}
4 changes: 2 additions & 2 deletions between.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const (
// fmt.Printf("validation errors: %#v\n", v.Errors())
// }
func (v Validator) BetweenInt(i, min, max int, field, msg string) Validator {
v.Check(i >= min && i <= max, field, v.msg(Between, msg, field, min, max))
v.check(i >= min && i <= max, field, v.msg(Between, msg, field, min, max))

return v
}
Expand All @@ -32,7 +32,7 @@ func (v Validator) BetweenInt(i, min, max int, field, msg string) Validator {
// fmt.Printf("validation errors: %#v\n", v.Errors())
// }
func (v Validator) BetweenFloat(f, min, max float64, field, msg string) Validator {
v.Check(f >= min && f <= max, field, v.msg(Between, msg, field, min, max))
v.check(f >= min && f <= max, field, v.msg(Between, msg, field, min, max))

return v
}
11 changes: 11 additions & 0 deletions custom.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package govalidator

// CustomRule is a dynamic method to define any custom validation rule by passing a rule as a function or expression
// which will return a boolean.
func (v Validator) CustomRule(ok bool, field, msg string) Validator {
if !ok {
v.addError(field, msg)
}

return v
}
70 changes: 70 additions & 0 deletions custom_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package govalidator

import (
"github.com/stretchr/testify/assert"
"testing"
)

func Test_CustomRule(t *testing.T) {
tests := []struct {
name string
field string
value bool
isPassed bool
msg string
expectedMsg string
}{
{
name: "test CustomRule with true condition",
value: true,
field: "username",
msg: "",
isPassed: true,
expectedMsg: "",
},
{
name: "test CustomRule with false condition and custom message",
value: false,
field: "username",
msg: "username must be unique",
isPassed: false,
expectedMsg: "username must be unique",
},
{
name: "test CustomRule with false condition and empty message",
value: false,
field: "email",
msg: "",
isPassed: false,
expectedMsg: "",
},
{
name: "test CustomRule with true condition and custom message",
value: true,
field: "email",
msg: "email must be valid",
isPassed: true,
expectedMsg: "",
},
}

for _, test := range tests {
v := New()

v.CustomRule(test.value, test.field, test.msg)

assert.Equal(t, test.isPassed, v.IsPassed(), test.name)

if !test.isPassed {
assert.Equalf(
t,
test.expectedMsg,
v.Errors()[test.field],
"test case %q failed, expected: %s, got: %s",
test.name,
test.expectedMsg,
v.Errors()[test.field],
)
}
}
}
2 changes: 1 addition & 1 deletion date.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const (
func (v Validator) Date(layout, d, field, msg string) Validator {
_, err := time.Parse(layout, d)
if err != nil {
v.Check(false, field, v.msg(Date, msg, field))
v.check(false, field, v.msg(Date, msg, field))
}

return v
Expand Down
2 changes: 1 addition & 1 deletion exists.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const (
// fmt.Printf("validation errors: %#v\n", v.Errors())
// }
func (v Validator) Exists(value any, table, column, field, msg string) Validator {
v.Check(v.repo.Exists(value, table, column), field, v.msg(Exists, msg, field))
v.check(v.repo.Exists(value, table, column), field, v.msg(Exists, msg, field))

return v
}
15 changes: 15 additions & 0 deletions exists_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,21 @@ func (repo) Exists(value any, table, column string) bool {
return false
}

func (repo) ExistsExceptSelf(value any, table, column string, selfID int) bool {
data, exists := tables[table]
if !exists {
return false
}

for _, item := range data {
if item[column] == value {
return true
}
}

return false
}

func TestValidator_Exists(t *testing.T) {
tests := []struct {
name string
Expand Down
2 changes: 1 addition & 1 deletion ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const (
func (v Validator) IP4(s, field, msg string) Validator {
ip := net.ParseIP(s)

v.Check(ip != nil && ip.To4() != nil, field, v.msg(IP4, msg, field))
v.check(ip != nil && ip.To4() != nil, field, v.msg(IP4, msg, field))

return v
}
6 changes: 3 additions & 3 deletions len.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const (
// fmt.Printf("validation errors: %#v\n", v.Errors())
// }
func (v Validator) LenString(s string, size int, field, msg string) Validator {
v.Check(utf8.RuneCountInString(strings.TrimSpace(s)) == size, field, v.msg(Len, msg, field, size))
v.check(utf8.RuneCountInString(strings.TrimSpace(s)) == size, field, v.msg(Len, msg, field, size))

return v
}
Expand All @@ -42,7 +42,7 @@ func (v Validator) LenString(s string, size int, field, msg string) Validator {
// fmt.Printf("validation errors: %#v\n", v.Errors())
// }
func (v Validator) LenInt(i, size int, field, msg string) Validator {
v.Check(len(strconv.Itoa(i)) == size, field, v.msg(Len, msg, field, size))
v.check(len(strconv.Itoa(i)) == size, field, v.msg(Len, msg, field, size))

return v
}
Expand All @@ -57,7 +57,7 @@ func (v Validator) LenInt(i, size int, field, msg string) Validator {
// fmt.Printf("validation errors: %#v\n", v.Errors())
// }
func (v Validator) LenSlice(s []any, size int, field, msg string) Validator {
v.Check(len(s) == size, field, v.msg(LenList, msg, field, size))
v.check(len(s) == size, field, v.msg(LenList, msg, field, size))

return v
}
6 changes: 3 additions & 3 deletions max.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const (
// fmt.Printf("validation errors: %#v\n", v.Errors())
// }
func (v Validator) MaxInt(i, max int, field, msg string) Validator {
v.Check(i <= max, field, v.msg(Max, msg, field, max))
v.check(i <= max, field, v.msg(Max, msg, field, max))

return v
}
Expand All @@ -41,7 +41,7 @@ func (v Validator) MaxInt(i, max int, field, msg string) Validator {
// fmt.Printf("validation errors: %#v\n", v.Errors())
// }
func (v Validator) MaxFloat(f, max float64, field, msg string) Validator {
v.Check(f <= max, field, v.msg(Max, msg, field, max))
v.check(f <= max, field, v.msg(Max, msg, field, max))

return v
}
Expand All @@ -56,7 +56,7 @@ func (v Validator) MaxFloat(f, max float64, field, msg string) Validator {
// fmt.Printf("validation errors: %#v\n", v.Errors())
// }
func (v Validator) MaxString(s string, maxLen int, field, msg string) Validator {
v.Check(utf8.RuneCountInString(strings.TrimSpace(s)) <= maxLen, field, v.msg(MaxString, msg, field, maxLen))
v.check(utf8.RuneCountInString(strings.TrimSpace(s)) <= maxLen, field, v.msg(MaxString, msg, field, maxLen))

return v
}
6 changes: 3 additions & 3 deletions min.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const (
// fmt.Printf("validation errors: %#v\n", v.Errors())
// }
func (v Validator) MinInt(i, min int, field, msg string) Validator {
v.Check(i >= min, field, v.msg(Min, msg, field, min))
v.check(i >= min, field, v.msg(Min, msg, field, min))

return v
}
Expand All @@ -41,7 +41,7 @@ func (v Validator) MinInt(i, min int, field, msg string) Validator {
// fmt.Printf("validation errors: %#v\n", v.Errors())
// }
func (v Validator) MinFloat(f, min float64, field, msg string) Validator {
v.Check(f >= min, field, v.msg(Min, msg, field, min))
v.check(f >= min, field, v.msg(Min, msg, field, min))

return v
}
Expand All @@ -56,7 +56,7 @@ func (v Validator) MinFloat(f, min float64, field, msg string) Validator {
// fmt.Printf("validation errors: %#v\n", v.Errors())
// }
func (v Validator) MinString(s string, minLen int, field, msg string) Validator {
v.Check(utf8.RuneCountInString(strings.TrimSpace(s)) >= minLen, field, v.msg(MinString, msg, field, minLen))
v.check(utf8.RuneCountInString(strings.TrimSpace(s)) >= minLen, field, v.msg(MinString, msg, field, minLen))

return v
}
2 changes: 1 addition & 1 deletion notexists.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const (
// fmt.Printf("validation errors: %#v\n", v.Errors())
// }
func (v Validator) NotExists(value any, table, column, field, msg string) Validator {
v.Check(!v.repo.Exists(value, table, column), field, v.msg(NotExists, msg, field))
v.check(!v.repo.Exists(value, table, column), field, v.msg(NotExists, msg, field))

return v
}
2 changes: 1 addition & 1 deletion regex.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const (
func (v Validator) RegexMatches(s string, pattern string, field, msg string) Validator {
r := regexp.MustCompile(pattern)

v.Check(r.Match([]byte(s)), field, v.msg(Regex, msg))
v.check(r.Match([]byte(s)), field, v.msg(Regex, msg))

return v
}
8 changes: 4 additions & 4 deletions required.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const (
// fmt.Printf("validation errors: %#v\n", v.Errors())
// }
func (v Validator) RequiredString(s, field string, msg string) Validator {
v.Check(strings.TrimSpace(s) != "", field, v.msg(Required, msg, field))
v.check(strings.TrimSpace(s) != "", field, v.msg(Required, msg, field))

return v
}
Expand All @@ -34,7 +34,7 @@ func (v Validator) RequiredString(s, field string, msg string) Validator {
// fmt.Printf("validation errors: %#v\n", v.Errors())
// }
func (v Validator) RequiredInt(i int, field string, msg string) Validator {
v.Check(i != 0, field, v.msg(Required, msg, field))
v.check(i != 0, field, v.msg(Required, msg, field))

return v
}
Expand All @@ -49,7 +49,7 @@ func (v Validator) RequiredInt(i int, field string, msg string) Validator {
// fmt.Printf("validation errors: %#v\n", v.Errors())
// }
func (v Validator) RequiredSlice(s []any, field string, msg string) Validator {
v.Check(len(s) > 0, field, v.msg(Required, msg, field))
v.check(len(s) > 0, field, v.msg(Required, msg, field))

return v
}
Expand All @@ -64,7 +64,7 @@ func (v Validator) RequiredSlice(s []any, field string, msg string) Validator {
// fmt.Printf("validation errors: %#v\n", v.Errors())
// }
func (v Validator) RequiredFloat(f float64, field string, msg string) Validator {
v.Check(f != 0.0, field, v.msg(Required, msg, field))
v.check(f != 0.0, field, v.msg(Required, msg, field))

return v
}
2 changes: 1 addition & 1 deletion url.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const (
func (v Validator) URL(s, field, msg string) Validator {
u, err := url.Parse(s)

v.Check(err == nil && u.Scheme != "" && u.Host != "", field, v.msg(URL, msg, field))
v.check(err == nil && u.Scheme != "" && u.Host != "", field, v.msg(URL, msg, field))

return v
}
2 changes: 1 addition & 1 deletion uuid.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const (
func (v Validator) UUID(u, field, msg string) Validator {
_, err := uuid.Parse(u)
if err != nil {
v.Check(false, field, v.msg(UUID, msg, field))
v.check(false, field, v.msg(UUID, msg, field))

return v
}
Expand Down
6 changes: 3 additions & 3 deletions validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type (
// check a record exists on database or not.
Repository interface {
Exists(value any, table, column string) bool
ExistsExceptSelf(value any, table, column string, selfID int) bool
}

// Validator represents the validator structure
Expand Down Expand Up @@ -80,9 +81,8 @@ func (v Validator) Errors() map[string]string {
return v.errs
}

// Check is a dynamic method to define any custom validator rule by passing a rule as a function or expression
// which will return a boolean.
func (v Validator) Check(ok bool, field, msg string) {
// check is the internal method easily validate each validator method result
func (v Validator) check(ok bool, field, msg string) {
if !ok {
v.addError(field, msg)
}
Expand Down

0 comments on commit bc079bd

Please sign in to comment.