Skip to content

Commit 40d14a9

Browse files
authored
🐛 fix: Embedded struct parsing (#3478)
* Fix "[Bug]: Incorrect Parsing of Slice by QueryParser() with Embedded Structs #2859" * Fix "[Bug]: Incorrect Parsing of Slice by QueryParser() with Embedded Structs #2859"
1 parent b6f0772 commit 40d14a9

File tree

2 files changed

+62
-20
lines changed

2 files changed

+62
-20
lines changed

ctx.go

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,43 +1326,44 @@ func (*Ctx) parseToStruct(aliasTag string, out interface{}, data map[string][]st
13261326
}
13271327

13281328
func equalFieldType(out interface{}, kind reflect.Kind, key, tag string) bool {
1329-
// Get type of interface
13301329
outTyp := reflect.TypeOf(out).Elem()
1331-
key = utils.ToLower(key)
1332-
// Must be a struct to match a field
13331330
if outTyp.Kind() != reflect.Struct {
13341331
return false
13351332
}
1336-
// Copy interface to an value to be used
1337-
outVal := reflect.ValueOf(out).Elem()
1338-
// Loop over each field
1333+
key = utils.ToLower(key)
1334+
return checkEqualFieldType(outTyp, kind, key, tag)
1335+
}
1336+
1337+
func checkEqualFieldType(outTyp reflect.Type, kind reflect.Kind, key, tag string) bool {
13391338
for i := 0; i < outTyp.NumField(); i++ {
1340-
// Get field value data
1341-
structField := outVal.Field(i)
1342-
// Can this field be changed?
1343-
if !structField.CanSet() {
1339+
typeField := outTyp.Field(i)
1340+
1341+
if typeField.Anonymous && typeField.Type.Kind() == reflect.Struct {
1342+
if checkEqualFieldType(typeField.Type, kind, key, tag) {
1343+
return true
1344+
}
1345+
}
1346+
1347+
if typeField.PkgPath != "" { // unexported field
13441348
continue
13451349
}
1346-
// Get field key data
1347-
typeField := outTyp.Field(i)
1348-
// Get type of field key
1349-
structFieldKind := structField.Kind()
1350-
// Does the field type equals input?
1351-
if structFieldKind != kind {
1350+
1351+
if typeField.Type.Kind() != kind {
13521352
continue
13531353
}
1354-
// Get tag from field if exist
1354+
13551355
inputFieldName := typeField.Tag.Get(tag)
13561356
if inputFieldName == "" {
13571357
inputFieldName = typeField.Name
1358-
} else {
1359-
inputFieldName = strings.Split(inputFieldName, ",")[0]
1358+
} else if idx := strings.IndexByte(inputFieldName, ','); idx > -1 {
1359+
inputFieldName = inputFieldName[:idx]
13601360
}
1361-
// Compare field/tag with provided key
1361+
13621362
if utils.ToLower(inputFieldName) == key {
13631363
return true
13641364
}
13651365
}
1366+
13661367
return false
13671368
}
13681369

ctx_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4875,6 +4875,28 @@ func Test_Ctx_QueryParser_Schema(t *testing.T) {
48754875
utils.AssertEqual(t, 12, cq.Data[1].Age)
48764876
}
48774877

4878+
func Test_Ctx_QueryParser_EmbeddedStruct(t *testing.T) {
4879+
t.Parallel()
4880+
app := New(Config{EnableSplittingOnParsers: true})
4881+
c := app.AcquireCtx(&fasthttp.RequestCtx{})
4882+
defer app.ReleaseCtx(c)
4883+
4884+
type A struct {
4885+
Products []string `query:"products"`
4886+
}
4887+
4888+
type Person struct {
4889+
Name string `query:"name"`
4890+
Pass string `query:"pass"`
4891+
A
4892+
}
4893+
4894+
c.Request().URI().SetQueryString("name=john&pass=doe&products=shoe,hat")
4895+
p := new(Person)
4896+
utils.AssertEqual(t, nil, c.QueryParser(p))
4897+
utils.AssertEqual(t, []string{"shoe", "hat"}, p.Products)
4898+
}
4899+
48784900
// go test -run Test_Ctx_ReqHeaderParser -v
48794901
func Test_Ctx_ReqHeaderParser(t *testing.T) {
48804902
t.Parallel()
@@ -5402,6 +5424,25 @@ func Benchmark_Ctx_ReqHeaderParser(b *testing.B) {
54025424
utils.AssertEqual(b, nil, c.ReqHeaderParser(q))
54035425
}
54045426

5427+
// go test -v -run=^$ -bench=Benchmark_equalFieldType -benchmem -count=4
5428+
func Benchmark_equalFieldType(b *testing.B) {
5429+
type user struct {
5430+
Name string `query:"name"`
5431+
Age int `query:"age"`
5432+
}
5433+
5434+
u := new(user)
5435+
b.ReportAllocs()
5436+
b.ResetTimer()
5437+
5438+
var res bool
5439+
for n := 0; n < b.N; n++ {
5440+
res = equalFieldType(u, reflect.String, "name", queryTag)
5441+
}
5442+
5443+
utils.AssertEqual(b, true, res)
5444+
}
5445+
54055446
// go test -run Test_Ctx_BodyStreamWriter
54065447
func Test_Ctx_BodyStreamWriter(t *testing.T) {
54075448
t.Parallel()

0 commit comments

Comments
 (0)