2021-06-21 19:30:33 +00:00
|
|
|
package validator
|
2019-05-01 09:23:05 +00:00
|
|
|
|
|
|
|
import (
|
2020-03-28 17:48:27 +00:00
|
|
|
"reflect"
|
2019-05-01 09:23:05 +00:00
|
|
|
"regexp"
|
|
|
|
"strconv"
|
|
|
|
)
|
|
|
|
|
2021-06-21 19:30:33 +00:00
|
|
|
var (
|
|
|
|
fixedLengthRegex = regexp.MustCompile(`^string\((\d+)\)$`)
|
|
|
|
variableLengthRegex = regexp.MustCompile(`^string\((\d+), ?(\d+)\)$`)
|
|
|
|
)
|
2019-05-01 09:23:05 +00:00
|
|
|
|
2021-06-21 19:30:33 +00:00
|
|
|
// StringType makes the types beloz available in the aicra configuration:
|
|
|
|
// - "string" considers any string valid
|
|
|
|
// - "string(n)" considers any string with an exact size of `n` valid
|
|
|
|
// - "string(a,b)" considers any string with a size between `a` and `b` valid
|
|
|
|
// > for the last one, `a` and `b` are included in the valid sizes
|
|
|
|
type StringType struct{}
|
2019-05-01 09:23:05 +00:00
|
|
|
|
2021-06-21 19:30:33 +00:00
|
|
|
// GoType returns the `string` type
|
|
|
|
func (StringType) GoType() reflect.Type {
|
2020-03-28 18:11:23 +00:00
|
|
|
return reflect.TypeOf(string(""))
|
2020-03-28 17:48:27 +00:00
|
|
|
}
|
|
|
|
|
2021-06-21 19:30:33 +00:00
|
|
|
// Validator for strings with any/fixed/bound sizes
|
|
|
|
func (s StringType) Validator(typename string, avail ...Type) ValidateFunc {
|
|
|
|
var (
|
|
|
|
simple = (typename == "string")
|
|
|
|
fixedLengthMatches = fixedLengthRegex.FindStringSubmatch(typename)
|
|
|
|
variableLengthMatches = variableLengthRegex.FindStringSubmatch(typename)
|
|
|
|
)
|
2019-05-01 09:23:05 +00:00
|
|
|
|
2021-06-21 19:30:33 +00:00
|
|
|
// ignore unknown typename
|
2020-03-14 15:13:38 +00:00
|
|
|
if !simple && fixedLengthMatches == nil && variableLengthMatches == nil {
|
2019-05-01 09:23:05 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-05-03 18:09:04 +00:00
|
|
|
var (
|
|
|
|
mustFail bool
|
|
|
|
min, max int
|
|
|
|
)
|
|
|
|
|
|
|
|
// extract fixed length
|
|
|
|
if fixedLengthMatches != nil {
|
|
|
|
exLen, ok := s.getFixedLength(fixedLengthMatches)
|
|
|
|
if !ok {
|
2021-06-21 19:30:33 +00:00
|
|
|
return nil
|
2019-05-03 18:09:04 +00:00
|
|
|
}
|
|
|
|
min = exLen
|
|
|
|
max = exLen
|
|
|
|
|
|
|
|
// extract variable length
|
|
|
|
} else if variableLengthMatches != nil {
|
|
|
|
exMin, exMax, ok := s.getVariableLength(variableLengthMatches)
|
|
|
|
if !ok {
|
2021-06-21 19:30:33 +00:00
|
|
|
return nil
|
2019-05-03 18:09:04 +00:00
|
|
|
}
|
|
|
|
min = exMin
|
|
|
|
max = exMax
|
|
|
|
}
|
|
|
|
|
2020-03-14 15:13:38 +00:00
|
|
|
return func(value interface{}) (interface{}, bool) {
|
2019-05-03 18:09:04 +00:00
|
|
|
// preprocessing error
|
|
|
|
if mustFail {
|
2020-03-14 15:13:38 +00:00
|
|
|
return "", false
|
2019-05-03 18:09:04 +00:00
|
|
|
}
|
|
|
|
|
2019-05-01 09:23:05 +00:00
|
|
|
// check type
|
|
|
|
strValue, isString := value.(string)
|
2019-11-18 15:17:02 +00:00
|
|
|
byteSliceValue, isByteSlice := value.([]byte)
|
|
|
|
if !isString && isByteSlice {
|
|
|
|
strValue = string(byteSliceValue)
|
|
|
|
isString = true
|
|
|
|
}
|
|
|
|
|
2019-05-01 09:23:05 +00:00
|
|
|
if !isString {
|
2020-03-14 15:13:38 +00:00
|
|
|
return "", false
|
2019-05-01 09:23:05 +00:00
|
|
|
}
|
|
|
|
|
2020-03-14 15:13:38 +00:00
|
|
|
if simple {
|
|
|
|
return strValue, true
|
2019-05-01 09:23:05 +00:00
|
|
|
}
|
|
|
|
|
2019-05-03 18:09:04 +00:00
|
|
|
// check length against previously extracted length
|
|
|
|
l := len(strValue)
|
2020-03-14 15:13:38 +00:00
|
|
|
return strValue, l >= min && l <= max
|
2019-05-01 09:23:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// getFixedLength returns the fixed length from regex matches and a success state.
|
2021-06-21 19:30:33 +00:00
|
|
|
func (StringType) getFixedLength(regexMatches []string) (int, bool) {
|
2019-05-01 09:23:05 +00:00
|
|
|
// incoherence error
|
|
|
|
if regexMatches == nil || len(regexMatches) < 2 {
|
|
|
|
return 0, false
|
|
|
|
}
|
|
|
|
|
|
|
|
// extract length
|
2019-05-03 18:09:04 +00:00
|
|
|
fixedLength, err := strconv.ParseInt(regexMatches[1], 10, 64)
|
|
|
|
if err != nil || fixedLength < 0 {
|
2019-05-01 09:23:05 +00:00
|
|
|
return 0, false
|
|
|
|
}
|
|
|
|
|
|
|
|
return int(fixedLength), true
|
|
|
|
}
|
|
|
|
|
|
|
|
// getVariableLength returns the length min and max from regex matches and a success state.
|
2021-06-21 19:30:33 +00:00
|
|
|
func (StringType) getVariableLength(regexMatches []string) (int, int, bool) {
|
2019-05-01 09:23:05 +00:00
|
|
|
// incoherence error
|
|
|
|
if regexMatches == nil || len(regexMatches) < 3 {
|
|
|
|
return 0, 0, false
|
|
|
|
}
|
|
|
|
|
|
|
|
// extract minimum length
|
2019-05-03 18:09:04 +00:00
|
|
|
minLen, err := strconv.ParseInt(regexMatches[1], 10, 64)
|
|
|
|
if err != nil || minLen < 0 {
|
2019-05-01 09:23:05 +00:00
|
|
|
return 0, 0, false
|
|
|
|
}
|
|
|
|
// extract maximum length
|
2019-05-03 18:09:04 +00:00
|
|
|
maxLen, err := strconv.ParseInt(regexMatches[2], 10, 64)
|
|
|
|
if err != nil || maxLen < 0 {
|
2019-05-01 09:23:05 +00:00
|
|
|
return 0, 0, false
|
|
|
|
}
|
|
|
|
|
|
|
|
return int(minLen), int(maxLen), true
|
|
|
|
}
|