nurse/validation/registry.go

76 lines
1.5 KiB
Go
Raw Normal View History

2022-06-09 20:12:45 +00:00
package validation
import (
"fmt"
"strings"
"sync"
2022-09-22 09:46:36 +00:00
"code.icb4dc0.de/prskr/nurse/check"
"code.icb4dc0.de/prskr/nurse/grammar"
2022-06-09 20:12:45 +00:00
)
type (
Validator[T any] interface {
Validate(in T) error
}
FromCall[T any] interface {
Validator[T]
check.CallUnmarshaler
}
Chain[T any] []Validator[T]
)
func (c Chain[T]) Validate(in T) error {
for i := range c {
if err := c[i].Validate(in); err != nil {
return err
}
}
return nil
}
func NewRegistry[R any]() *Registry[R] {
return &Registry[R]{
validators: make(map[string]func() FromCall[R]),
}
}
type Registry[R any] struct {
lock sync.Mutex
validators map[string]func() FromCall[R]
}
func (r *Registry[R]) Register(name string, factory func() FromCall[R]) {
r.lock.Lock()
defer r.lock.Unlock()
r.validators[strings.ToLower(name)] = factory
}
func (r *Registry[R]) ValidatorsForFilters(filters *grammar.Filters) (Chain[R], error) {
r.lock.Lock()
defer r.lock.Unlock()
if filters == nil || filters.Chain == nil {
return Chain[R]{}, nil
}
chain := make(Chain[R], 0, len(filters.Chain))
for i := range filters.Chain {
validationCall := filters.Chain[i]
if validatorProvider, ok := r.validators[strings.ToLower(validationCall.Name)]; !ok {
return nil, fmt.Errorf("%w: %s", check.ErrNoSuchValidator, validationCall.Name)
} else {
validator := validatorProvider()
if err := validator.UnmarshalCall(validationCall); err != nil {
return nil, err
}
chain = append(chain, validator)
}
}
return chain, nil
}