github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/validator/enum/enum.go (about)

     1  // Copyright (c) 2018-2021, R.I. Pienaar and the Choria Project contributors
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package enum
     6  
     7  import (
     8  	"fmt"
     9  	"reflect"
    10  	"regexp"
    11  	"strings"
    12  )
    13  
    14  // ValidateSlice validates that all items in target is one of valid
    15  func ValidateSlice(target []string, valid []string) (bool, error) {
    16  	for _, item := range target {
    17  		found, _ := ValidateString(item, valid)
    18  		if !found {
    19  			return false, fmt.Errorf("'%s' is not in the allowed list: %s", item, strings.Join(valid, ", "))
    20  		}
    21  	}
    22  
    23  	return true, nil
    24  }
    25  
    26  // ValidateString validates that a string is in the list of allowed values
    27  func ValidateString(target string, valid []string) (bool, error) {
    28  	found := false
    29  
    30  	for _, e := range valid {
    31  		if e == target {
    32  			found = true
    33  		}
    34  	}
    35  
    36  	if !found {
    37  		return false, fmt.Errorf("'%s' is not in the allowed list: %s", target, strings.Join(valid, ", "))
    38  	}
    39  
    40  	return true, nil
    41  }
    42  
    43  // ValidateStructField validates a structure field, only []string and string types are supported
    44  func ValidateStructField(value reflect.Value, tag string) (bool, error) {
    45  	re := regexp.MustCompile(`^enum=(.+,*?)+$`)
    46  	parts := re.FindStringSubmatch(tag)
    47  
    48  	if len(parts) != 2 {
    49  		return false, fmt.Errorf("invalid tag '%s', must be enum=v1,v2,v3", tag)
    50  	}
    51  
    52  	evs := strings.Split(parts[1], ",")
    53  
    54  	switch value.Kind() {
    55  	case reflect.Slice:
    56  		slice, ok := value.Interface().([]string)
    57  		if !ok {
    58  			return false, fmt.Errorf("only []string slices can be validated for enums")
    59  		}
    60  
    61  		return ValidateSlice(slice, evs)
    62  	case reflect.String:
    63  		str, _ := value.Interface().(string)
    64  
    65  		return ValidateString(str, evs)
    66  
    67  	default:
    68  		return false, fmt.Errorf("cannot valid data of type %s for enums", value.Kind().String())
    69  	}
    70  }