Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix issues #2980 #2994

Merged
merged 3 commits into from Oct 11, 2023
Merged

fix issues #2980 #2994

merged 3 commits into from Oct 11, 2023

Conversation

oldme-git
Copy link
Member

gconv.Scan() is the time zone consistent in recursive. View at #2980, please.

type Post struct {
	CreatedAt *gtime.Time `json:"createdAt" `
}

type PostWithUser struct {
	Post
	UserName string `json:"UserName"`
}

gtest.C(t, func(t *gtest.T) {
	params := g.Map{
		"CreatedAt": gtime.New("2023-09-22 12:00:00").UTC(),
		"UserName":  "Galileo",
	}
	postWithUser := new(PostWithUser)
	err := gconv.Scan(params, postWithUser)
	t.AssertNil(err)
	g.Dump(postWithUser.CreatedAt.Location()) // result: Local
})

gtest.C(t, func(t *gtest.T) {
	params := g.Map{
		"CreatedAt": gtime.New("2023-09-22 12:00:00").UTC(),
	}
	post := new(Post)
	err := gconv.Scan(params, post )
	t.AssertNil(err)
	g.Dump(post .CreatedAt.Location()) // result: UTC
})

@oldme-git
Copy link
Member Author

@houseme 之前的PR关掉了,我重新提交一个,帅哥哥帮忙看看o.O

@Issues-translate-bot
Copy link

Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿


@houseme The previous PR was closed, I will resubmit one, handsome brother, please help me take a look o.O

util/gconv/gconv_struct.go Outdated Show resolved Hide resolved
@gqcn
Copy link
Member

gqcn commented Oct 9, 2023

@oldme-git Any updates.

@oldme-git
Copy link
Member Author

@gqcn 匿名结构体在 doStruct 的递归中丢失了细节信息,看一下这个代码示例:

func Test_Struct_Issue2980C(t *testing.T) {
	var pointer interface{} = gtime.New("2023-09-22 12:00:00").UTC()
	fmt.Println(pointer.(*gtime.Time).Location()) // UTC
	if v, ok := pointer.(iUnmarshalText); ok {
		var valueBytes []byte
		if b, ok := pointer.([]byte); ok {
			valueBytes = b
		} else if s, ok := pointer.(string); ok {
			valueBytes = []byte(s)
		} else if f, ok := pointer.(iString); ok {
			// !!!!! gtime.Time的String方法只会转换2006-01-02 15:04:05格式,导致细节丢失
			valueBytes = []byte(f.String()) 
		}
		if len(valueBytes) > 0 {
			v.UnmarshalText(valueBytes)
		}
	}
	fmt.Println(pointer.(*gtime.Time).Location()) // Local
}

第一次执行数据绑定时,嵌套结构体中时间字段尚且是空的,所以可以绑定成功。当递归到第二次的时候,嵌套结构体有了默认值,在执行 bindVarToReflectValueWithInterfaceCheck 时,触发了 gtime 的 UnmarshalText 方法,使时间细节丢失。

这里面的逻辑有些绕,具体的这段代码在 gconv_struct.go 的 409 行 444 行。

强哥有什么其他的好的修改方法吗?

@Issues-translate-bot
Copy link

Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿


@gqcn Anonymous structures lose details in the recursion of doStruct. Take a look at this code example:

func Test_Struct_Issue2980C(t *testing.T) {
var pointer interface{} = gtime.New("2023-09-22 12:00:00").UTC()
fmt.Println(pointer.(*gtime.Time).Location()) // UTC
if v, ok := pointer.(iUnmarshalText); ok {
var valueBytes[]byte
if b, ok := pointer.([]byte); ok {
valueBytes = b
} else if s, ok := pointer.(string); ok {
valueBytes = []byte(s)
} else if f, ok := pointer.(iString); ok {
// !!!!! The String method of gtime.Time will only convert the 2006-01-02 15:04:05 format, resulting in loss of details
valueBytes = []byte(f.String())
}
if len(valueBytes) > 0 {
v.UnmarshalText(valueBytes)
}
}
fmt.Println(pointer.(*gtime.Time).Location()) // Local
}

**When performing data binding for the first time, the time field in the nested structure is still empty, so the binding can be successful. When the recursion reaches the second time, the nested structure has a default value. When bindVarToReflectValueWithInterfaceCheck is executed, the UnmarshalText method of gtime is triggered, causing the time details to be lost. **

The logic here is a bit convoluted. The specific code is in lines 409 and 444 of gconv_struct.go.

Brother Qiang, do you have any other good modification methods?

@gqcn
Copy link
Member

gqcn commented Oct 10, 2023

@gqcn 匿名结构体在 doStruct 的递归中丢失了细节信息,看一下这个代码示例:

