Skip to content

Commit

Permalink
feat(string): impl variant validator and ensure backward compatibility
Browse files Browse the repository at this point in the history
* feat: add internal error wrapper

* feat(string): impl variant validator and ensure backward compatibility (#49)

* feat(string): impl variant validator and ensure backward compatibility

* refactor(string): use sort name
  • Loading branch information
josestg authored Jun 30, 2023
1 parent 8d929d2 commit 84da936
Showing 1 changed file with 33 additions and 21 deletions.
54 changes: 33 additions & 21 deletions string.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,43 @@ package goval
import (
"context"
"fmt"
"github.com/pkg-id/goval/funcs"
"strings"

"github.com/pkg-id/goval/funcs"
)

// StringValidator is a FunctionValidator that validates string.
type StringValidator FunctionValidator[string]
// For backward compatibility.
type StringValidator = SVV[string]

// String returns a StringValidator with no rules.
// For backward compatibility.
func String() StringValidator {
return NopFunctionValidator[string]
return StringVariant[string]()
}

// SVV (String Variant Validator) is a FunctionValidator that validates string
// variants.
type SVV[T ~string] FunctionValidator[T]

// StringVariant returns a SVV with no rules.
func StringVariant[T ~string]() SVV[T] {
return NopFunctionValidator[T]
}

// Validate executes the validation rules immediately.
func (f StringValidator) Validate(ctx context.Context, value string) error {
func (f SVV[T]) Validate(ctx context.Context, value T) error {
return validatorOf(f, value).Validate(ctx)
}

// With attaches the next rule to the chain.
func (f StringValidator) With(next StringValidator) StringValidator {
func (f SVV[T]) With(next SVV[T]) SVV[T] {
return Chain(f, next)
}

// Required ensures the string is not empty.
func (f StringValidator) Required() StringValidator {
return f.With(func(ctx context.Context, value string) error {
func (f SVV[T]) Required() SVV[T] {
return f.With(func(ctx context.Context, value T) error {
if value == "" {
return NewRuleError(StringRequired)
}
Expand All @@ -36,8 +48,8 @@ func (f StringValidator) Required() StringValidator {
}

// Min ensures the length of the string is not less than the given length.
func (f StringValidator) Min(length int) StringValidator {
return f.With(func(ctx context.Context, value string) error {
func (f SVV[T]) Min(length int) SVV[T] {
return f.With(func(ctx context.Context, value T) error {
if len(value) < length {
return NewRuleError(StringMin, length)
}
Expand All @@ -46,8 +58,8 @@ func (f StringValidator) Min(length int) StringValidator {
}

// Max ensures the length of the string is not greater than the given length.
func (f StringValidator) Max(length int) StringValidator {
return f.With(func(ctx context.Context, value string) error {
func (f SVV[T]) Max(length int) SVV[T] {
return f.With(func(ctx context.Context, value T) error {
if len(value) > length {
return NewRuleError(StringMax, length)
}
Expand All @@ -57,16 +69,16 @@ func (f StringValidator) Max(length int) StringValidator {

// Match ensures the string matches the given pattern.
// If pattern cause panic, will be recovered.
func (f StringValidator) Match(pattern Pattern) StringValidator {
return f.With(func(ctx context.Context, value string) (err error) {
func (f SVV[T]) Match(pattern Pattern) SVV[T] {
return f.With(func(ctx context.Context, value T) (err error) {
defer func() {
if rec := recover(); rec != nil {
err = fmt.Errorf("panic: %v", rec)
}
}()

exp := pattern.RegExp()
if !exp.MatchString(value) {
if !exp.MatchString(string(value)) {
return NewRuleError(StringMatch, exp.String())
}

Expand All @@ -76,9 +88,9 @@ func (f StringValidator) Match(pattern Pattern) StringValidator {

// In ensures that the provided string is one of the specified options.
// This validation is case-sensitive, use InFold to perform a case-insensitive In validation.
func (f StringValidator) In(options ...string) StringValidator {
return f.With(func(ctx context.Context, value string) error {
ok := funcs.Contains(options, func(opt string) bool { return value == opt })
func (f SVV[T]) In(options ...T) SVV[T] {
return f.With(func(ctx context.Context, value T) error {
ok := funcs.Contains(options, func(opt T) bool { return value == opt })
if !ok {
return NewRuleError(StringIn, options)
}
Expand All @@ -87,9 +99,9 @@ func (f StringValidator) In(options ...string) StringValidator {
}

// InFold ensures that the provided string is one of the specified options with case-insensitivity.
func (f StringValidator) InFold(options ...string) StringValidator {
return f.With(func(ctx context.Context, value string) error {
ok := funcs.Contains(options, func(opt string) bool { return strings.EqualFold(value, opt) })
func (f SVV[T]) InFold(options ...T) SVV[T] {
return f.With(func(ctx context.Context, value T) error {
ok := funcs.Contains(options, func(opt T) bool { return strings.EqualFold(string(value), string(opt)) })
if !ok {
return NewRuleError(StringInFold, options)
}
Expand All @@ -104,6 +116,6 @@ func (f StringValidator) InFold(options ...string) StringValidator {
//
// The mapper function takes a StringValidator instance and returns a new StringValidator instance with
// additional validation logic.
func (f StringValidator) When(p Predicate[string], m Mapper[string, StringValidator]) StringValidator {
func (f SVV[T]) When(p Predicate[T], m Mapper[T, SVV[T]]) SVV[T] {
return whenLinker(f, p, m)
}

0 comments on commit 84da936

Please sign in to comment.