mirror of
https://github.com/gin-gonic/gin.git
synced 2025-04-24 02:16:24 +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