github.com/System-Glitch/goyave/v2@v2.10.3-0.20200819142921-51011e75d504/validation/arrays.go (about)

     1  package validation
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"net/url"
     7  	"reflect"
     8  	"time"
     9  
    10  	"github.com/System-Glitch/goyave/v2/helper"
    11  	"github.com/google/uuid"
    12  )
    13  
    14  // createArray create a slice of the same type as the given type.
    15  func createArray(dataType string, length int) reflect.Value {
    16  	var arr reflect.Value
    17  	switch dataType {
    18  	case "string":
    19  		newArray := make([]string, 0, length)
    20  		arr = reflect.ValueOf(&newArray).Elem()
    21  	case "numeric":
    22  		newArray := make([]float64, 0, length)
    23  		arr = reflect.ValueOf(&newArray).Elem()
    24  	case "integer":
    25  		newArray := make([]int, 0, length)
    26  		arr = reflect.ValueOf(&newArray).Elem()
    27  	case "timezone":
    28  		newArray := make([]*time.Location, 0, length)
    29  		arr = reflect.ValueOf(&newArray).Elem()
    30  	case "ip", "ipv4", "ipv6":
    31  		newArray := make([]net.IP, 0, length)
    32  		arr = reflect.ValueOf(&newArray).Elem()
    33  	case "json":
    34  		newArray := make([]interface{}, 0, length)
    35  		arr = reflect.ValueOf(&newArray).Elem()
    36  	case "url":
    37  		newArray := make([]*url.URL, 0, length)
    38  		arr = reflect.ValueOf(&newArray).Elem()
    39  	case "uuid":
    40  		newArray := make([]uuid.UUID, 0, length)
    41  		arr = reflect.ValueOf(&newArray).Elem()
    42  	case "bool":
    43  		newArray := make([]bool, 0, length)
    44  		arr = reflect.ValueOf(&newArray).Elem()
    45  	case "date":
    46  		newArray := make([]time.Time, 0, length)
    47  		arr = reflect.ValueOf(&newArray).Elem()
    48  	}
    49  	return arr
    50  }
    51  
    52  func validateArray(field string, value interface{}, parameters []string, form map[string]interface{}) bool {
    53  	if GetFieldType(value) == "array" {
    54  
    55  		if len(parameters) == 0 {
    56  			return true
    57  		}
    58  
    59  		if parameters[0] == "array" {
    60  			panic("Cannot use array type for array validation. Use \">array\" instead")
    61  		}
    62  
    63  		if !validationRules[parameters[0]].IsType {
    64  			panic(fmt.Sprintf("Rule %s is not converting, cannot use it for array validation", parameters[0]))
    65  		}
    66  
    67  		list := reflect.ValueOf(value)
    68  		length := list.Len()
    69  		arr := createArray(parameters[0], length)
    70  
    71  		params := parameters[1:]
    72  
    73  		for i := 0; i < length; i++ {
    74  			val := list.Index(i).Interface()
    75  			tmpData := map[string]interface{}{field: val}
    76  			if !validationRules[parameters[0]].Function(field, val, params, tmpData) {
    77  				return false
    78  			}
    79  			arr.Set(reflect.Append(arr, reflect.ValueOf(tmpData[field])))
    80  		}
    81  
    82  		form[field] = arr.Interface()
    83  		return true
    84  	}
    85  
    86  	return false
    87  }
    88  
    89  func validateDistinct(field string, value interface{}, parameters []string, form map[string]interface{}) bool {
    90  	if GetFieldType(value) != "array" {
    91  		return false // Can't validate if not an array
    92  	}
    93  
    94  	found := []interface{}{}
    95  	list := reflect.ValueOf(value)
    96  	for i := 0; i < list.Len(); i++ {
    97  		v := list.Index(i).Interface()
    98  		if helper.Contains(found, v) {
    99  			return false
   100  		}
   101  		found = append(found, v)
   102  	}
   103  
   104  	return true
   105  }
   106  
   107  func checkInNumeric(parameters []string, value interface{}) bool {
   108  	for _, v := range parameters {
   109  		floatVal, _ := helper.ToFloat64(value)
   110  		other, err := helper.ToFloat64(v)
   111  		if err == nil && floatVal == other { // Compare only values of the same type
   112  			return true
   113  		}
   114  	}
   115  	return false
   116  }
   117  
   118  func validateIn(field string, value interface{}, parameters []string, form map[string]interface{}) bool {
   119  	switch GetFieldType(value) {
   120  	case "numeric":
   121  		return checkInNumeric(parameters, value)
   122  	case "string":
   123  		return helper.Contains(parameters, value)
   124  	}
   125  	// Don't check arrays and files
   126  	return false
   127  }
   128  
   129  func validateNotIn(field string, value interface{}, parameters []string, form map[string]interface{}) bool {
   130  	switch GetFieldType(value) {
   131  	case "numeric":
   132  		return !checkInNumeric(parameters, value)
   133  	case "string":
   134  		return !helper.ContainsStr(parameters, value.(string))
   135  	}
   136  	// Don't check arrays and files
   137  	return false
   138  }
   139  
   140  func validateInArray(field string, value interface{}, parameters []string, form map[string]interface{}) bool {
   141  	other, exists := form[parameters[0]]
   142  	if exists && GetFieldType(other) == "array" {
   143  		return helper.Contains(other, value)
   144  	}
   145  	return false
   146  }
   147  
   148  func validateNotInArray(field string, value interface{}, parameters []string, form map[string]interface{}) bool {
   149  	other, exists := form[parameters[0]]
   150  	if exists && GetFieldType(other) == "array" {
   151  		return !helper.Contains(other, value)
   152  	}
   153  	return false
   154  }