func Test_Struct_Issue2980C(t *testing.T) {
	var pointer interface{} = gtime.New("2023-09-22 12:00:00").UTC()
	fmt.Println(pointer.(*gtime.Time).Location()) // UTC
	if v, ok := pointer.(iUnmarshalText); ok {
		var valueBytes []byte
		if b, ok := pointer.([]byte); ok {
			valueBytes = b
		} else if s, ok := pointer.(string); ok {
			valueBytes = []byte(s)
		} else if f, ok := pointer.(iString); ok {
			// !!!!! gtime.Time的String方法只会转换2006-01-02 15:04:05格式,导致细节丢失
			valueBytes = []byte(f.String()) 
		}
		if len(valueBytes) > 0 {
			v.UnmarshalText(valueBytes)
		}
	}
	fmt.Println(pointer.(*gtime.Time).Location()) // Local
}

第一次执行数据绑定时,嵌套结构体中时间字段尚且是空的,所以可以绑定成功。当递归到第二次的时候,嵌套结构体有了默认值,在执行 bindVarToReflectValueWithInterfaceCheck 时,触发了 gtime 的 UnmarshalText 方法,使时间细节丢失。

这里面的逻辑有些绕,具体的这段代码在 gconv_struct.go 的 409 行 444 行。

强哥有什么其他的好的修改方法吗?

我看看呢

@Issues-translate-bot
Copy link

Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿


@gqcn Anonymous structures lose details in the recursion of doStruct, take a look at this code example:

func Test_Struct_Issue2980C(t *testing.T) {
var pointer interface{} = gtime.New("2023-09-22 12:00:00").UTC()
fmt.Println(pointer.(*gtime.Time).Location()) // UTC
if v, ok := pointer.(iUnmarshalText); ok {
var valueBytes []byte
if b, ok := pointer.([]byte); ok {
valueBytes = b
} else if s, ok := pointer.(string); ok {
valueBytes = []byte(s)
} else if f, ok := pointer.(iString); ok {
// !!!!! The String method of gtime.Time will only convert the 2006-01-02 15:04:05 format, resulting in loss of details
valueBytes = []byte(f.String())
}
if len(valueBytes) > 0 {
v.UnmarshalText(valueBytes)
}
}
fmt.Println(pointer.(*gtime.Time).Location()) // Local
}

**When performing data binding for the first time, the time field in the nested structure is still empty, so the binding can be successful. When the recursion reaches the second time, the nested structure has a default value. When bindVarToReflectValueWithInterfaceCheck is executed, the UnmarshalText method of gtime is triggered, causing the time details to be lost. **

The logic here is a bit convoluted. The specific code is in lines 409 and 444 of gconv_struct.go.

Brother Qiang, do you have any other good modification methods?

Let me take a look

@gqcn
Copy link
Member

gqcn commented Oct 10, 2023

@gqcn 匿名结构体在 doStruct 的递归中丢失了细节信息,看一下这个代码示例:

func Test_Struct_Issue2980C(t *testing.T) {
	var pointer interface{} = gtime.New("2023-09-22 12:00:00").UTC()
	fmt.Println(pointer.(*gtime.Time).Location()) // UTC
	if v, ok := pointer.(iUnmarshalText); ok {
		var valueBytes []byte
		if b, ok := pointer.([]byte); ok {
			valueBytes = b
		} else if s, ok := pointer.(string); ok {
			valueBytes = []byte(s)
		} else if f, ok := pointer.(iString); ok {
			// !!!!! gtime.Time的String方法只会转换2006-01-02 15:04:05格式,导致细节丢失
			valueBytes = []byte(f.String()) 
		}
		if len(valueBytes) > 0 {
			v.UnmarshalText(valueBytes)
		}
	}
	fmt.Println(pointer.(*gtime.Time).Location()) // Local
}

第一次执行数据绑定时,嵌套结构体中时间字段尚且是空的,所以可以绑定成功。当递归到第二次的时候,嵌套结构体有了默认值,在执行 bindVarToReflectValueWithInterfaceCheck 时,触发了 gtime 的 UnmarshalText 方法,使时间细节丢失。

这里面的逻辑有些绕,具体的这段代码在 gconv_struct.go 的 409 行 444 行。

强哥有什么其他的好的修改方法吗?

你好,感谢持续参与框架建设!转换组件这块是框架中比较复杂的组件,我仔细看了下源码,确实可能一些特殊的结构体对象会触发一些常见的接口转换,比较典型的就是time.Time/*time.Time或者gtime.Time/*gtime.Time,针对这些特殊的结构体类型,可以在这里的前面增加特殊的类型判断处理。你可以评估一下,如下图。由于这块确实有点难度,如果无法评估如何改动,你可以补充单例,我来尝试改进。
image

@houseme houseme requested a review from gqcn October 10, 2023 13:04
@oldme-git
Copy link
Member Author

好,我来看一下

@Issues-translate-bot
Copy link

Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿


OK, let me take a look

@gqcn gqcn merged commit 10b67fc into gogf:master Oct 11, 2023
12 checks passed
@oldme-git oldme-git deleted the fix/2980 branch October 11, 2023 14:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants