Merge fbd60bfe6b3c2ccc7d1823396bffcbf850b85216 into 8763f33c65f7df8be5b9fe7504ab7fcf20abb41d

This commit is contained in:
aydinomer00 2025-03-23 04:01:40 +05:30 committed by GitHub
commit a12c35a302
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 119 additions and 0 deletions

29
binding/decimal.go Normal file
View 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
View 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())
})
}
}

View 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(&params); 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")
}