feat(types):增加日期时间的范围区间类型。
This commit is contained in:
parent
2d6bff5828
commit
2c303cfba7
|
@ -153,6 +153,15 @@ func (d Date) IsEmpty() bool {
|
|||
return d.Time.IsZero()
|
||||
}
|
||||
|
||||
func (d *Date) Parse(s string) error {
|
||||
t, err := ParseDate(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Time = t.Time
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d Date) ToString() string {
|
||||
return d.Time.Format("2006-01-02")
|
||||
}
|
||||
|
|
80
types/daterange.go
Normal file
80
types/daterange.go
Normal file
|
@ -0,0 +1,80 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"electricity_bill_calc/tools"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
type DateRange struct {
|
||||
pgtype.Range[Date]
|
||||
}
|
||||
|
||||
func NewDateRange(lower *Date, upper *Date) DateRange {
|
||||
return DateRange{
|
||||
Range: pgtype.Range[Date]{
|
||||
LowerType: tools.Cond(lower != nil, pgtype.Inclusive, pgtype.Unbounded),
|
||||
Lower: tools.DefaultTo(lower, MinDate()),
|
||||
UpperType: tools.Cond(upper != nil, pgtype.Inclusive, pgtype.Unbounded),
|
||||
Upper: tools.DefaultTo(upper, MaxDate()),
|
||||
Valid: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
var _ driver.Valuer = (*DateRange)(nil)
|
||||
|
||||
func (dr DateRange) Value() (driver.Value, error) {
|
||||
return assembleRange(dr.Range), nil
|
||||
}
|
||||
|
||||
var _ sql.Scanner = (*DateRange)(nil)
|
||||
|
||||
func (dr *DateRange) Scan(src interface{}) (err error) {
|
||||
switch src := src.(type) {
|
||||
case pgtype.Range[Date]:
|
||||
dr.Range = src
|
||||
case string:
|
||||
r, err := destructureToRange[Date](src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dr.Range = r
|
||||
case []byte:
|
||||
r, err := destructureToRange[Date](string(src))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dr.Range = r
|
||||
case nil:
|
||||
dr = nil
|
||||
default:
|
||||
return errors.New("该数据类型不支持解析到日期范围。")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var _ json.Marshaler = (*DateRange)(nil)
|
||||
|
||||
func (dr DateRange) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(assembleRange(dr.Range))
|
||||
}
|
||||
|
||||
var _ json.Unmarshaler = (*DateRange)(nil)
|
||||
|
||||
func (dr *DateRange) UnmarshalJSON(data []byte) error {
|
||||
var str string
|
||||
if err := json.Unmarshal(data, &str); err != nil {
|
||||
return errors.New("不能解析指定的日期范围值。")
|
||||
}
|
||||
r, err := destructureToRange[Date](str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dr.Range = r
|
||||
return nil
|
||||
}
|
|
@ -34,6 +34,18 @@ func NewEmptyDateTime() DateTime {
|
|||
}
|
||||
}
|
||||
|
||||
func MinDateTime() DateTime {
|
||||
return DateTime{
|
||||
Time: time.Date(1, 1, 1, 0, 0, 0, 0, loc),
|
||||
}
|
||||
}
|
||||
|
||||
func MaxDateTime() DateTime {
|
||||
return DateTime{
|
||||
Time: time.Date(9999, 12, 31, 23, 59, 59, 999999, loc),
|
||||
}
|
||||
}
|
||||
|
||||
func Timestamp() int64 {
|
||||
startline := time.Date(2022, 2, 22, 22, 22, 22, 0, loc).Unix()
|
||||
return Now().Unix() - startline
|
||||
|
@ -159,6 +171,15 @@ func (dt DateTime) IsEmpty() bool {
|
|||
return dt.Time.IsZero()
|
||||
}
|
||||
|
||||
func (dt *DateTime) Parse(s string) error {
|
||||
t, err := ParseDateTime(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dt.Time = t.Time
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dt DateTime) ToString() string {
|
||||
return dt.Time.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
|
80
types/datetimerange.go
Normal file
80
types/datetimerange.go
Normal file
|
@ -0,0 +1,80 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"electricity_bill_calc/tools"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
type DateTimeRange struct {
|
||||
pgtype.Range[DateTime]
|
||||
}
|
||||
|
||||
func NewDateTimeRange(lower *DateTime, upper *DateTime) DateTimeRange {
|
||||
return DateTimeRange{
|
||||
Range: pgtype.Range[DateTime]{
|
||||
LowerType: tools.Cond(lower != nil, pgtype.Inclusive, pgtype.Unbounded),
|
||||
Lower: tools.DefaultTo(lower, MinDateTime()),
|
||||
UpperType: tools.Cond(upper != nil, pgtype.Inclusive, pgtype.Unbounded),
|
||||
Upper: tools.DefaultTo(upper, MaxDateTime()),
|
||||
Valid: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
var _ driver.Value = (*DateTimeRange)(nil)
|
||||
|
||||
func (dr DateTimeRange) Value() (driver.Value, error) {
|
||||
return assembleRange(dr.Range), nil
|
||||
}
|
||||
|
||||
var _ sql.Scanner = (*DateTimeRange)(nil)
|
||||
|
||||
func (dr *DateTimeRange) Scan(src interface{}) (err error) {
|
||||
switch src := src.(type) {
|
||||
case pgtype.Range[DateTime]:
|
||||
dr.Range = src
|
||||
case string:
|
||||
r, err := destructureToRange[DateTime](src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dr.Range = r
|
||||
case []byte:
|
||||
r, err := destructureToRange[DateTime](string(src))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dr.Range = r
|
||||
case nil:
|
||||
dr = nil
|
||||
default:
|
||||
return errors.New("该数据类型不支持解析到日期范围。")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var _ json.Marshaler = (*DateTimeRange)(nil)
|
||||
|
||||
func (dr DateTimeRange) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(assembleRange(dr.Range))
|
||||
}
|
||||
|
||||
var _ json.Unmarshaler = (*DateTimeRange)(nil)
|
||||
|
||||
func (dr *DateTimeRange) UnmarshalJSON(data []byte) error {
|
||||
var str string
|
||||
if err := json.Unmarshal(data, &str); err != nil {
|
||||
return errors.New("不能解析指定的日期范围值。")
|
||||
}
|
||||
r, err := destructureToRange[DateTime](str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dr.Range = r
|
||||
return nil
|
||||
}
|
115
types/range.go
Normal file
115
types/range.go
Normal file
|
@ -0,0 +1,115 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
type Parse interface {
|
||||
Parse(string) error
|
||||
}
|
||||
|
||||
type ToString interface {
|
||||
ToString() string
|
||||
}
|
||||
|
||||
// 将一个字符串拆解解析为一个 Postgresql 范围类型的值。
|
||||
func destructureToRange[T any, PT interface {
|
||||
Parse
|
||||
*T
|
||||
}](s string) (pgtype.Range[T], error) {
|
||||
var r pgtype.Range[T]
|
||||
r.Valid = false
|
||||
if len(s) == 0 {
|
||||
r.LowerType = pgtype.Empty
|
||||
r.UpperType = pgtype.Empty
|
||||
return r, nil
|
||||
}
|
||||
rangeUnit := strings.Split(s, ",")
|
||||
if len(rangeUnit) != 2 {
|
||||
return r, errors.New("无法解析给定的范围值,格式不正确。")
|
||||
}
|
||||
if unit, found := strings.CutPrefix(rangeUnit[0], "["); found {
|
||||
var t PT
|
||||
if len(unit) > 0 {
|
||||
r.LowerType = pgtype.Inclusive
|
||||
err := t.Parse(unit)
|
||||
if err != nil {
|
||||
return r, errors.New("无法解析给定的最低范围值。")
|
||||
}
|
||||
} else {
|
||||
r.LowerType = pgtype.Unbounded
|
||||
}
|
||||
r.Lower = *t
|
||||
}
|
||||
if unit, found := strings.CutPrefix(rangeUnit[0], "("); found {
|
||||
var t PT
|
||||
if len(unit) > 0 {
|
||||
r.LowerType = pgtype.Exclusive
|
||||
err := t.Parse(unit)
|
||||
if err != nil {
|
||||
return r, errors.New("无法解析给定的最低范围值。")
|
||||
}
|
||||
} else {
|
||||
r.LowerType = pgtype.Unbounded
|
||||
}
|
||||
r.Lower = *t
|
||||
}
|
||||
|
||||
if unit, found := strings.CutSuffix(rangeUnit[1], "]"); found {
|
||||
var t PT
|
||||
if len(unit) > 0 {
|
||||
r.UpperType = pgtype.Inclusive
|
||||
err := t.Parse(unit)
|
||||
if err != nil {
|
||||
return r, errors.New("无法解析给定的最高范围值。")
|
||||
}
|
||||
} else {
|
||||
r.UpperType = pgtype.Unbounded
|
||||
}
|
||||
r.Upper = *t
|
||||
}
|
||||
if unit, found := strings.CutSuffix(rangeUnit[1], ")"); found {
|
||||
var t PT
|
||||
if len(unit) > 0 {
|
||||
r.UpperType = pgtype.Exclusive
|
||||
err := t.Parse(unit)
|
||||
if err != nil {
|
||||
return r, errors.New("无法解析给定的最高范围值。")
|
||||
}
|
||||
} else {
|
||||
r.UpperType = pgtype.Unbounded
|
||||
}
|
||||
r.Upper = *t
|
||||
}
|
||||
r.Valid = true
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// 将一个范围类型的值转换为一个字符串、
|
||||
func assembleRange[T ToString](r pgtype.Range[T]) string {
|
||||
var sb strings.Builder
|
||||
if r.LowerType == pgtype.Empty || r.UpperType == pgtype.Empty {
|
||||
return "empty"
|
||||
}
|
||||
if r.LowerType == pgtype.Inclusive {
|
||||
sb.WriteString("[")
|
||||
} else {
|
||||
sb.WriteString("(")
|
||||
}
|
||||
if r.LowerType != pgtype.Unbounded {
|
||||
sb.WriteString(r.Lower.ToString())
|
||||
}
|
||||
sb.WriteString(",")
|
||||
if r.UpperType != pgtype.Unbounded {
|
||||
sb.WriteString(r.Upper.ToString())
|
||||
}
|
||||
if r.UpperType == pgtype.Inclusive {
|
||||
sb.WriteString("]")
|
||||
} else {
|
||||
sb.WriteString(")")
|
||||
}
|
||||
return sb.String()
|
||||
}
|
Loading…
Reference in New Issue
Block a user