WIP: 增加自定义类型实现FromDB,ToDB方法,使用指针类型添加/更新时使用空更新,不使用默认值 #1541

Closed
venjiang wants to merge 4 commits from master into master
First-time contributor

一般我们使用指针类型定义数据库对应可空字段,此PR实现自定义类型(实现Conversion接口),使用指针类型插入更新数据时使用<空>更新数据存储值,非指针类型更新保持0值初始化同原始设计

一般我们使用指针类型定义数据库对应可空字段,此PR实现自定义类型(实现Conversion接口),使用指针类型插入更新数据时使用<空>更新数据存储值,非指针类型更新保持0值初始化同原始设计
Owner

Could you add some tests?

Could you add some tests?
Author
First-time contributor

比方说我自己实现个Time,

// Time 自定义时间
type Time time.Time

func (t Time) String() string {
	return t.Origin().Format(time.RFC3339Nano)
}

func (t Time) MarshalJSON() ([]byte, error) {
	ot := time.Time(t)
	return json.Marshal(ot)
}

func (t *Time) UnmarshalJSON(b []byte) error {
	var err error
	var ot time.Time
	var value string
	if err = json.Unmarshal(b, &value); err != nil {
		return err
	}
	for _, layout := range TimeFormats {
		ot, err = time.ParseInLocation(layout, value, time.Local)
		if err == nil {
			break
		}
	}
	*t = Time(ot)
	return err
}

// Origin 原始类型值
func (t *Time) Origin() *time.Time {
	if t != nil {
		ot := time.Time(*t)
		return &ot
	}
	return nil
}

// TimeFrom 根据time.Time类型构建model.Time类型对象
func TimeFrom(t time.Time) Time {
	return Time(t)
}

func (t *Time) FromDB(b []byte) error {
	var err error
	var ot time.Time
	var value string
	value = string(b)
	if len(b) > 0 {
		for _, layout := range TimeFormats {
			ot, err = time.ParseInLocation(layout, value, time.Local)
			if err == nil {
				break
			}
		}
		*t = Time(ot)
		return err
	}
	return nil
}
func (t *Time) ToDB() ([]byte, error) {
	if t == nil {
		log.Println("[Time.ToDB] is nil")
		return nil, nil
	}
	str := t.String()
	if str == "" {
		return nil, nil
	}
	return []byte(str), nil
}

模型类定义

type TestModel struct {
	ID           string  `xorm:"varchar(20) pk unique 'id'" json:"id"`
	Username     string  `xorm:"varchar(100) notnull" json:"username"`
	Nickname     *string `xorm:"varchar(50) null" json:"nickname"`
	Like         JSON    `xorm:"jsonb default('{}')" json:"like"`
	TJson        *JSON   `xorm:"json default('{}')" json:"t_json"`
	StartTime    Time    `xorm:"timestampz notnull" json:"start_time"`
	EndTime      *Time   `xorm:"timestampz null" json:"end_time"`

指针类型对应数据可为空的字段,先前的逻辑,如果是指针类型会在数据库中插入空字符串,而我希望是null,PR就是解决这问题
上面的例子还有个特殊的问题,我的Time是time.Time的别名类型,如果按先前逻辑,空指针(EndTime)会在数据库是插入空字符串,而空字符串不是有效的timestamptz类型,会造成插入更新失败

比方说我自己实现个Time, ``` go // Time 自定义时间 type Time time.Time func (t Time) String() string { return t.Origin().Format(time.RFC3339Nano) } func (t Time) MarshalJSON() ([]byte, error) { ot := time.Time(t) return json.Marshal(ot) } func (t *Time) UnmarshalJSON(b []byte) error { var err error var ot time.Time var value string if err = json.Unmarshal(b, &value); err != nil { return err } for _, layout := range TimeFormats { ot, err = time.ParseInLocation(layout, value, time.Local) if err == nil { break } } *t = Time(ot) return err } // Origin 原始类型值 func (t *Time) Origin() *time.Time { if t != nil { ot := time.Time(*t) return &ot } return nil } // TimeFrom 根据time.Time类型构建model.Time类型对象 func TimeFrom(t time.Time) Time { return Time(t) } func (t *Time) FromDB(b []byte) error { var err error var ot time.Time var value string value = string(b) if len(b) > 0 { for _, layout := range TimeFormats { ot, err = time.ParseInLocation(layout, value, time.Local) if err == nil { break } } *t = Time(ot) return err } return nil } func (t *Time) ToDB() ([]byte, error) { if t == nil { log.Println("[Time.ToDB] is nil") return nil, nil } str := t.String() if str == "" { return nil, nil } return []byte(str), nil } ``` 模型类定义 ``` go type TestModel struct { ID string `xorm:"varchar(20) pk unique 'id'" json:"id"` Username string `xorm:"varchar(100) notnull" json:"username"` Nickname *string `xorm:"varchar(50) null" json:"nickname"` Like JSON `xorm:"jsonb default('{}')" json:"like"` TJson *JSON `xorm:"json default('{}')" json:"t_json"` StartTime Time `xorm:"timestampz notnull" json:"start_time"` EndTime *Time `xorm:"timestampz null" json:"end_time"` ``` 指针类型对应数据可为空的字段,先前的逻辑,如果是指针类型会在数据库中插入空字符串,而我希望是null,PR就是解决这问题 上面的例子还有个特殊的问题,我的Time是time.Time的别名类型,如果按先前逻辑,空指针(EndTime)会在数据库是插入空字符串,而空字符串不是有效的timestamptz类型,会造成插入更新失败
Owner

I know that. Please add your tests on some test file, maybe time_test.go. Once the CI pass, I could merge it.

I know that. Please add your tests on some test file, maybe `time_test.go`. Once the CI pass, I could merge it.
Author
First-time contributor

I know that. Please add your tests on some test file, maybe time_test.go. Once the CI pass, I could merge it.

Yeah, I've added tests.

> I know that. Please add your tests on some test file, maybe `time_test.go`. Once the CI pass, I could merge it. Yeah, I've added tests.
Owner

@venjiang CI failed.

@venjiang CI failed.
venjiang closed this pull request 2020-04-01 01:17:04 +00:00
Some checks failed
continuous-integration/drone/pr Build is failing

Pull request closed

Sign in to join this conversation.
No description provided.