mirror of
https://github.com/gin-gonic/gin.git
synced 2025-04-06 03:57:46 +08:00
Merge fbd60bfe6b3c2ccc7d1823396bffcbf850b85216 into 8763f33c65f7df8be5b9fe7504ab7fcf20abb41d
This commit is contained in:
commit
a12c35a302
29
binding/decimal.go
Normal file
29
binding/decimal.go
Normal file
@ -0,0 +1,29 @@
|
||||
package binding
|
||||
|
||||
import (
|
||||
"github.com/shopspring/decimal"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CustomDecimal represents a decimal number that can be bound from form values.
|
||||
// It supports values with leading dots (e.g. ".1" is parsed as "0.1").
|
||||
type CustomDecimal struct {
|
||||
decimal.Decimal
|
||||
}
|
||||
|
||||
// UnmarshalParam implements the binding.BindUnmarshaler interface.
|
||||
// It converts form values to decimal.Decimal, with special handling for
|
||||
// values that start with a dot (e.g. ".1" becomes "0.1").
|
||||
func (cd *CustomDecimal) UnmarshalParam(val string) error {
|
||||
if strings.HasPrefix(val, ".") {
|
||||
val = "0" + val
|
||||
}
|
||||
|
||||
dec, err := decimal.NewFromString(val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cd.Decimal = dec
|
||||
return nil
|
||||
}
|
59
binding/decimal_test.go
Normal file
59
binding/decimal_test.go
Normal file
@ -0,0 +1,59 @@
|
||||
package binding
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCustomDecimalUnmarshalParam(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "leading dot",
|
||||
input: ".1",
|
||||
want: "0.1",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "invalid decimal",
|
||||
input: "abc",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty string",
|
||||
input: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "leading dot with multiple digits",
|
||||
input: ".123",
|
||||
want: "0.123",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "normal decimal",
|
||||
input: "1.23",
|
||||
want: "1.23",
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var cd CustomDecimal
|
||||
err := cd.UnmarshalParam(tt.input)
|
||||
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.want, cd.String())
|
||||
})
|
||||
}
|
||||
}
|
31
examples/custom-decimal/main.go
Normal file
31
examples/custom-decimal/main.go
Normal file
@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type QueryParams struct {
|
||||
Amount binding.CustomDecimal `form:"amount"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
r := gin.Default()
|
||||
|
||||
r.GET("/amount", func(c *gin.Context) {
|
||||
var params QueryParams
|
||||
if err := c.BindQuery(¶ms); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"amount": params.Amount.String(),
|
||||
})
|
||||
})
|
||||
|
||||
r.Run(":8080")
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user