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) }