Files
chaisql/internal/types/blob.go
2025-09-21 11:28:55 +05:30

151 lines
3.0 KiB
Go

package types
import (
"bytes"
"encoding/base64"
"encoding/hex"
"github.com/chaisql/chai/internal/encoding"
"github.com/cockroachdb/errors"
)
var _ TypeDefinition = ByteaTypeDef{}
type ByteaTypeDef struct{}
func (ByteaTypeDef) Decode(src []byte) (Value, int) {
x, n := encoding.DecodeBytea(src)
return NewByteaValue(x), n
}
func (ByteaTypeDef) IsComparableWith(other Type) bool {
return other == TypeBytea
}
func (ByteaTypeDef) IsIndexComparableWith(other Type) bool {
return other == TypeBytea
}
var _ Value = NewByteaValue(nil)
type ByteaValue []byte
// NewByteaValue returns a SQL BYTEA value.
func NewByteaValue(x []byte) ByteaValue {
return ByteaValue(x)
}
func (v ByteaValue) V() any {
return []byte(v)
}
func (v ByteaValue) Type() Type {
return TypeBytea
}
func (v ByteaValue) TypeDef() TypeDefinition {
return ByteaTypeDef{}
}
func (v ByteaValue) IsZero() (bool, error) {
return v == nil, nil
}
func (v ByteaValue) String() string {
t, _ := v.MarshalText()
return string(t)
}
func (v ByteaValue) MarshalText() ([]byte, error) {
var dst bytes.Buffer
// Use single quotes for SQL bytea hex literal: '\x...'
dst.WriteString("'\\x")
_, _ = hex.NewEncoder(&dst).Write(v)
dst.WriteByte('\'')
return dst.Bytes(), nil
}
func (v ByteaValue) MarshalJSON() ([]byte, error) {
dst := make([]byte, base64.StdEncoding.EncodedLen(len(v))+2)
dst[0] = '"'
dst[len(dst)-1] = '"'
base64.StdEncoding.Encode(dst[1:], v)
return dst, nil
}
func (v ByteaValue) Encode(dst []byte) ([]byte, error) {
return encoding.EncodeBytea(dst, v), nil
}
func (v ByteaValue) EncodeAsKey(dst []byte) ([]byte, error) {
return encoding.EncodeBytea(dst, v), nil
}
func (v ByteaValue) CastAs(target Type) (Value, error) {
switch target {
case TypeBytea:
return v, nil
case TypeText:
return NewTextValue(base64.StdEncoding.EncodeToString([]byte(v))), nil
}
return nil, errors.Errorf("cannot cast %q as %q", v.Type(), target)
}
func (v ByteaValue) EQ(other Value) (bool, error) {
if other.Type() != TypeBytea {
return false, nil
}
return bytes.Equal([]byte(v), AsByteSlice(other)), nil
}
func (v ByteaValue) GT(other Value) (bool, error) {
t := other.Type()
if t != TypeBytea {
return false, nil
}
return bytes.Compare([]byte(v), AsByteSlice(other)) > 0, nil
}
func (v ByteaValue) GTE(other Value) (bool, error) {
t := other.Type()
if t != TypeBytea {
return false, nil
}
return bytes.Compare([]byte(v), AsByteSlice(other)) >= 0, nil
}
func (v ByteaValue) LT(other Value) (bool, error) {
t := other.Type()
if t != TypeBytea {
return false, nil
}
return bytes.Compare([]byte(v), AsByteSlice(other)) < 0, nil
}
func (v ByteaValue) LTE(other Value) (bool, error) {
t := other.Type()
if t != TypeBytea {
return false, nil
}
return bytes.Compare([]byte(v), AsByteSlice(other)) <= 0, nil
}
func (v ByteaValue) Between(a, b Value) (bool, error) {
if a.Type() != TypeBytea || b.Type() != TypeBytea {
return false, nil
}
ok, err := a.LTE(v)
if err != nil || !ok {
return false, err
}
return b.GTE(v)
}