Skip to content

Commit

Permalink
fix: add skipt empty string parser, if kind is number
Browse files Browse the repository at this point in the history
  • Loading branch information
thinkgos committed May 29, 2024
1 parent e4d4e5a commit 871bcec
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 2 deletions.
32 changes: 30 additions & 2 deletions form/form_custom_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func EncodeSliceToCommaString(t reflect.Type, x any) ([]string, error) {
val = strconv.FormatBool(fv.Bool())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
val = strconv.FormatInt(fv.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
val = strconv.FormatUint(fv.Uint(), 10)
case reflect.Float32:
val = strconv.FormatFloat(fv.Float(), 'f', -1, 32)
Expand Down Expand Up @@ -130,6 +130,28 @@ func DecodeCommaString2Slice[T constraints.Integer | constraints.Float | ~string
}
}

var _skipIfEmptyStringAndNumber = map[reflect.Kind]struct{}{
reflect.Bool: {},
reflect.Int: {},
reflect.Int8: {},
reflect.Int16: {},
reflect.Int32: {},
reflect.Int64: {},
reflect.Uint: {},
reflect.Uint8: {},
reflect.Uint16: {},
reflect.Uint32: {},
reflect.Uint64: {},
reflect.Float32: {},
reflect.Float64: {},
reflect.Uintptr: {},
}

func skipIfEmptyStringAndNumber(k reflect.Kind) bool {
_, ok := _skipIfEmptyStringAndNumber[k]
return ok
}

// DecodeCommaString22Slice decode a comma-separated string to a slice.
// NOTE: slice element only support `constraints.Integer | constraints.Float | ~string | ~bool`
func DecodeCommaString22Slice(t reflect.Type, values []string) (any, error) {
Expand All @@ -144,6 +166,9 @@ func DecodeCommaString22Slice(t reflect.Type, values []string) (any, error) {
te := t.Elem()
teKind := te.Kind()
for _, s := range values {
if skipIfEmptyStringAndNumber(teKind) && strings.TrimSpace(s) == "" {
continue
}
elements := strings.Split(s, ",")
if oldLen, oldCap := ret.Len(), ret.Cap(); oldCap < oldLen+len(elements) {
newCap := growCap(oldCap, oldCap+len(elements))
Expand All @@ -152,6 +177,9 @@ func DecodeCommaString22Slice(t reflect.Type, values []string) (any, error) {
ret = nret
}
for _, ss := range elements {
if skipIfEmptyStringAndNumber(teKind) && strings.TrimSpace(ss) == "" {
continue
}
val := reflect.New(te).Elem()
switch teKind {
case reflect.Bool:
Expand Down Expand Up @@ -214,7 +242,7 @@ func DecodeCommaString22Slice(t reflect.Type, values []string) (any, error) {
return nil, err
}
val.SetUint(i)
case reflect.Uint64:
case reflect.Uint64, reflect.Uintptr:
i, err := strconv.ParseUint(ss, 10, 64)
if err != nil {
return nil, err
Expand Down
30 changes: 30 additions & 0 deletions form/form_custom_type_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type CustomUint8 uint8
type CustomUint16 uint16
type CustomUint32 uint32
type CustomUint64 uint64
type CustomUintptr uintptr
type CustomFloat32 float32
type CustomFloat64 float64
type CustomString string
Expand All @@ -35,6 +36,7 @@ type customCodecValue struct {
U16 []uint16 `json:"u16"`
U32 []uint32 `json:"u32"`
U64 []uint64 `json:"u64"`
Up []uintptr `json:"up"`
F32 []float32 `json:"f32"`
F64 []float64 `json:"f64"`
S []string `json:"s"`
Expand All @@ -49,6 +51,7 @@ type customCodecValue struct {
Cu16 []CustomUint16 `json:"cu16"`
Cu32 []CustomUint32 `json:"cu32"`
Cu64 []CustomUint64 `json:"cu64"`
Cup []CustomUintptr `json:"cup"`
Cf32 []CustomFloat32 `json:"cf32"`
Cf64 []CustomFloat64 `json:"cf64"`
Cs []CustomString `json:"cs"`
Expand All @@ -70,6 +73,7 @@ var testCodecValue = customCodecValue{
U16: []uint16{1611, 1622, 1633},
U32: []uint32{3211, 3222, 3233},
U64: []uint64{6411, 6422, 6433},
Up: []uintptr{99991, 99992, 99993},
F32: []float32{1.1, 1.2, 1.3},
F64: []float64{2.1, 2.2, 2.3},
S: []string{"a", "b", "c", "d", "e", "f"},
Expand All @@ -84,6 +88,7 @@ var testCodecValue = customCodecValue{
Cu16: []CustomUint16{1611, 1622, 1633},
Cu32: []CustomUint32{3211, 3222, 3233},
Cu64: []CustomUint64{6411, 6422, 6433},
Cup: []CustomUintptr{99991, 99992, 99993},
Cf32: []CustomFloat32{1.1, 1.2, 1.3},
Cf64: []CustomFloat64{2.1, 2.2, 2.3},
Cs: []CustomString{"a", "b", "c"},
Expand All @@ -104,6 +109,7 @@ var testDecoderUrlValues = url.Values{
"u16": []string{"1611,1622,1633"},
"u32": []string{"3211,3222,3233"},
"u64": []string{"6411,6422,6433"},
"up": []string{"99991", "99992", "99993"},
"f32": []string{"1.1,1.2,1.3"},
"f64": []string{"2.1,2.2,2.3"},
"s": []string{"a,b,c", "d,e,f"},
Expand All @@ -118,6 +124,7 @@ var testDecoderUrlValues = url.Values{
"cu16": []string{"1611,1622,1633"},
"cu32": []string{"3211,3222,3233"},
"cu64": []string{"6411,6422,6433"},
"cup": []string{"99991", "99992", "99993"},
"cf32": []string{"1.1,1.2,1.3"},
"cf64": []string{"2.1,2.2,2.3"},
"cs": []string{"a,b,c"},
Expand All @@ -139,6 +146,7 @@ var testEncoderUrlValues = url.Values{
"u16": []string{"1611,1622,1633"},
"u32": []string{"3211,3222,3233"},
"u64": []string{"6411,6422,6433"},
"up": []string{"99991,99992,99993"},
"f32": []string{"1.1,1.2,1.3"},
"f64": []string{"2.1,2.2,2.3"},
"s": []string{"a,b,c,d,e,f"},
Expand All @@ -153,6 +161,7 @@ var testEncoderUrlValues = url.Values{
"cu16": []string{"1611,1622,1633"},
"cu32": []string{"3211,3222,3233"},
"cu64": []string{"6411,6422,6433"},
"cup": []string{"99991,99992,99993"},
"cf32": []string{"1.1,1.2,1.3"},
"cf64": []string{"2.1,2.2,2.3"},
"cs": []string{"a,b,c"},
Expand All @@ -178,6 +187,7 @@ func Test_CustomType_Encoder(t *testing.T) {
enc.RegisterCustomTypeFunc(EncodeSlice2CommaString[CustomUint16](), []CustomUint16{})
enc.RegisterCustomTypeFunc(EncodeSlice2CommaString[CustomUint32](), []CustomUint32{})
enc.RegisterCustomTypeFunc(EncodeSlice2CommaString[CustomUint64](), []CustomUint64{})
enc.RegisterCustomTypeFunc(EncodeSlice2CommaString[CustomUintptr](), []CustomUintptr{})
enc.RegisterCustomTypeFunc(EncodeSlice2CommaString[CustomFloat32](), []CustomFloat32{})
enc.RegisterCustomTypeFunc(EncodeSlice2CommaString[CustomFloat64](), []CustomFloat64{})
enc.RegisterCustomTypeFunc(EncodeSlice2CommaString[CustomString](), []CustomString{})
Expand Down Expand Up @@ -221,6 +231,7 @@ func Test_CustomType_Decoder(t *testing.T) {
dec.RegisterCustomTypeFunc(DecodeCommaString2Slice[CustomUint16](), []CustomUint16{})
dec.RegisterCustomTypeFunc(DecodeCommaString2Slice[CustomUint32](), []CustomUint32{})
dec.RegisterCustomTypeFunc(DecodeCommaString2Slice[CustomUint64](), []CustomUint64{})
dec.RegisterCustomTypeFunc(DecodeCommaString2Slice[CustomUintptr](), []CustomUintptr{})
dec.RegisterCustomTypeFunc(DecodeCommaString2Slice[CustomFloat32](), []CustomFloat32{})
dec.RegisterCustomTypeFunc(DecodeCommaString2Slice[CustomFloat64](), []CustomFloat64{})
dec.RegisterCustomTypeFunc(DecodeCommaString2Slice[CustomString](), []CustomString{})
Expand All @@ -245,6 +256,24 @@ func Test_CustomType_Decoder(t *testing.T) {
require.Error(t, err)
t.Log(err)
})
t.Run("skip if empty string and number type", func(t *testing.T) {
type Custom struct {
A []int `json:"a"`
}
got1 := Custom{}
err := dec.Decode(&got1, url.Values{
"a": []string{""},
})
require.NoError(t, err)
require.Equal(t, Custom{A: []int{}}, got1)

got2 := Custom{}
err = dec.Decode(&got2, url.Values{
"a": []string{"1,,3"},
})
require.NoError(t, err)
require.Equal(t, Custom{A: []int{1, 3}}, got2)
})

t.Run("invalid value", func(t *testing.T) {
got := customCodecValue{}
Expand All @@ -253,4 +282,5 @@ func Test_CustomType_Decoder(t *testing.T) {
})
require.Error(t, err)
})

}

Check failure on line 286 in form/form_custom_type_test.go

View workflow job for this annotation

GitHub Actions / GolangCi-Lint

unnecessary trailing newline (whitespace)

Check failure on line 286 in form/form_custom_type_test.go

View workflow job for this annotation

GitHub Actions / GolangCi-Lint

unnecessary trailing newline (whitespace)

0 comments on commit 871bcec

Please sign in to comment.