From 835b252b5ddcc61d3e200a302c229cb7d76305e4 Mon Sep 17 00:00:00 2001 From: John Guo Date: Tue, 6 Jun 2023 20:40:32 +0800 Subject: [PATCH] fix issue in Where when used in field with prefix that not match struct attribute name (#2688) --- .../mysql/mysql_feature_model_do_test.go | 59 +++++++++++++++++++ .../mysql/testdata/table_with_prefix.sql | 7 +++ database/gdb/gdb_func.go | 16 ++++- os/gspath/gspath_z_unit_test.go | 6 +- 4 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 contrib/drivers/mysql/testdata/table_with_prefix.sql diff --git a/contrib/drivers/mysql/mysql_feature_model_do_test.go b/contrib/drivers/mysql/mysql_feature_model_do_test.go index 2b367e5cf..27a08eab3 100644 --- a/contrib/drivers/mysql/mysql_feature_model_do_test.go +++ b/contrib/drivers/mysql/mysql_feature_model_do_test.go @@ -11,6 +11,7 @@ import ( "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/test/gtest" + "github.com/gogf/gf/v2/text/gstr" "github.com/gogf/gf/v2/util/gconv" ) @@ -329,3 +330,61 @@ func Test_Model_Where_ForDao(t *testing.T) { t.Assert(one[`nickname`], `name_1`) }) } + +func Test_Model_Where_FieldPrefix(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + array := gstr.SplitAndTrim(gtest.DataContent(`table_with_prefix.sql`), ";") + for _, v := range array { + if _, err := db.Exec(ctx, v); err != nil { + gtest.Error(err) + } + } + defer dropTable("instance") + + type Instance struct { + ID int `orm:"f_id"` + Name string + } + + type InstanceDo struct { + g.Meta `orm:"table:instance, do:true"` + ID interface{} `orm:"f_id"` + } + var instance *Instance + err := db.Model("instance").Where(InstanceDo{ + ID: 1, + }).Scan(&instance) + t.AssertNil(err) + t.AssertNE(instance, nil) + t.Assert(instance.ID, 1) + t.Assert(instance.Name, "john") + }) + // With omitempty. + gtest.C(t, func(t *gtest.T) { + array := gstr.SplitAndTrim(gtest.DataContent(`table_with_prefix.sql`), ";") + for _, v := range array { + if _, err := db.Exec(ctx, v); err != nil { + gtest.Error(err) + } + } + defer dropTable("instance") + + type Instance struct { + ID int `orm:"f_id,omitempty"` + Name string + } + + type InstanceDo struct { + g.Meta `orm:"table:instance, do:true"` + ID interface{} `orm:"f_id,omitempty"` + } + var instance *Instance + err := db.Model("instance").Where(InstanceDo{ + ID: 1, + }).Scan(&instance) + t.AssertNil(err) + t.AssertNE(instance, nil) + t.Assert(instance.ID, 1) + t.Assert(instance.Name, "john") + }) +} diff --git a/contrib/drivers/mysql/testdata/table_with_prefix.sql b/contrib/drivers/mysql/testdata/table_with_prefix.sql new file mode 100644 index 000000000..8c4188d49 --- /dev/null +++ b/contrib/drivers/mysql/testdata/table_with_prefix.sql @@ -0,0 +1,7 @@ +CREATE TABLE `instance` ( + `f_id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NULL DEFAULT '', + PRIMARY KEY (`f_id`) USING BTREE +) ENGINE = InnoDB; + +INSERT INTO `instance` VALUES (1, 'john'); \ No newline at end of file diff --git a/database/gdb/gdb_func.go b/database/gdb/gdb_func.go index ad6368f4b..8c6f23dc3 100644 --- a/database/gdb/gdb_func.go +++ b/database/gdb/gdb_func.go @@ -310,9 +310,12 @@ func getFieldsFromStructOrMap(structOrMap interface{}) (fields []string) { Pointer: structOrMap, RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag, }) + var ormTagValue string for _, structField := range structFields { - if tag := structField.Tag(OrmTagForStruct); tag != "" && gregex.IsMatchString(regularFieldNameRegPattern, tag) { - fields = append(fields, tag) + ormTagValue = structField.Tag(OrmTagForStruct) + ormTagValue = gstr.Split(gstr.Trim(ormTagValue), ",")[0] + if ormTagValue != "" && gregex.IsMatchString(regularFieldNameRegPattern, ormTagValue) { + fields = append(fields, ormTagValue) } else { fields = append(fields, structField.Name()) } @@ -494,9 +497,16 @@ func formatWhereHolder(ctx context.Context, db DB, in formatWhereHolderInput) (n data, _ = db.GetCore().mappingAndFilterData(ctx, in.Schema, in.Table, data, true) } // Put the struct attributes in sequence in Where statement. + var ormTagValue string for i := 0; i < reflectType.NumField(); i++ { structField = reflectType.Field(i) - foundKey, foundValue := gutil.MapPossibleItemByKey(data, structField.Name) + // Use tag value from `orm` as field name if specified. + ormTagValue = structField.Tag.Get(OrmTagForStruct) + ormTagValue = gstr.Split(gstr.Trim(ormTagValue), ",")[0] + if ormTagValue == "" { + ormTagValue = structField.Name + } + foundKey, foundValue := gutil.MapPossibleItemByKey(data, ormTagValue) if foundKey != "" { if in.OmitNil && empty.IsNil(foundValue) { continue diff --git a/os/gspath/gspath_z_unit_test.go b/os/gspath/gspath_z_unit_test.go index b269585a6..0b6479365 100644 --- a/os/gspath/gspath_z_unit_test.go +++ b/os/gspath/gspath_z_unit_test.go @@ -53,7 +53,9 @@ func TestSPath_Basic(t *testing.T) { realPath, err = gsp.Add(gfile.Join(root, "gf_tmp", "gf.txt")) t.Assert(err != nil, true) t.Assert(realPath, "") + gsp.Remove("gf_tmp1") + t.Assert(gsp.Size(), 2) t.Assert(len(gsp.Paths()), 2) t.Assert(len(gsp.AllPaths()), 0) @@ -110,9 +112,5 @@ func TestSPath_Basic(t *testing.T) { fp, isDir = gsp.Search("gf_tmp", "gf.txt") t.Assert(fp, gfile.Join(root, "gf_tmp", "gf.txt")) t.Assert(isDir, false) - - fp, isDir = gsp.Search("/", "gf.txt") - t.Assert(fp, pwd) - t.Assert(isDir, true) }) }