[英]How to represent PostgreSQL interval in Go
如何在 Go 中表示 PostgreSQL 区间?
我的结构如下所示:
type Product struct {
Id int
Name string
Type int
Price float64
Execution_time ????
}
我数据库上的 execution_time 字段是interval
。
最佳答案我已经遇到是使用bigint
在您的架构,并实现Value
和Scan
上的包装类型time.Duration
。
// Duration lets us convert between a bigint in Postgres and time.Duration
// in Go
type Duration time.Duration
// Value converts Duration to a primitive value ready to written to a database.
func (d Duration) Value() (driver.Value, error) {
return driver.Value(int64(d)), nil
}
// Scan reads a Duration value from database driver type.
func (d *Duration) Scan(raw interface{}) error {
switch v := raw.(type) {
case int64:
*d = Duration(v)
case nil:
*d = Duration(0)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.Duration from: %#v", v)
}
return nil
}
不幸的是,你会牺牲在查询中进行区间运算的能力 - 除非一些聪明的家伙想要发布bigint
=> interval
的类型转换。
如果你确定有符合time.Duration
限制,你只需要秒精度你可以:
... someInterval INTERVAL SECOND(0), ...
将INTERVAL转换为秒: SELECT EXTRACT(EPOCH FROM someInterval) FROM someTable;
使用time.Duration :: Seconds将数据插入到预准备语句中
一种解决方案是将time.Duration
类型包装在包装器类型中,并在其上提供sql.Scanner
和driver.Valuer
的实现。
// PgDuration wraps a time.Duration to provide implementations of
// sql.Scanner and driver.Valuer for reading/writing from/to a DB.
type PgDuration time.Duration
Postgres 在插入INTERVAL
列时提供的格式似乎非常灵活。 接受在持续时间上调用String()
返回的默认格式,因此对于driver.Value
的实现,只需调用它:
// Value converts the PgDuration into a string.
func (d PgDuration) Value() (driver.Value, error) {
return time.Duration(d).String(), nil
}
从 Postgres 检索INTERVAL
值时,它以 Go 不易解析的格式返回它(例如"2 days 05:00:30.000250"
),因此我们需要在sql.Scanner
的实现中进行一些手动解析sql.Scanner
。 就我而言,我只关心支持小时、分钟和秒,所以我实现如下:
// Scan converts the received string in the format hh:mm:ss into a PgDuration.
func (d *PgDuration) Scan(value interface{}) error {
switch v := value.(type) {
case string:
// Convert format of hh:mm:ss into format parseable by time.ParseDuration()
v = strings.Replace(v, ":", "h", 1)
v = strings.Replace(v, ":", "m", 1)
v += "s"
dur, err := time.ParseDuration(v)
if err != nil {
return err
}
*d = PgDuration(dur)
return nil
default:
return fmt.Errorf("cannot sql.Scan() PgDuration from: %#v", v)
}
}
如果您需要支持其他持续时间单位,您可以从类似的方法开始,并适当地处理额外的单位。
此外,如果您碰巧使用 GORM 库来自动迁移表,您还需要提供 GORM 的migrator.GormDataTypeInterface
的实现:
// GormDataType tells GORM to use the INTERVAL data type for a PgDuration column.
func (PgDuration) GormDataType() string {
return "INTERVAL"
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.