2019-05-01 09:23:05 +00:00
|
|
|
package builtin
|
|
|
|
|
|
|
|
import (
|
|
|
|
"regexp"
|
|
|
|
"strconv"
|
|
|
|
|
2020-03-16 08:20:00 +00:00
|
|
|
"git.xdrm.io/go/aicra/datatype"
|
2019-05-01 09:23:05 +00:00
|
|
|
)
|
|
|
|
|
2019-05-01 13:14:49 +00:00
|
|
|
var fixedLengthRegex = regexp.MustCompile(`^string\((\d+)\)$`)
|
2019-05-01 09:23:05 +00:00
|
|
|
var variableLengthRegex = regexp.MustCompile(`^string\((\d+), ?(\d+)\)$`)
|
|
|
|
|
2020-03-14 15:13:38 +00:00
|
|
|
// StringDataType is what its name tells
|
|
|
|
type StringDataType struct{}
|
2019-05-01 09:23:05 +00:00
|
|
|
|
2020-03-14 15:13:38 +00:00
|
|
|
// Build returns the validator.
|
|
|
|
// availables type names are : `string`, `string(length)` and `string(minLength, maxLength)`.
|
2020-03-22 15:50:10 +00:00
|
|
|
func (s StringDataType) Build(typeName string, registry ...datatype.T) datatype.Validator {
|
2020-03-14 15:13:38 +00:00
|
|
|
simple := typeName == "string"
|
2019-05-01 09:23:05 +00:00
|
|
|
fixedLengthMatches := fixedLengthRegex.FindStringSubmatch(typeName)
|
|
|
|
variableLengthMatches := variableLengthRegex.FindStringSubmatch(typeName)
|
|
|
|
|
|
|
|
// nothing if type not handled
|
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 {
|
|
|
|
mustFail = true
|
|
|
|
}
|
|
|
|
min = exLen
|
|
|
|
max = exLen
|
|
|
|
|
|
|
|
// extract variable length
|
|
|
|
} else if variableLengthMatches != nil {
|
|
|
|
exMin, exMax, ok := s.getVariableLength(variableLengthMatches)
|
|
|
|
if !ok {
|
|
|
|
mustFail = true
|
|
|
|
}
|
|
|
|
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.
|
2020-03-14 15:13:38 +00:00
|
|
|
func (StringDataType) 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.
|
2020-03-14 15:13:38 +00:00
|
|
|
func (StringDataType) 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
|
|
|
|
}
|