| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588 |
- package dara
- import (
- "encoding/json"
- "errors"
- "fmt"
- "reflect"
- "regexp"
- "strconv"
- "strings"
- )
- type Model interface {
- Validate() error
- ToMap() map[string]interface{}
- copyWithouStream() Model
- }
- func Validate(params interface{}) error {
- if params == nil {
- return nil
- }
- requestValue := reflect.ValueOf(params)
- if requestValue.IsNil() {
- return nil
- }
- err := validate(requestValue.Elem())
- return err
- }
- // ValidateRequired checks if a value is set (non-nil)
- func ValidateRequired(value interface{}, fieldName string) error {
- if value == nil {
- return errors.New(fieldName + " should be setted")
- }
- // Check for typed nil pointers
- switch v := value.(type) {
- case *string:
- if v == nil {
- return errors.New(fieldName + " should be setted")
- }
- case *int:
- if v == nil {
- return errors.New(fieldName + " should be setted")
- }
- case *int8:
- if v == nil {
- return errors.New(fieldName + " should be setted")
- }
- case *int16:
- if v == nil {
- return errors.New(fieldName + " should be setted")
- }
- case *int32:
- if v == nil {
- return errors.New(fieldName + " should be setted")
- }
- case *int64:
- if v == nil {
- return errors.New(fieldName + " should be setted")
- }
- case *uint:
- if v == nil {
- return errors.New(fieldName + " should be setted")
- }
- case *uint8:
- if v == nil {
- return errors.New(fieldName + " should be setted")
- }
- case *uint16:
- if v == nil {
- return errors.New(fieldName + " should be setted")
- }
- case *uint32:
- if v == nil {
- return errors.New(fieldName + " should be setted")
- }
- case *uint64:
- if v == nil {
- return errors.New(fieldName + " should be setted")
- }
- case *float32:
- if v == nil {
- return errors.New(fieldName + " should be setted")
- }
- case *float64:
- if v == nil {
- return errors.New(fieldName + " should be setted")
- }
- }
- return nil
- }
- // ValidateMaxLength validates maximum length using type assertions
- func ValidateMaxLength(value interface{}, maxLength int, fieldName string) error {
- length := getValueLength(value)
- if length > maxLength {
- return fmt.Errorf("The length of %s is %d which is more than %d", fieldName, length, maxLength)
- }
- return nil
- }
- // ValidateMinLength validates minimum length using type assertions
- func ValidateMinLength(value interface{}, minLength int, fieldName string) error {
- length := getValueLength(value)
- if length < minLength {
- return fmt.Errorf("The length of %s is %d which is less than %d", fieldName, length, minLength)
- }
- return nil
- }
- // ValidatePattern validates string against regex pattern
- func ValidatePattern(value interface{}, pattern string, fieldName string) error {
- strValue := getStringValue(value)
- if strValue == "" {
- return nil // Empty strings are valid unless required
- }
- r, err := regexp.Compile("^" + pattern + "$")
- if err != nil {
- return err
- }
- if !r.MatchString(strValue) {
- return errors.New(strValue + " is not matched " + pattern)
- }
- return nil
- }
- // ValidateMaximum validates maximum value for numeric types
- func ValidateMaximum(value interface{}, maximum float64, fieldName string) error {
- numValue, ok := getNumericValue(value)
- if !ok {
- return nil // Skip validation for non-numeric types
- }
- if numValue > maximum {
- return fmt.Errorf("The size of %s is %f which is greater than %f", fieldName, numValue, maximum)
- }
- return nil
- }
- // ValidateMinimum validates minimum value for numeric types
- func ValidateMinimum(value interface{}, minimum float64, fieldName string) error {
- numValue, ok := getNumericValue(value)
- if !ok {
- return nil // Skip validation for non-numeric types
- }
- if numValue < minimum {
- return fmt.Errorf("The size of %s is %f which is less than %f", fieldName, numValue, minimum)
- }
- return nil
- }
- // ValidateArray validates array/slice elements recursively
- func ValidateArray(arr interface{}, validator func(interface{}) error) error {
- switch v := arr.(type) {
- case []interface{}:
- for _, item := range v {
- if err := validator(item); err != nil {
- return err
- }
- }
- case []*string:
- for _, item := range v {
- if err := validator(item); err != nil {
- return err
- }
- }
- case []*int:
- for _, item := range v {
- if err := validator(item); err != nil {
- return err
- }
- }
- // Add more specific types as needed
- }
- return nil
- }
- // ValidateMap validates map values recursively
- func ValidateMap(m interface{}, validator func(interface{}) error) error {
- switch v := m.(type) {
- case map[string]interface{}:
- for _, value := range v {
- if err := validator(value); err != nil {
- return err
- }
- }
- case map[string]*string:
- for _, value := range v {
- if err := validator(value); err != nil {
- return err
- }
- }
- // Add more specific types as needed
- }
- return nil
- }
- // Helper functions using pure type assertions (no reflection)
- // getStringValue extracts string value using type assertions
- func getStringValue(value interface{}) string {
- switch v := value.(type) {
- case string:
- return v
- case *string:
- if v != nil {
- return *v
- }
- return ""
- default:
- return ""
- }
- }
- // getNumericValue extracts numeric value as float64 using type assertions
- func getNumericValue(value interface{}) (float64, bool) {
- switch v := value.(type) {
- // Direct numeric types
- case int:
- return float64(v), true
- case int8:
- return float64(v), true
- case int16:
- return float64(v), true
- case int32:
- return float64(v), true
- case int64:
- return float64(v), true
- case uint:
- return float64(v), true
- case uint8:
- return float64(v), true
- case uint16:
- return float64(v), true
- case uint32:
- return float64(v), true
- case uint64:
- return float64(v), true
- case float32:
- return float64(v), true
- case float64:
- return v, true
- // Pointer types
- case *int:
- if v != nil {
- return float64(*v), true
- }
- case *int8:
- if v != nil {
- return float64(*v), true
- }
- case *int16:
- if v != nil {
- return float64(*v), true
- }
- case *int32:
- if v != nil {
- return float64(*v), true
- }
- case *int64:
- if v != nil {
- return float64(*v), true
- }
- case *uint:
- if v != nil {
- return float64(*v), true
- }
- case *uint8:
- if v != nil {
- return float64(*v), true
- }
- case *uint16:
- if v != nil {
- return float64(*v), true
- }
- case *uint32:
- if v != nil {
- return float64(*v), true
- }
- case *uint64:
- if v != nil {
- return float64(*v), true
- }
- case *float32:
- if v != nil {
- return float64(*v), true
- }
- case *float64:
- if v != nil {
- return *v, true
- }
- default:
- return 0, false
- }
- return 0, false
- }
- // getValueLength returns length of string, array, slice, or map using type assertions
- func getValueLength(value interface{}) int {
- switch v := value.(type) {
- case string:
- // Use the same method as original implementation for consistency
- return len([]rune(v))
- case *string:
- if v != nil {
- return len([]rune(*v))
- }
- return 0
- case []interface{}:
- return len(v)
- case []string:
- return len(v)
- case []*string:
- return len(v)
- case []int:
- return len(v)
- case []*int:
- return len(v)
- case map[string]interface{}:
- return len(v)
- case map[string]string:
- return len(v)
- case map[string]*string:
- return len(v)
- // Add more specific types as needed
- default:
- return 0
- }
- }
- // Deprecated: use new validation methods instead
- // Verify whether the parameters meet the requirements
- func validate(dataValue reflect.Value) error {
- if strings.HasPrefix(dataValue.Type().String(), "*") { // Determines whether the input is a structure object or a pointer object
- if dataValue.IsNil() {
- return nil
- }
- dataValue = dataValue.Elem()
- }
- dataType := dataValue.Type()
- for i := 0; i < dataType.NumField(); i++ {
- field := dataType.Field(i)
- valueField := dataValue.Field(i)
- for _, value := range validateParams {
- err := validateParam(field, valueField, value)
- if err != nil {
- return err
- }
- }
- }
- return nil
- }
- func validateParam(field reflect.StructField, valueField reflect.Value, tagName string) error {
- tag, containsTag := field.Tag.Lookup(tagName) // Take out the checked regular expression
- if containsTag && tagName == "require" {
- err := checkRequire(field, valueField)
- if err != nil {
- return err
- }
- }
- if strings.HasPrefix(field.Type.String(), "[]") { // Verify the parameters of the array type
- err := validateSlice(field, valueField, containsTag, tag, tagName)
- if err != nil {
- return err
- }
- } else if valueField.Kind() == reflect.Ptr { // Determines whether it is a pointer object
- err := validatePtr(field, valueField, containsTag, tag, tagName)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func validateSlice(field reflect.StructField, valueField reflect.Value, containsregexpTag bool, tag, tagName string) error {
- if valueField.IsValid() && !valueField.IsNil() { // Determines whether the parameter has a value
- if containsregexpTag {
- if tagName == "maxItems" {
- err := checkMaxItems(field, valueField, tag)
- if err != nil {
- return err
- }
- }
- if tagName == "minItems" {
- err := checkMinItems(field, valueField, tag)
- if err != nil {
- return err
- }
- }
- }
- for m := 0; m < valueField.Len(); m++ {
- elementValue := valueField.Index(m)
- if elementValue.Type().Kind() == reflect.Ptr { // Determines whether the child elements of an array are of a basic type
- err := validatePtr(field, elementValue, containsregexpTag, tag, tagName)
- if err != nil {
- return err
- }
- }
- }
- }
- return nil
- }
- func validatePtr(field reflect.StructField, elementValue reflect.Value, containsregexpTag bool, tag, tagName string) error {
- if elementValue.IsNil() {
- return nil
- }
- if isFilterType(elementValue.Elem().Type().String(), basicTypes) {
- if containsregexpTag {
- if tagName == "pattern" {
- err := checkPattern(field, elementValue.Elem(), tag)
- if err != nil {
- return err
- }
- }
- if tagName == "maxLength" {
- err := checkMaxLength(field, elementValue.Elem(), tag)
- if err != nil {
- return err
- }
- }
- if tagName == "minLength" {
- err := checkMinLength(field, elementValue.Elem(), tag)
- if err != nil {
- return err
- }
- }
- if tagName == "maximum" {
- err := checkMaximum(field, elementValue.Elem(), tag)
- if err != nil {
- return err
- }
- }
- if tagName == "minimum" {
- err := checkMinimum(field, elementValue.Elem(), tag)
- if err != nil {
- return err
- }
- }
- }
- } else {
- err := validate(elementValue)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func checkRequire(field reflect.StructField, valueField reflect.Value) error {
- name, _ := field.Tag.Lookup("json")
- strs := strings.Split(name, ",")
- name = strs[0]
- if !valueField.IsNil() && valueField.IsValid() {
- return nil
- }
- return errors.New(name + " should be setted")
- }
- func checkPattern(field reflect.StructField, valueField reflect.Value, tag string) error {
- if valueField.IsValid() && valueField.String() != "" {
- value := valueField.String()
- r, _ := regexp.Compile("^" + tag + "$")
- if match := r.MatchString(value); !match { // Determines whether the parameter value satisfies the regular expression or not, and throws an error
- return errors.New(value + " is not matched " + tag)
- }
- }
- return nil
- }
- func checkMaxItems(field reflect.StructField, valueField reflect.Value, tag string) error {
- if valueField.IsValid() && valueField.String() != "" {
- maxItems, err := strconv.Atoi(tag)
- if err != nil {
- return err
- }
- length := valueField.Len()
- if maxItems < length {
- errMsg := fmt.Sprintf("The length of %s is %d which is more than %d", field.Name, length, maxItems)
- return errors.New(errMsg)
- }
- }
- return nil
- }
- func checkMinItems(field reflect.StructField, valueField reflect.Value, tag string) error {
- if valueField.IsValid() {
- minItems, err := strconv.Atoi(tag)
- if err != nil {
- return err
- }
- length := valueField.Len()
- if minItems > length {
- errMsg := fmt.Sprintf("The length of %s is %d which is less than %d", field.Name, length, minItems)
- return errors.New(errMsg)
- }
- }
- return nil
- }
- func checkMaxLength(field reflect.StructField, valueField reflect.Value, tag string) error {
- if valueField.IsValid() && valueField.String() != "" {
- maxLength, err := strconv.Atoi(tag)
- if err != nil {
- return err
- }
- length := valueField.Len()
- if valueField.Kind().String() == "string" {
- length = strings.Count(valueField.String(), "") - 1
- }
- if maxLength < length {
- errMsg := fmt.Sprintf("The length of %s is %d which is more than %d", field.Name, length, maxLength)
- return errors.New(errMsg)
- }
- }
- return nil
- }
- func checkMinLength(field reflect.StructField, valueField reflect.Value, tag string) error {
- if valueField.IsValid() {
- minLength, err := strconv.Atoi(tag)
- if err != nil {
- return err
- }
- length := valueField.Len()
- if valueField.Kind().String() == "string" {
- length = strings.Count(valueField.String(), "") - 1
- }
- if minLength > length {
- errMsg := fmt.Sprintf("The length of %s is %d which is less than %d", field.Name, length, minLength)
- return errors.New(errMsg)
- }
- }
- return nil
- }
- func checkMaximum(field reflect.StructField, valueField reflect.Value, tag string) error {
- if valueField.IsValid() && valueField.String() != "" {
- maximum, err := strconv.ParseFloat(tag, 64)
- if err != nil {
- return err
- }
- byt, _ := json.Marshal(valueField.Interface())
- num, err := strconv.ParseFloat(string(byt), 64)
- if err != nil {
- return err
- }
- if maximum < num {
- errMsg := fmt.Sprintf("The size of %s is %f which is greater than %f", field.Name, num, maximum)
- return errors.New(errMsg)
- }
- }
- return nil
- }
- func checkMinimum(field reflect.StructField, valueField reflect.Value, tag string) error {
- if valueField.IsValid() && valueField.String() != "" {
- minimum, err := strconv.ParseFloat(tag, 64)
- if err != nil {
- return err
- }
- byt, _ := json.Marshal(valueField.Interface())
- num, err := strconv.ParseFloat(string(byt), 64)
- if err != nil {
- return err
- }
- if minimum > num {
- errMsg := fmt.Sprintf("The size of %s is %f which is less than %f", field.Name, num, minimum)
- return errors.New(errMsg)
- }
- }
- return nil
- }
|