From 7507cf8fe1ad28357b23c441ae4228db126f6d64 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?=
 <go_developer@163.com>
Date: Sun, 23 Mar 2025 17:51:13 +0800
Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=8D=95=E5=85=83=E6=B5=8B?=
 =?UTF-8?q?=E8=AF=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 abstract.go     |   4 ++
 builder_test.go | 129 ++++++++++++++++++++++++++++++++++++++++++++++++
 field_config.go |   8 +++
 3 files changed, 141 insertions(+)

diff --git a/abstract.go b/abstract.go
index 30f3af2..74fb89c 100644
--- a/abstract.go
+++ b/abstract.go
@@ -27,6 +27,10 @@ type IFieldConfig interface {
 	SetType(typ any) IFieldConfig
 	// SetTag 设置字段 tag.
 	SetTag(tag string) IFieldConfig
+	// GetType 获取类型
+	GetType() any
+	// GetTag 获取tag
+	GetTag() string
 }
 
 // IDynamicStruct contains defined dynamic struct.
diff --git a/builder_test.go b/builder_test.go
index 790235d..08b1cc4 100644
--- a/builder_test.go
+++ b/builder_test.go
@@ -94,3 +94,132 @@ func TestStruct(t *testing.T) {
 		So(res["slice"], ShouldEqual, []any{float64(1), float64(2), float64(3)})
 	})
 }
+
+// TestNestedStruct : 测试嵌套结构体
+func TestNestedStruct(t *testing.T) {
+	Convey("嵌套结构体", t, func() {
+		data := []byte(`
+		{
+"user": {"info": {
+			"age": 123,
+			"name": "example",
+			"double": 123.45,
+			"bool": true,
+			"slice": [1, 2, 3]
+		}}}
+		`)
+		instance := NewStruct(map[string]string{
+			"test_tag_map": `json:"tag_map"`,
+		}).
+			AddField("user.info.age", "", 0, `json:"age"`, false).
+			AddField("user.info.name", "", "", `json:"name"`, false).
+			Build()
+		val := instance.New()
+		err := json.Unmarshal(data, &val)
+		So(err, ShouldBeNil)
+		reflectType := reflect.TypeOf(val)
+		// 需要是结构体类型
+		So(reflectType.Elem().Kind(), ShouldEqual, reflect.Struct)
+		// 验证数据
+		// 数据序列化成功
+		targetByte, targetErr := json.Marshal(val)
+		So(targetErr, ShouldBeNil)
+		// 数据转map成功
+		var res map[string]any
+		targetUnmarshalErr := json.Unmarshal(targetByte, &res)
+		So(targetUnmarshalErr, ShouldBeNil)
+		So(len(res), ShouldEqual, 1)
+		So(res["user"], ShouldNotBeEmpty)
+		userMap, ok := res["user"].(map[string]any)
+		So(ok, ShouldBeTrue)
+		So(len(userMap), ShouldEqual, 1)
+		userInfoMap, ok := userMap["info"].(map[string]any)
+		So(ok, ShouldBeTrue)
+		So(userInfoMap["age"], ShouldEqual, float64(123))
+		So(userInfoMap["name"], ShouldEqual, "example")
+	})
+}
+
+// TestStruct : 测试数组
+func TestArray(t *testing.T) {
+	Convey("嵌套结构体带多级数组", t, func() {
+		data := []byte(`
+		{
+"user": {"list":[[[{
+			"age": 123,
+			"name": "example",
+			"double": 123.45,
+			"bool": true,
+			"slice": [1, 2, 3]
+		}]]]}
+}
+		`)
+		instance := NewStruct(map[string]string{
+			"test_tag_map": `json:"tag_map"`,
+		}).
+			AddField("user.list.[].[].[].age", "", 0, `json:"age"`, false).
+			AddField("user.list.[].[].[].name", "", "", `json:"name"`, false).
+			Build()
+		val := instance.New()
+		err := json.Unmarshal(data, &val)
+		So(err, ShouldBeNil)
+		reflectType := reflect.TypeOf(val)
+		// 需要是结构体类型
+		So(reflectType.Elem().Kind(), ShouldEqual, reflect.Struct)
+		// 验证数据
+		// 数据序列化成功
+		targetByte, targetErr := json.Marshal(val)
+		So(targetErr, ShouldBeNil)
+		// 数据转map成功
+		var res map[string]map[string][][][]any
+		targetUnmarshalErr := json.Unmarshal(targetByte, &res)
+		So(targetUnmarshalErr, ShouldBeNil)
+		So(len(res), ShouldEqual, 1)
+		So(res["user"], ShouldNotBeEmpty)
+		So(len(res["user"]), ShouldEqual, 1)
+		So(len(res["user"]["list"][0]), ShouldEqual, 1)
+		So(len(res["user"]["list"][0][0]), ShouldEqual, 1)
+		userMap, ok := res["user"]["list"][0][0][0].(map[string]any)
+		So(ok, ShouldBeTrue)
+		So(len(userMap), ShouldEqual, 2)
+		So(userMap["age"], ShouldEqual, float64(123))
+		So(userMap["name"], ShouldEqual, "example")
+		So(userMap["double"], ShouldBeNil)
+	})
+}
+
+func TestFieldManage(t *testing.T) {
+	Convey("结构体字段管理", t, func() {
+		instance := NewStruct(map[string]string{
+			"test_tag_map": `json:"tag_map"`,
+		}).AddField("age", "", 0, `json:"age"`, false).
+			AddField("name", "", "", `json:"name"`, false)
+		So(instance.HasField("Name"), ShouldBeTrue)
+		So(instance.GetField("Name"), ShouldNotBeNil)
+		instance.RemoveField("Name")
+		So(instance.HasField("Name"), ShouldBeFalse)
+		So(instance.GetField("Name"), ShouldBeNil)
+		So(instance.HasField("Age"), ShouldBeTrue)
+	})
+}
+
+func TestExtendStruct(t *testing.T) {
+	Convey("结构体字段继承", t, func() {
+		type User struct {
+			Name string `json:"name"`
+			Age  int    `json:"age"`
+		}
+		type Company struct {
+			Address string  `json:"address"`
+			Logo    string  `json:"logo"`
+			Age     float64 `json:"company_age"` // 应该覆盖掉 User.Age
+		}
+		instance := ExtendStruct(User{}, Company{})
+		So(instance.HasField("Name"), ShouldBeTrue)
+		So(instance.HasField("Age"), ShouldBeTrue)
+		So(instance.HasField("Address"), ShouldBeTrue)
+		So(instance.HasField("Logo"), ShouldBeTrue)
+		So(reflect.TypeOf(instance.GetField("Age").GetType()).Kind(), ShouldEqual, reflect.Float64)
+		So(instance.GetField("Age").GetTag(), ShouldEqual, `json:"company_age"`)
+	})
+}
diff --git a/field_config.go b/field_config.go
index 8d59aaf..ceb3b74 100644
--- a/field_config.go
+++ b/field_config.go
@@ -21,8 +21,16 @@ func (f *fieldConfigImpl) SetType(typ any) IFieldConfig {
 	return f
 }
 
+func (f *fieldConfigImpl) GetType() any {
+	return f.typ
+}
+
 // SetTag 设置字段标签
 func (f *fieldConfigImpl) SetTag(tag string) IFieldConfig {
 	f.tag = tag
 	return f
 }
+
+func (f *fieldConfigImpl) GetTag() string {
+	return f.tag
+}