From 389d5867ead02eb904e5f82832e80f6af92d3d1c Mon Sep 17 00:00:00 2001 From: Jamess-Lucass Date: Fri, 26 Jan 2024 22:06:53 +0000 Subject: [PATCH] wip --- examples/main.go | 10 ++- rules.go | 70 +++++++++--------- validator.go | 26 +++---- validator_test.go | 181 ++++++++++++++++++++++++++-------------------- 4 files changed, 157 insertions(+), 130 deletions(-) diff --git a/examples/main.go b/examples/main.go index f73786c..63f0dd2 100644 --- a/examples/main.go +++ b/examples/main.go @@ -10,6 +10,7 @@ import ( type User struct { Firstname string Lastname string + Age int } func main() { @@ -30,6 +31,7 @@ func main() { validator.Required(), validator.Min(3), ).WithName("lastname"), + validator.RuleFor(user.Age, validator.Min(0)), ) validationResult := rules.Validate() @@ -37,12 +39,12 @@ func main() { fmt.Printf("valid: %t with errors: %v\n", validationResult.IsValid(), validationResult.Errors) } -func Custom() *validator.RuleConfig { - return &validator.RuleConfig{ - MessageFunc: func(r validator.RuleConfig) string { +func Custom[T any]() *validator.RuleConfig[T] { + return &validator.RuleConfig[T]{ + MessageFunc: func(r validator.RuleConfig[T]) string { return fmt.Sprintf("'%s' must equal 'jane'", r.Value) }, - ValidateFunc: func(r validator.RuleConfig) bool { + ValidateFunc: func(r validator.RuleConfig[T]) bool { val, ok := r.Value.(string) if !ok { return false diff --git a/rules.go b/rules.go index ba3cb86..2335a3a 100644 --- a/rules.go +++ b/rules.go @@ -2,67 +2,67 @@ package validator import "fmt" -type RuleConfig struct { - Value any - MessageFunc func(RuleConfig) string - ValidateFunc func(RuleConfig) bool +type RuleConfig[T any] struct { + Value T + MessageFunc func(RuleConfig[T]) string + ValidateFunc func(RuleConfig[T]) bool } -func Min(min int) *RuleConfig { - return &RuleConfig{ - MessageFunc: func(r RuleConfig) string { +func Min[T string](min int) *RuleConfig[T] { + return &RuleConfig[T]{ + MessageFunc: func(r RuleConfig[T]) string { return fmt.Sprintf("'%s' does not meet the minimum length of %d", r.Value, min) }, - ValidateFunc: func(r RuleConfig) bool { - val, ok := r.Value.(string) - if !ok { - return false - } - - return len(val) >= min + ValidateFunc: func(r RuleConfig[T]) bool { + return len(r.Value) >= min }, } } -func Max(max int) *RuleConfig { - return &RuleConfig{ - MessageFunc: func(r RuleConfig) string { +func Max[T string](max int) *RuleConfig[T] { + return &RuleConfig[T]{ + MessageFunc: func(r RuleConfig[T]) string { return fmt.Sprintf("'%s' exceeds the maximum length of %d", r.Value, max) }, - ValidateFunc: func(r RuleConfig) bool { - val, ok := r.Value.(string) - if !ok { - return false - } - - return len(val) <= max + ValidateFunc: func(r RuleConfig[T]) bool { + return len(r.Value) <= max }, } } -func Must(predicate func() bool) *RuleConfig { - return &RuleConfig{ - MessageFunc: func(r RuleConfig) string { +func Must[T any](predicate func() bool) *RuleConfig[T] { + return &RuleConfig[T]{ + MessageFunc: func(r RuleConfig[T]) string { return "Validation failed" }, - ValidateFunc: func(r RuleConfig) bool { + ValidateFunc: func(r RuleConfig[T]) bool { return predicate() }, } } -func Required() *RuleConfig { - return &RuleConfig{ - MessageFunc: func(r RuleConfig) string { +func Required[T string]() *RuleConfig[T] { + return &RuleConfig[T]{ + MessageFunc: func(r RuleConfig[T]) string { return "Required" }, - ValidateFunc: func(r RuleConfig) bool { - val, ok := r.Value.(string) + ValidateFunc: func(r RuleConfig[T]) bool { + return len(r.Value) > 0 + }, + } +} + +func GreaterThan[T int](min int) *RuleConfig[T] { + return &RuleConfig[T]{ + MessageFunc: func(r RuleConfig[T]) string { + return fmt.Sprintf("%d must be greater than %d", r.Value, min) + }, + ValidateFunc: func(r RuleConfig[T]) bool { + val, ok := interface{}(r.Value).(int) if !ok { return false } - - return len(val) > 0 + return val > min }, } } diff --git a/validator.go b/validator.go index 06ecd75..8d41aef 100644 --- a/validator.go +++ b/validator.go @@ -17,31 +17,31 @@ func (m *ValidationError) Error() string { return m.errorMessage } -func (r *RuleConfig) WithMessage(message string) *RuleConfig { - r.MessageFunc = func(r RuleConfig) string { +func (r *RuleConfig[T]) WithMessage(message string) *RuleConfig[T] { + r.MessageFunc = func(r RuleConfig[T]) string { return message } return r } -type Rule struct { - value any +type Rule[T any] struct { + value T name string - rules []*RuleConfig + rules []*RuleConfig[T] } -func RuleFor(value any, options ...*RuleConfig) *Rule { - return &Rule{value: value, rules: options} +func RuleFor[T any](value T, options ...*RuleConfig[T]) *Rule[T] { + return &Rule[T]{value: value, rules: options} } -func (r *Rule) WithName(name string) *Rule { +func (r *Rule[T]) WithName(name string) *Rule[T] { r.name = name return r } -func (r *Rule) Validate() *ValidationResult { +func (r *Rule[T]) Validate() *ValidationResult { res := &ValidationResult{} for _, rule := range r.rules { @@ -60,10 +60,10 @@ func (r *Rule) Validate() *ValidationResult { return res } -type MultipleRules []Rule +type MultipleRules[T any] []Rule[T] -func Rules(options ...*Rule) *MultipleRules { - multipleRules := make(MultipleRules, len(options)) +func Rules[T any](options ...*Rule[T]) *MultipleRules[T] { + multipleRules := make(MultipleRules[T], len(options)) for i, opt := range options { multipleRules[i] = *opt @@ -72,7 +72,7 @@ func Rules(options ...*Rule) *MultipleRules { return &multipleRules } -func (r *MultipleRules) Validate() *ValidationResult { +func (r *MultipleRules[T]) Validate() *ValidationResult { res := &ValidationResult{} for _, rule := range *r { diff --git a/validator_test.go b/validator_test.go index 9928f45..5b5d2c3 100644 --- a/validator_test.go +++ b/validator_test.go @@ -10,89 +10,114 @@ import ( type User struct { Firstname string Lastname string + Age int } -func Test_MinWithValidLength_ReturnsTrue(t *testing.T) { - user := User{ - Firstname: "john", - } +// func Test_MinWithValidLength_ReturnsTrue(t *testing.T) { +// user := User{ +// Firstname: "john", +// } + +// rule := validator.RuleFor( +// user.Firstname, +// validator.Min(4), +// ) + +// res := rule.Validate() + +// assert.Equal(t, true, res.IsValid()) +// } + +// func Test_MinWithInvalidLength_ReturnsFalse(t *testing.T) { +// user := User{ +// Firstname: "john", +// } + +// rule := validator.RuleFor( +// user.Firstname, +// validator.Min(100), +// ) + +// assert.Equal(t, false, rule.Validate().IsValid()) +// } + +// func Test_MultipleMinWithInValidLength_ReturnsFalse(t *testing.T) { +// user := User{ +// Firstname: "john", +// } + +// rules := validator.Rules( +// validator.RuleFor( +// user.Firstname, +// validator.Min(4), +// ), +// validator.RuleFor( +// user.Lastname, +// validator.Min(4), +// ), +// ) + +// assert.Equal(t, false, rules.Validate().IsValid()) +// } + +// func Test_MaxWithValidLength_ReturnsTrue(t *testing.T) { +// user := User{ +// Firstname: "john", +// } + +// rule := validator.RuleFor( +// user.Firstname, +// validator.Max(5), +// ) + +// assert.Equal(t, true, rule.Validate().IsValid()) +// } + +// func Test_MaxWithInvalidLength_ReturnsFalse(t *testing.T) { +// user := User{ +// Firstname: "john", +// } + +// rule := validator.RuleFor( +// user.Firstname, +// validator.Max(2), +// ) + +// assert.Equal(t, false, rule.Validate().IsValid()) +// } + +// func Test_RequiredWithNoValue_ReturnsFalse(t *testing.T) { +// user := User{} + +// rule := validator.RuleFor( +// user.Firstname, +// validator.Required(), +// validator.Min(2), +// ) + +// assert.Equal(t, false, rule.Validate().IsValid()) +// } + +// func Test_GreaterThanInvalid_ReturnsFalse(t *testing.T) { +// user := User{Age: 17} + +// rule := validator.RuleFor( +// user.Age, +// validator.Required(), +// validator.GreaterThan(17), +// ) + +// assert.Equal(t, false, rule.Validate().IsValid()) +// } + +func Test_GreaterThanValid_ReturnsTrue(t *testing.T) { + user := User{Age: 18} rule := validator.RuleFor( - user.Firstname, - validator.Min(4), - ) - - res := rule.Validate() - - assert.Equal(t, true, res.IsValid()) -} - -func Test_MinWithInvalidLength_ReturnsFalse(t *testing.T) { - user := User{ - Firstname: "john", - } - - rule := validator.RuleFor( - user.Firstname, - validator.Min(100), - ) - - assert.Equal(t, false, rule.Validate().IsValid()) -} - -func Test_MultipleMinWithInValidLength_ReturnsFalse(t *testing.T) { - user := User{ - Firstname: "john", - } - - rules := validator.Rules( - validator.RuleFor( - user.Firstname, - validator.Min(4), - ), - validator.RuleFor( - user.Lastname, - validator.Min(4), - ), - ) - - assert.Equal(t, false, rules.Validate().IsValid()) -} - -func Test_MaxWithValidLength_ReturnsTrue(t *testing.T) { - user := User{ - Firstname: "john", - } - - rule := validator.RuleFor( - user.Firstname, - validator.Max(5), - ) - - assert.Equal(t, true, rule.Validate().IsValid()) -} - -func Test_MaxWithInvalidLength_ReturnsFalse(t *testing.T) { - user := User{ - Firstname: "john", - } - - rule := validator.RuleFor( - user.Firstname, - validator.Max(2), - ) - - assert.Equal(t, false, rule.Validate().IsValid()) -} - -func Test_RequiredWithNoValue_ReturnsFalse(t *testing.T) { - user := User{} - - rule := validator.RuleFor( - user.Firstname, + user.Age, validator.Required(), - validator.Min(2), + validator.GreaterThan(17), ) - assert.Equal(t, false, rule.Validate().IsValid()) + assert.Equal(t, true, rule.Validate().IsValid()) }