package pgtype
import (
)
const (
microsecondsPerSecond = 1_000_000
microsecondsPerMinute = 60 * microsecondsPerSecond
microsecondsPerHour = 60 * microsecondsPerMinute
microsecondsPerDay = 24 * microsecondsPerHour
microsecondsPerMonth = 30 * microsecondsPerDay
)
type IntervalScanner interface {
ScanInterval(v Interval) error
}
type IntervalValuer interface {
IntervalValue() (Interval, error)
}
type Interval struct {
Microseconds int64
Days int32
Months int32
Valid bool
}
func ( *Interval) ( Interval) error {
* =
return nil
}
func ( Interval) () (Interval, error) {
return , nil
}
func ( *Interval) ( any) error {
if == nil {
* = Interval{}
return nil
}
switch src := .(type) {
case string:
return scanPlanTextAnyToIntervalScanner{}.Scan([]byte(), )
}
return fmt.Errorf("cannot scan %T", )
}
func ( Interval) () (driver.Value, error) {
if !.Valid {
return nil, nil
}
, := IntervalCodec{}.PlanEncode(nil, 0, TextFormatCode, ).Encode(, nil)
if != nil {
return nil,
}
return string(),
}
type IntervalCodec struct{}
func (IntervalCodec) ( int16) bool {
return == TextFormatCode || == BinaryFormatCode
}
func (IntervalCodec) () int16 {
return BinaryFormatCode
}
func (IntervalCodec) ( *Map, uint32, int16, any) EncodePlan {
if , := .(IntervalValuer); ! {
return nil
}
switch {
case BinaryFormatCode:
return encodePlanIntervalCodecBinary{}
case TextFormatCode:
return encodePlanIntervalCodecText{}
}
return nil
}
type encodePlanIntervalCodecBinary struct{}
func (encodePlanIntervalCodecBinary) ( any, []byte) ( []byte, error) {
, := .(IntervalValuer).IntervalValue()
if != nil {
return nil,
}
if !.Valid {
return nil, nil
}
= pgio.AppendInt64(, .Microseconds)
= pgio.AppendInt32(, .Days)
= pgio.AppendInt32(, .Months)
return , nil
}
type encodePlanIntervalCodecText struct{}
func (encodePlanIntervalCodecText) ( any, []byte) ( []byte, error) {
, := .(IntervalValuer).IntervalValue()
if != nil {
return nil,
}
if !.Valid {
return nil, nil
}
if .Months != 0 {
= append(, strconv.FormatInt(int64(.Months), 10)...)
= append(, " mon "...)
}
if .Days != 0 {
= append(, strconv.FormatInt(int64(.Days), 10)...)
= append(, " day "...)
}
:= .Microseconds
if < 0 {
= -
= append(, '-')
}
:= / microsecondsPerHour
:= ( % microsecondsPerHour) / microsecondsPerMinute
:= ( % microsecondsPerMinute) / microsecondsPerSecond
:= fmt.Sprintf("%02d:%02d:%02d", , , )
= append(, ...)
:= % microsecondsPerSecond
if != 0 {
= append(, fmt.Sprintf(".%06d", )...)
}
return , nil
}
func (IntervalCodec) ( *Map, uint32, int16, any) ScanPlan {
switch {
case BinaryFormatCode:
switch .(type) {
case IntervalScanner:
return scanPlanBinaryIntervalToIntervalScanner{}
}
case TextFormatCode:
switch .(type) {
case IntervalScanner:
return scanPlanTextAnyToIntervalScanner{}
}
}
return nil
}
type scanPlanBinaryIntervalToIntervalScanner struct{}
func (scanPlanBinaryIntervalToIntervalScanner) ( []byte, any) error {
:= ().(IntervalScanner)
if == nil {
return .ScanInterval(Interval{})
}
if len() != 16 {
return fmt.Errorf("Received an invalid size for an interval: %d", len())
}
:= int64(binary.BigEndian.Uint64())
:= int32(binary.BigEndian.Uint32([8:]))
:= int32(binary.BigEndian.Uint32([12:]))
return .ScanInterval(Interval{Microseconds: , Days: , Months: , Valid: true})
}
type scanPlanTextAnyToIntervalScanner struct{}
func (scanPlanTextAnyToIntervalScanner) ( []byte, any) error {
:= ().(IntervalScanner)
if == nil {
return .ScanInterval(Interval{})
}
var int64
var int32
var int32
:= strings.Split(string(), " ")
for := 0; < len()-1; += 2 {
, := strconv.ParseInt([], 10, 64)
if != nil {
return fmt.Errorf("bad interval format")
}
switch [+1] {
case "year", "years":
+= int32( * 12)
case "mon", "mons":
+= int32()
case "day", "days":
= int32()
default:
return fmt.Errorf("bad interval format: %q", [+1])
}
}
if len()%2 == 1 {
:= strings.SplitN([len()-1], ":", 3)
if len() != 3 {
return fmt.Errorf("bad interval format")
}
var bool
if [0][0] == '-' {
= true
[0] = [0][1:]
}
, := strconv.ParseInt([0], 10, 64)
if != nil {
return fmt.Errorf("bad interval hour format: %s", [0])
}
, := strconv.ParseInt([1], 10, 64)
if != nil {
return fmt.Errorf("bad interval minute format: %s", [1])
}
, , := strings.Cut([2], ".")
, := strconv.ParseInt(, 10, 64)
if != nil {
return fmt.Errorf("bad interval second format: %s", )
}
var int64
if {
, = strconv.ParseInt(, 10, 64)
if != nil {
return fmt.Errorf("bad interval decimal format: %s", )
}
for := 0; < 6-len(); ++ {
*= 10
}
}
= * microsecondsPerHour
+= * microsecondsPerMinute
+= * microsecondsPerSecond
+=
if {
= -
}
}
return .ScanInterval(Interval{Months: , Days: , Microseconds: , Valid: true})
}
func ( IntervalCodec) ( *Map, uint32, int16, []byte) (driver.Value, error) {
return codecDecodeToTextFormat(, , , , )
}
func ( IntervalCodec) ( *Map, uint32, int16, []byte) (any, error) {
if == nil {
return nil, nil
}
var Interval
:= codecScan(, , , , , &)
if != nil {
return nil,
}
return , nil
}