Skip to content

Commit

Permalink
simplify rule logic
Browse files Browse the repository at this point in the history
  • Loading branch information
nieomylnieja committed Sep 28, 2023
1 parent 8438ef0 commit 01a89ce
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 45 deletions.
2 changes: 1 addition & 1 deletion manifest/v1alpha/labels/labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type (
Value = string
)

func ValidationRule() validation.SingleRuleFunc[Labels] {
func ValidationRule() validation.SingleRule[Labels] {
return func(v Labels) error { return v.Validate() }
}

Expand Down
31 changes: 5 additions & 26 deletions manifest/v1alpha/validation/rule.go
Original file line number Diff line number Diff line change
@@ -1,44 +1,23 @@
package validation

import "github.com/pkg/errors"

// Rule is the interface for all validation rules.
type Rule[T any] interface {
Validate(v T) error
}

// SingleRule represents a single validation Rule.
// The Message conveys the reason for the rules' failure and IsValid
// is the function which verifies if the rule passes or not.
type SingleRule[T any] struct {
Message string
IsValid func(v T) bool
}
type SingleRule[T any] func(v T) error

func (r SingleRule[T]) Validate(v T) error {
if r.IsValid(v) {
return nil
}
return errors.New(r.Message)
}
func (r SingleRule[T]) Validate(v T) error { return r(v) }

// MultiRule allows defining Rule which aggregates multiple sub-rules.
type MultiRule[T any] struct {
Rules []Rule[T]
}
type MultiRule[T any] []Rule[T]

func (r MultiRule[T]) Validate(v T) error {
var mErr multiRuleError
for i := range r.Rules {
if err := r.Rules[i].Validate(v); err != nil {
for i := range r {
if err := r[i].Validate(v); err != nil {
mErr = append(mErr, err)
}
}
return mErr
}

// SingleRuleFunc is a function variant of SingleRule.
// Instead of defining message and validation check separately it can be used to
type SingleRuleFunc[T any] func(v T) error

func (r SingleRuleFunc[T]) Validate(v T) error { return r(v) }
39 changes: 21 additions & 18 deletions manifest/v1alpha/validation/string.go
Original file line number Diff line number Diff line change
@@ -1,42 +1,45 @@
package validation

import (
"fmt"
"regexp"
"unicode/utf8"

"github.com/pkg/errors"
)

func StringRequired() SingleRule[string] {
return SingleRule[string]{
Message: "field is required but was empty",
IsValid: func(v string) bool { return v != "" },
return func(v string) error {
if v == "" {
return errors.New("field is required but was empty")
}
return nil
}
}

func StringLength(min, max int) SingleRule[string] {
return SingleRule[string]{
Message: fmt.Sprintf("length must be between %d and %d", min, max),
IsValid: func(v string) bool {
rc := utf8.RuneCountInString(v)
return !(rc <= min || rc >= max)
},
return func(v string) error {
rc := utf8.RuneCountInString(v)
if rc <= min || rc >= max {
return errors.Errorf("length must be between %d and %d", min, max)
}
return nil
}
}

var dns1123SubdomainRegexp = regexp.MustCompile("^[a-z0-9]([-a-z0-9]*[a-z0-9])?$")

func StringIsDNSSubdomain() MultiRule[string] {
return MultiRule[string]{
Rules: []Rule[string]{
StringLength(0, 63),
SingleRule[string]{
Message: regexErrorMsg(
StringLength(0, 63),
SingleRule[string](func(v string) error {
if !dns1123SubdomainRegexp.MatchString(v) {
return errors.New(regexErrorMsg(
"a DNS-1123 compliant name must consist of lower case alphanumeric characters or '-',"+
" and must start and end with an alphanumeric character",
dns1123SubdomainRegexp.String(), "my-name", "123-abc"),
IsValid: func(v string) bool { return dns1123SubdomainRegexp.MatchString(v) },
},
},
dns1123SubdomainRegexp.String(), "my-name", "123-abc"))
}
return nil
}),
}
}

Expand Down

0 comments on commit 01a89ce

Please sign in to comment.