monzero/vendor/github.com/jackc/pgx/v5/pgtype/range.go
Gibheer 6ea4d2c82d switch from github.com/lib/pq to github.com/jackc/pgx/v5
lib/pq is out of maintenance for some time now, so switch to the newer
more active library. Looks like it finally stabilized after a long time.
2024-09-05 19:38:25 +02:00

323 lines
6.1 KiB
Go

package pgtype
import (
"bytes"
"encoding/binary"
"fmt"
)
type BoundType byte
const (
Inclusive = BoundType('i')
Exclusive = BoundType('e')
Unbounded = BoundType('U')
Empty = BoundType('E')
)
func (bt BoundType) String() string {
return string(bt)
}
type untypedTextRange struct {
Lower string
Upper string
LowerType BoundType
UpperType BoundType
}
func parseUntypedTextRange(src string) (*untypedTextRange, error) {
utr := &untypedTextRange{}
if src == "empty" {
utr.LowerType = Empty
utr.UpperType = Empty
return utr, nil
}
buf := bytes.NewBufferString(src)
skipWhitespace(buf)
r, _, err := buf.ReadRune()
if err != nil {
return nil, fmt.Errorf("invalid lower bound: %w", err)
}
switch r {
case '(':
utr.LowerType = Exclusive
case '[':
utr.LowerType = Inclusive
default:
return nil, fmt.Errorf("missing lower bound, instead got: %v", string(r))
}
r, _, err = buf.ReadRune()
if err != nil {
return nil, fmt.Errorf("invalid lower value: %w", err)
}
buf.UnreadRune()
if r == ',' {
utr.LowerType = Unbounded
} else {
utr.Lower, err = rangeParseValue(buf)
if err != nil {
return nil, fmt.Errorf("invalid lower value: %w", err)
}
}
r, _, err = buf.ReadRune()
if err != nil {
return nil, fmt.Errorf("missing range separator: %w", err)
}
if r != ',' {
return nil, fmt.Errorf("missing range separator: %v", r)
}
r, _, err = buf.ReadRune()
if err != nil {
return nil, fmt.Errorf("invalid upper value: %w", err)
}
if r == ')' || r == ']' {
utr.UpperType = Unbounded
} else {
buf.UnreadRune()
utr.Upper, err = rangeParseValue(buf)
if err != nil {
return nil, fmt.Errorf("invalid upper value: %w", err)
}
r, _, err = buf.ReadRune()
if err != nil {
return nil, fmt.Errorf("missing upper bound: %w", err)
}
switch r {
case ')':
utr.UpperType = Exclusive
case ']':
utr.UpperType = Inclusive
default:
return nil, fmt.Errorf("missing upper bound, instead got: %v", string(r))
}
}
skipWhitespace(buf)
if buf.Len() > 0 {
return nil, fmt.Errorf("unexpected trailing data: %v", buf.String())
}
return utr, nil
}
func rangeParseValue(buf *bytes.Buffer) (string, error) {
r, _, err := buf.ReadRune()
if err != nil {
return "", err
}
if r == '"' {
return rangeParseQuotedValue(buf)
}
buf.UnreadRune()
s := &bytes.Buffer{}
for {
r, _, err := buf.ReadRune()
if err != nil {
return "", err
}
switch r {
case '\\':
r, _, err = buf.ReadRune()
if err != nil {
return "", err
}
case ',', '[', ']', '(', ')':
buf.UnreadRune()
return s.String(), nil
}
s.WriteRune(r)
}
}
func rangeParseQuotedValue(buf *bytes.Buffer) (string, error) {
s := &bytes.Buffer{}
for {
r, _, err := buf.ReadRune()
if err != nil {
return "", err
}
switch r {
case '\\':
r, _, err = buf.ReadRune()
if err != nil {
return "", err
}
case '"':
r, _, err = buf.ReadRune()
if err != nil {
return "", err
}
if r != '"' {
buf.UnreadRune()
return s.String(), nil
}
}
s.WriteRune(r)
}
}
type untypedBinaryRange struct {
Lower []byte
Upper []byte
LowerType BoundType
UpperType BoundType
}
// 0 = () = 00000
// 1 = empty = 00001
// 2 = [) = 00010
// 4 = (] = 00100
// 6 = [] = 00110
// 8 = ) = 01000
// 12 = ] = 01100
// 16 = ( = 10000
// 18 = [ = 10010
// 24 = = 11000
const emptyMask = 1
const lowerInclusiveMask = 2
const upperInclusiveMask = 4
const lowerUnboundedMask = 8
const upperUnboundedMask = 16
func parseUntypedBinaryRange(src []byte) (*untypedBinaryRange, error) {
ubr := &untypedBinaryRange{}
if len(src) == 0 {
return nil, fmt.Errorf("range too short: %v", len(src))
}
rangeType := src[0]
rp := 1
if rangeType&emptyMask > 0 {
if len(src[rp:]) > 0 {
return nil, fmt.Errorf("unexpected trailing bytes parsing empty range: %v", len(src[rp:]))
}
ubr.LowerType = Empty
ubr.UpperType = Empty
return ubr, nil
}
if rangeType&lowerInclusiveMask > 0 {
ubr.LowerType = Inclusive
} else if rangeType&lowerUnboundedMask > 0 {
ubr.LowerType = Unbounded
} else {
ubr.LowerType = Exclusive
}
if rangeType&upperInclusiveMask > 0 {
ubr.UpperType = Inclusive
} else if rangeType&upperUnboundedMask > 0 {
ubr.UpperType = Unbounded
} else {
ubr.UpperType = Exclusive
}
if ubr.LowerType == Unbounded && ubr.UpperType == Unbounded {
if len(src[rp:]) > 0 {
return nil, fmt.Errorf("unexpected trailing bytes parsing unbounded range: %v", len(src[rp:]))
}
return ubr, nil
}
if len(src[rp:]) < 4 {
return nil, fmt.Errorf("too few bytes for size: %v", src[rp:])
}
valueLen := int(binary.BigEndian.Uint32(src[rp:]))
rp += 4
val := src[rp : rp+valueLen]
rp += valueLen
if ubr.LowerType != Unbounded {
ubr.Lower = val
} else {
ubr.Upper = val
if len(src[rp:]) > 0 {
return nil, fmt.Errorf("unexpected trailing bytes parsing range: %v", len(src[rp:]))
}
return ubr, nil
}
if ubr.UpperType != Unbounded {
if len(src[rp:]) < 4 {
return nil, fmt.Errorf("too few bytes for size: %v", src[rp:])
}
valueLen := int(binary.BigEndian.Uint32(src[rp:]))
rp += 4
ubr.Upper = src[rp : rp+valueLen]
rp += valueLen
}
if len(src[rp:]) > 0 {
return nil, fmt.Errorf("unexpected trailing bytes parsing range: %v", len(src[rp:]))
}
return ubr, nil
}
// Range is a generic range type.
type Range[T any] struct {
Lower T
Upper T
LowerType BoundType
UpperType BoundType
Valid bool
}
func (r Range[T]) IsNull() bool {
return !r.Valid
}
func (r Range[T]) BoundTypes() (lower, upper BoundType) {
return r.LowerType, r.UpperType
}
func (r Range[T]) Bounds() (lower, upper any) {
return &r.Lower, &r.Upper
}
func (r *Range[T]) ScanNull() error {
*r = Range[T]{}
return nil
}
func (r *Range[T]) ScanBounds() (lowerTarget, upperTarget any) {
return &r.Lower, &r.Upper
}
func (r *Range[T]) SetBoundTypes(lower, upper BoundType) error {
if lower == Unbounded || lower == Empty {
var zero T
r.Lower = zero
}
if upper == Unbounded || upper == Empty {
var zero T
r.Upper = zero
}
r.LowerType = lower
r.UpperType = upper
r.Valid = true
return nil
}