Skip to content

Commit

Permalink
feat(proto): support Bool type
Browse files Browse the repository at this point in the history
  • Loading branch information
ernado committed Dec 17, 2021
1 parent 9fba5c6 commit e56e9c6
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ func main() {
* Enum8, Enum16
* LowCardinality(T)
* Map(K, V)
* Bool

## TODO
- [ ] Nullable
Expand Down
4 changes: 4 additions & 0 deletions proto/_golden/col_bool.hex
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
00000000 01 00 00 01 00 00 01 00 00 01 00 00 01 00 00 01 |................|
00000010 00 00 01 00 00 01 00 00 01 00 00 01 00 00 01 00 |................|
00000020 00 01 00 00 01 00 00 01 00 00 01 00 00 01 00 00 |................|
00000030 01 00 |..|
Binary file added proto/_golden/col_bool.raw
Binary file not shown.
63 changes: 63 additions & 0 deletions proto/col_bool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package proto

import "github.com/go-faster/errors"

// ColBool is Bool column.
type ColBool []bool

// Compile-time assertions for ColBool.
var (
_ Input = ColBool{}
_ Result = (*ColBool)(nil)
_ Column = (*ColBool)(nil)
)

// Type returns ColumnType of Int8.
func (ColBool) Type() ColumnType {
return ColumnTypeBool
}

// Rows returns count of rows in column.
func (c ColBool) Rows() int {
return len(c)
}

// Reset resets data in row, preserving capacity for efficiency.
func (c *ColBool) Reset() {
*c = (*c)[:0]
}

// EncodeColumn encodes Int8 rows to *Buffer.
func (c ColBool) EncodeColumn(b *Buffer) {
start := len(b.Buf)
b.Buf = append(b.Buf, make([]byte, len(c))...)
for i := range c {
if c[i] {
b.Buf[i+start] = boolTrue
} else {
b.Buf[i+start] = boolFalse
}
}
}

// DecodeColumn decodes Int8 rows from *Reader.
func (c *ColBool) DecodeColumn(r *Reader, rows int) error {
data, err := r.ReadRaw(rows)
if err != nil {
return errors.Wrap(err, "read")
}
v := *c
v = append(v, make([]bool, rows)...)
for i := range data {
switch data[i] {
case boolTrue:
v[i] = true
case boolFalse:
v[i] = false
default:
return errors.Errorf("[%d]: bad value %d for Bool", i, data[i])
}
}
*c = v
return nil
}
99 changes: 99 additions & 0 deletions proto/col_bool_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package proto

import (
"bytes"
"io"
"testing"

"github.com/stretchr/testify/require"

"github.com/go-faster/ch/internal/gold"
)

func TestColBool_DecodeColumn(t *testing.T) {
const rows = 50
var data ColBool
for i := 0; i < rows; i++ {
data = append(data, (i%3) == 0)
}

var buf Buffer
data.EncodeColumn(&buf)
t.Run("Golden", func(t *testing.T) {
gold.Bytes(t, buf.Buf, "col_bool")
})
t.Run("Ok", func(t *testing.T) {
br := bytes.NewReader(buf.Buf)
r := NewReader(br)

var dec ColBool
require.NoError(t, dec.DecodeColumn(r, rows))
require.Equal(t, data, dec)
require.Equal(t, rows, dec.Rows())
dec.Reset()
require.Equal(t, 0, dec.Rows())
require.Equal(t, ColumnTypeBool, dec.Type())
})
t.Run("ErrUnexpectedEOF", func(t *testing.T) {
r := NewReader(bytes.NewReader(nil))

var dec ColBool
require.ErrorIs(t, dec.DecodeColumn(r, rows), io.ErrUnexpectedEOF)
})
t.Run("NoShortRead", func(t *testing.T) {
var dec ColBool
requireNoShortRead(t, buf.Buf, colAware(&dec, rows))
})
}

func BenchmarkColBool_DecodeColumn(b *testing.B) {
const rows = 50_000
var data ColBool
for i := 0; i < rows; i++ {
data = append(data, (i%3) == 0)
}

var buf Buffer
data.EncodeColumn(&buf)

br := bytes.NewReader(buf.Buf)
r := NewReader(br)

var dec ColBool
if err := dec.DecodeColumn(r, rows); err != nil {
b.Fatal(err)
}
b.SetBytes(int64(len(buf.Buf)))
b.ResetTimer()
b.ReportAllocs()

for i := 0; i < b.N; i++ {
br.Reset(buf.Buf)
r.raw.Reset(br)
dec.Reset()

if err := dec.DecodeColumn(r, rows); err != nil {
b.Fatal(err)
}
}
}

func BenchmarkColBool_EncodeColumn(b *testing.B) {
const rows = 50_000
var data ColBool
for i := 0; i < rows; i++ {
data = append(data, (i%3) == 0)
}

var buf Buffer
data.EncodeColumn(&buf)

b.SetBytes(int64(len(buf.Buf)))
b.ResetTimer()
b.ReportAllocs()

for i := 0; i < b.N; i++ {
buf.Reset()
data.EncodeColumn(&buf)
}
}
1 change: 1 addition & 0 deletions proto/column.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ const (
ColumnTypeEnum16 ColumnType = "Enum16"
ColumnTypeLowCardinality ColumnType = "LowCardinality"
ColumnTypeMap ColumnType = "Map"
ColumnTypeBool ColumnType = "Bool"
)

// colWrap wraps Column with type t.
Expand Down

0 comments on commit e56e9c6

Please sign in to comment.