From 08ecef8e0b12f8db0b2127b0bcddf7caea447fe3 Mon Sep 17 00:00:00 2001 From: Jinzhu Date: Tue, 13 Oct 2020 15:32:25 +0800 Subject: [PATCH] Fix NamedArguments with nested struct, close #3596 --- clause/expression.go | 23 ++++++++++++++++------- clause/expression_test.go | 8 ++++++-- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/clause/expression.go b/clause/expression.go index 6a0dde8d..5822a314 100644 --- a/clause/expression.go +++ b/clause/expression.go @@ -91,16 +91,25 @@ func (expr NamedExpr) Build(builder Builder) { namedMap[k] = v } default: - reflectValue := reflect.Indirect(reflect.ValueOf(value)) - switch reflectValue.Kind() { - case reflect.Struct: - modelType := reflectValue.Type() - for i := 0; i < modelType.NumField(); i++ { - if fieldStruct := modelType.Field(i); ast.IsExported(fieldStruct.Name) { - namedMap[fieldStruct.Name] = reflectValue.Field(i).Interface() + var appendFieldsToMap func(reflect.Value) + appendFieldsToMap = func(reflectValue reflect.Value) { + reflectValue = reflect.Indirect(reflectValue) + switch reflectValue.Kind() { + case reflect.Struct: + modelType := reflectValue.Type() + for i := 0; i < modelType.NumField(); i++ { + if fieldStruct := modelType.Field(i); ast.IsExported(fieldStruct.Name) { + namedMap[fieldStruct.Name] = reflectValue.Field(i).Interface() + + if fieldStruct.Anonymous { + appendFieldsToMap(reflectValue.Field(i)) + } + } } } } + + appendFieldsToMap(reflect.ValueOf(value)) } } diff --git a/clause/expression_test.go b/clause/expression_test.go index 19e30e6c..83082486 100644 --- a/clause/expression_test.go +++ b/clause/expression_test.go @@ -37,9 +37,13 @@ func TestExpr(t *testing.T) { } func TestNamedExpr(t *testing.T) { + type Base struct { + Name2 string + } + type NamedArgument struct { Name1 string - Name2 string + Base } results := []struct { @@ -73,7 +77,7 @@ func TestNamedExpr(t *testing.T) { ExpectedVars: []interface{}{"jinzhu", "jinzhu2", "jinzhu", nil}, }, { SQL: "@@test AND name1 = @Name1 AND name2 = @Name2 AND name3 = @Name1 @Notexist", - Vars: []interface{}{NamedArgument{Name1: "jinzhu", Name2: "jinzhu2"}}, + Vars: []interface{}{NamedArgument{Name1: "jinzhu", Base: Base{Name2: "jinzhu2"}}}, Result: "@@test AND name1 = ? AND name2 = ? AND name3 = ? ?", ExpectedVars: []interface{}{"jinzhu", "jinzhu2", "jinzhu", nil}, }, {