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