feat(form): add array collection format in form binding (#3986)
* feat(form): add array collection format in form binding * feat(form): add array collection format in form binding * test(form): fix test code for array collection format in form binding
This commit is contained in:
		@ -182,6 +182,38 @@ func trySetCustom(val string, value reflect.Value) (isSet bool, err error) {
 | 
			
		||||
	return false, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func trySplit(vs []string, field reflect.StructField) (newVs []string, err error) {
 | 
			
		||||
	cfTag := field.Tag.Get("collection_format")
 | 
			
		||||
	if cfTag == "" || cfTag == "multi" {
 | 
			
		||||
		return vs, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var sep string
 | 
			
		||||
	switch cfTag {
 | 
			
		||||
	case "csv":
 | 
			
		||||
		sep = ","
 | 
			
		||||
	case "ssv":
 | 
			
		||||
		sep = " "
 | 
			
		||||
	case "tsv":
 | 
			
		||||
		sep = "\t"
 | 
			
		||||
	case "pipes":
 | 
			
		||||
		sep = "|"
 | 
			
		||||
	default:
 | 
			
		||||
		return vs, fmt.Errorf("%s is not supported in the collection_format. (csv, ssv, pipes)", cfTag)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	totalLength := 0
 | 
			
		||||
	for _, v := range vs {
 | 
			
		||||
		totalLength += strings.Count(v, sep) + 1
 | 
			
		||||
	}
 | 
			
		||||
	newVs = make([]string, 0, totalLength)
 | 
			
		||||
	for _, v := range vs {
 | 
			
		||||
		newVs = append(newVs, strings.Split(v, sep)...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return newVs, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func setByForm(value reflect.Value, field reflect.StructField, form map[string][]string, tagValue string, opt setOptions) (isSet bool, err error) {
 | 
			
		||||
	vs, ok := form[tagValue]
 | 
			
		||||
	if !ok && !opt.isDefaultExists {
 | 
			
		||||
@ -198,6 +230,10 @@ func setByForm(value reflect.Value, field reflect.StructField, form map[string][
 | 
			
		||||
			return ok, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if vs, err = trySplit(vs, field); err != nil {
 | 
			
		||||
			return false, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return true, setSlice(vs, value, field)
 | 
			
		||||
	case reflect.Array:
 | 
			
		||||
		if !ok {
 | 
			
		||||
@ -208,6 +244,10 @@ func setByForm(value reflect.Value, field reflect.StructField, form map[string][
 | 
			
		||||
			return ok, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if vs, err = trySplit(vs, field); err != nil {
 | 
			
		||||
			return false, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(vs) != value.Len() {
 | 
			
		||||
			return false, fmt.Errorf("%q is not valid value for %s", vs, value.Type().String())
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -264,6 +264,45 @@ func TestMappingArray(t *testing.T) {
 | 
			
		||||
	require.Error(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestMappingCollectionFormat(t *testing.T) {
 | 
			
		||||
	var s struct {
 | 
			
		||||
		SliceMulti []int  `form:"slice_multi" collection_format:"multi"`
 | 
			
		||||
		SliceCsv   []int  `form:"slice_csv" collection_format:"csv"`
 | 
			
		||||
		SliceSsv   []int  `form:"slice_ssv" collection_format:"ssv"`
 | 
			
		||||
		SliceTsv   []int  `form:"slice_tsv" collection_format:"tsv"`
 | 
			
		||||
		SlicePipes []int  `form:"slice_pipes" collection_format:"pipes"`
 | 
			
		||||
		ArrayMulti [2]int `form:"array_multi" collection_format:"multi"`
 | 
			
		||||
		ArrayCsv   [2]int `form:"array_csv" collection_format:"csv"`
 | 
			
		||||
		ArraySsv   [2]int `form:"array_ssv" collection_format:"ssv"`
 | 
			
		||||
		ArrayTsv   [2]int `form:"array_tsv" collection_format:"tsv"`
 | 
			
		||||
		ArrayPipes [2]int `form:"array_pipes" collection_format:"pipes"`
 | 
			
		||||
	}
 | 
			
		||||
	err := mappingByPtr(&s, formSource{
 | 
			
		||||
		"slice_multi": {"1", "2"},
 | 
			
		||||
		"slice_csv":   {"1,2"},
 | 
			
		||||
		"slice_ssv":   {"1 2"},
 | 
			
		||||
		"slice_tsv":   {"1	2"},
 | 
			
		||||
		"slice_pipes": {"1|2"},
 | 
			
		||||
		"array_multi": {"1", "2"},
 | 
			
		||||
		"array_csv":   {"1,2"},
 | 
			
		||||
		"array_ssv":   {"1 2"},
 | 
			
		||||
		"array_tsv":   {"1	2"},
 | 
			
		||||
		"array_pipes": {"1|2"},
 | 
			
		||||
	}, "form")
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
	assert.Equal(t, []int{1, 2}, s.SliceMulti)
 | 
			
		||||
	assert.Equal(t, []int{1, 2}, s.SliceCsv)
 | 
			
		||||
	assert.Equal(t, []int{1, 2}, s.SliceSsv)
 | 
			
		||||
	assert.Equal(t, []int{1, 2}, s.SliceTsv)
 | 
			
		||||
	assert.Equal(t, []int{1, 2}, s.SlicePipes)
 | 
			
		||||
	assert.Equal(t, [2]int{1, 2}, s.ArrayMulti)
 | 
			
		||||
	assert.Equal(t, [2]int{1, 2}, s.ArrayCsv)
 | 
			
		||||
	assert.Equal(t, [2]int{1, 2}, s.ArraySsv)
 | 
			
		||||
	assert.Equal(t, [2]int{1, 2}, s.ArrayTsv)
 | 
			
		||||
	assert.Equal(t, [2]int{1, 2}, s.ArrayPipes)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestMappingStructField(t *testing.T) {
 | 
			
		||||
	var s struct {
 | 
			
		||||
		J struct {
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user