mirror of
https://github.com/hanzo-ds/native.git
synced 2026-10-30 20:00:34 +00:00
Module path, package names, and identifiers de-branded to native/proto/compress/ pool/tracing. Server wire-protocol strings preserved. Vendored codec surface used by hanzo-ds/go (proto + compress).
175 lines
3.6 KiB
Go
175 lines
3.6 KiB
Go
package proto
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/go-faster/errors"
|
|
)
|
|
|
|
var (
|
|
_ Column = (*ColEnum)(nil)
|
|
_ ColumnOf[string] = (*ColEnum)(nil)
|
|
_ Inferable = (*ColEnum)(nil)
|
|
_ Preparable = (*ColEnum)(nil)
|
|
)
|
|
|
|
// ColEnum is inference helper for enums.
|
|
//
|
|
// You can set Values and actual enum mapping will be inferred during query
|
|
// execution.
|
|
type ColEnum struct {
|
|
t ColumnType
|
|
base ColumnType
|
|
|
|
rawToStr map[int]string
|
|
strToRaw map[string]int
|
|
raw8 ColEnum8
|
|
raw16 ColEnum16
|
|
|
|
// Values of ColEnum.
|
|
Values []string
|
|
}
|
|
|
|
func (e *ColEnum) raw() Column {
|
|
if e.t.Base() == ColumnTypeEnum8 {
|
|
return &e.raw8
|
|
}
|
|
return &e.raw16
|
|
}
|
|
|
|
func (e ColEnum) Row(i int) string {
|
|
return e.Values[i]
|
|
}
|
|
|
|
// Append value to Enum8 column.
|
|
func (e *ColEnum) Append(v string) {
|
|
e.Values = append(e.Values, v)
|
|
}
|
|
|
|
func (e *ColEnum) AppendArr(vs []string) {
|
|
e.Values = append(e.Values, vs...)
|
|
}
|
|
|
|
func (e *ColEnum) parse(t ColumnType) error {
|
|
if e.rawToStr == nil {
|
|
e.rawToStr = map[int]string{}
|
|
}
|
|
if e.strToRaw == nil {
|
|
e.strToRaw = map[string]int{}
|
|
}
|
|
|
|
elements := t.Elem().String()
|
|
for _, elem := range strings.Split(elements, ",") {
|
|
def := strings.TrimSpace(elem)
|
|
// 'hello' = 1
|
|
left, right, hascomma := strings.Cut(def, "=")
|
|
if !hascomma {
|
|
return errors.Errorf("bad enum definition %q", def)
|
|
}
|
|
left = strings.TrimSpace(left) // 'hello'
|
|
right = strings.TrimSpace(right) // 1
|
|
idx, err := strconv.Atoi(right)
|
|
if err != nil {
|
|
return errors.Errorf("bad right side of definition %q", right)
|
|
}
|
|
left = strings.TrimFunc(left, func(c rune) bool {
|
|
return c == '\''
|
|
})
|
|
e.strToRaw[left] = idx
|
|
e.rawToStr[idx] = left
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (e *ColEnum) Infer(t ColumnType) error {
|
|
if !strings.HasPrefix(t.Base().String(), "Enum") {
|
|
return errors.Errorf("invalid base %q to infer enum", t.Base())
|
|
}
|
|
if err := e.parse(t); err != nil {
|
|
return errors.Wrap(err, "parse type")
|
|
}
|
|
base := t.Base()
|
|
switch base {
|
|
case ColumnTypeEnum8, ColumnTypeEnum16:
|
|
e.base = base
|
|
default:
|
|
return errors.Errorf("invalid base %q", base)
|
|
}
|
|
e.t = t
|
|
return nil
|
|
}
|
|
|
|
func (e *ColEnum) Rows() int {
|
|
return len(e.Values)
|
|
}
|
|
|
|
func appendEnum[E Enum8 | Enum16](c []E, mapping map[int]string, values []string) ([]string, error) {
|
|
for _, v := range c {
|
|
s, ok := mapping[int(v)]
|
|
if !ok {
|
|
return nil, errors.Errorf("unknown enum value %d", v)
|
|
}
|
|
values = append(values, s)
|
|
}
|
|
return values, nil
|
|
}
|
|
|
|
func (e *ColEnum) DecodeColumn(r *Reader, rows int) error {
|
|
if err := e.raw().DecodeColumn(r, rows); err != nil {
|
|
return errors.Wrap(err, "raw")
|
|
}
|
|
var (
|
|
err error
|
|
v []string
|
|
)
|
|
switch e.base {
|
|
case ColumnTypeEnum8:
|
|
v, err = appendEnum[Enum8](e.raw8, e.rawToStr, e.Values[:0])
|
|
case ColumnTypeEnum16:
|
|
v, err = appendEnum[Enum16](e.raw16, e.rawToStr, e.Values[:0])
|
|
default:
|
|
return errors.Errorf("invalid enum base %q", e.base)
|
|
}
|
|
if err != nil {
|
|
return errors.Wrap(err, "map values")
|
|
}
|
|
e.Values = v
|
|
return nil
|
|
}
|
|
|
|
func (e *ColEnum) Reset() {
|
|
e.raw().Reset()
|
|
e.Values = e.Values[:0]
|
|
}
|
|
|
|
func (e *ColEnum) Prepare() error {
|
|
e.raw8 = e.raw8[:0]
|
|
e.raw16 = e.raw16[:0]
|
|
for _, v := range e.Values {
|
|
raw, ok := e.strToRaw[v]
|
|
if !ok {
|
|
return errors.Errorf("unknown enum value %q", v)
|
|
}
|
|
switch e.base {
|
|
case ColumnTypeEnum8:
|
|
e.raw8.Append(Enum8(raw))
|
|
case ColumnTypeEnum16:
|
|
e.raw16.Append(Enum16(raw))
|
|
default:
|
|
return errors.Errorf("invalid base %q", e.base)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (e *ColEnum) EncodeColumn(b *Buffer) {
|
|
e.raw().EncodeColumn(b)
|
|
}
|
|
|
|
func (e *ColEnum) WriteColumn(w *Writer) {
|
|
e.raw().WriteColumn(w)
|
|
}
|
|
|
|
func (e *ColEnum) Type() ColumnType { return e.t }
|