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 +}