Test FieldBuffer

This commit is contained in:
Asdine El Hrychy
2019-08-29 19:13:30 +01:00
parent a3d23f0d7d
commit afbb55a2af
5 changed files with 191 additions and 72 deletions

11
doc.go
View File

@@ -4,7 +4,7 @@ Genji supports various engines that write data on-disk, like BoltDB or Badger, a
It provides a complete framework with multiple APIs that can be used to manipulate, manage, read and write data.
Genji tables are schemaless and can be manipulated using the table package, which is a low-level functional API
Genji tables are schemaless and can be manipulated using the table package, which is a low-level streaming API
or by using the query package which is a powerful SQL like query engine.
Tables can be mapped to Go structures without reflection: Genji relies on code generation to translate data to and from Go structures.
@@ -49,8 +49,7 @@ Field, Record, and Table
Genji defines its own semantic to describe data.
Data stored in Genji being schemaless, the usual SQL triplet "column", "row", "table" wasn't chosen
for the vocabulary of this library. Also, Genji is a database written in Go for Go, and its primary goal
is to map structures and maps to tables, though it's not limited to that. The semantics were to be as close as possible
to what people are used to in this language.
is to map structures and maps to tables, though it's not limited to that.
That's why the triplet "field", "record" and "table" was chosen.
@@ -116,10 +115,8 @@ The genji command line can be used as follows to generate the code:
This will generate a file named user.genji.go containing the following types and methods
// user.genji.go
// The User type gets new methods that implement some Genji interfaces.
func (u *User) Field(name string) (field.Field, error) {}
func (u *User) GetField(name string) (field.Field, error) {}
func (u *User) Iterate(fn func(field.Field) error) error {}
func (u *User) ScanRecord(rec record.Record) error {}
func (u *User) PrimaryKey() ([]byte, error) {}
@@ -133,5 +130,7 @@ This will generate a file named user.genji.go containing the following types and
}
func NewUserFields() UserFields {}
The User type now implements all the interfaces needed to interact correctly with the database APIs.
See the examples in this page to see how it can be used.
*/
package genji

View File

@@ -25,6 +25,11 @@ type Scanner interface {
// FieldBuffer is slice of fields which implements the Record interface.
type FieldBuffer []field.Field
// NewFieldBuffer creates a FieldBuffer with the given fields.
func NewFieldBuffer(fields ...field.Field) FieldBuffer {
return FieldBuffer(fields)
}
// Add a field to the buffer.
func (fb *FieldBuffer) Add(f field.Field) {
*fb = append(*fb, f)
@@ -50,10 +55,11 @@ func (fb FieldBuffer) GetField(name string) (field.Field, error) {
}
// Set replaces a field if it already exists or creates one if not.
func (fb FieldBuffer) Set(f field.Field) {
for i := range fb {
if fb[i].Name == f.Name {
fb[i] = f
func (fb *FieldBuffer) Set(f field.Field) {
s := *fb
for i := range s {
if s[i].Name == f.Name {
(*fb)[i] = f
return
}
}
@@ -87,7 +93,7 @@ func (fb *FieldBuffer) Delete(name string) error {
return fmt.Errorf("field %q not found", name)
}
// Replace the field with the given by f.
// Replace the field with the given name by f.
func (fb *FieldBuffer) Replace(name string, f field.Field) error {
s := *fb
for i := range s {
@@ -98,7 +104,7 @@ func (fb *FieldBuffer) Replace(name string, f field.Field) error {
}
}
return fmt.Errorf("field %q not found", name)
return fmt.Errorf("field %q not found", f.Name)
}
// DumpRecord is helper that dumps the content of a record into the given writer.

View File

@@ -11,20 +11,120 @@ import (
var _ record.Record = new(record.FieldBuffer)
func TestFieldBuffer(t *testing.T) {
b := record.FieldBuffer([]field.Field{
buf := record.NewFieldBuffer(
field.NewInt64("a", 10),
field.NewString("b", "hello"),
})
)
t.Run("Iterate", func(t *testing.T) {
var i int
err := b.Iterate(func(f field.Field) error {
err := buf.Iterate(func(f field.Field) error {
require.NotEmpty(t, f)
require.Equal(t, f, b[i])
require.Equal(t, f, buf[i])
i++
return nil
})
require.NoError(t, err)
require.Equal(t, 2, i)
})
t.Run("Add", func(t *testing.T) {
buf := record.NewFieldBuffer(
field.NewInt64("a", 10),
field.NewString("b", "hello"),
)
c := field.NewBool("c", true)
buf.Add(c)
require.Len(t, buf, 3)
require.Equal(t, buf[2], c)
})
t.Run("ScanRecord", func(t *testing.T) {
buf1 := record.NewFieldBuffer(
field.NewInt64("a", 10),
field.NewString("b", "hello"),
)
buf2 := record.NewFieldBuffer(
field.NewInt64("a", 20),
field.NewString("b", "bye"),
field.NewBool("c", true),
)
err := buf1.ScanRecord(buf2)
require.NoError(t, err)
require.Equal(t, record.NewFieldBuffer(
field.NewInt64("a", 10),
field.NewString("b", "hello"),
field.NewInt64("a", 20),
field.NewString("b", "bye"),
field.NewBool("c", true),
), buf1)
})
t.Run("GetField", func(t *testing.T) {
f, err := buf.GetField("a")
require.NoError(t, err)
require.Equal(t, field.NewInt64("a", 10), f)
f, err = buf.GetField("not existing")
require.Error(t, err)
require.Zero(t, f)
})
t.Run("Set", func(t *testing.T) {
buf1 := record.NewFieldBuffer(
field.NewInt64("a", 10),
field.NewString("b", "hello"),
)
buf1.Set(field.NewInt64("a", 11))
require.Equal(t, field.NewInt64("a", 11), buf1[0])
buf1.Set(field.NewInt64("c", 12))
require.Len(t, buf1, 3)
require.Equal(t, field.NewInt64("c", 12), buf1[2])
})
t.Run("Delete", func(t *testing.T) {
buf1 := record.NewFieldBuffer(
field.NewInt64("a", 10),
field.NewString("b", "hello"),
)
err := buf1.Delete("a")
require.NoError(t, err)
require.Len(t, buf1, 1)
require.Equal(t, record.NewFieldBuffer(
field.NewString("b", "hello"),
), buf1)
err = buf1.Delete("b")
require.NoError(t, err)
require.Len(t, buf1, 0)
err = buf1.Delete("b")
require.Error(t, err)
})
t.Run("Replace", func(t *testing.T) {
buf1 := record.NewFieldBuffer(
field.NewInt64("a", 10),
field.NewString("b", "hello"),
)
err := buf1.Replace("a", field.NewInt64("c", 10))
require.NoError(t, err)
require.Equal(t, record.NewFieldBuffer(
field.NewInt64("c", 10),
field.NewString("b", "hello"),
), buf1)
err = buf1.Replace("d", field.NewInt64("c", 11))
require.Error(t, err)
})
}
func TestNewFromMap(t *testing.T) {

View File

@@ -1,9 +1,8 @@
package genji_test
package table_test
import (
"bytes"
"fmt"
"log"
"testing"
"time"
@@ -12,32 +11,12 @@ import (
"github.com/asdine/genji/field"
"github.com/asdine/genji/record"
"github.com/asdine/genji/table"
"github.com/asdine/genji/table/tabletest"
"github.com/stretchr/testify/require"
)
func tableBuilder(t testing.TB) func() (table.Table, func()) {
return func() (table.Table, func()) {
db, err := genji.New(memory.NewEngine())
require.NoError(t, err)
var _ table.Reader = (*genji.Table)(nil)
tx, err := db.Begin(true)
require.NoError(t, err)
tb, err := tx.CreateTable("test")
require.NoError(t, err)
return tb, func() {
tx.Rollback()
}
}
}
func TestTable(t *testing.T) {
tabletest.TestSuite(t, tableBuilder(t))
}
func TestTableString(t *testing.T) {
func TestDump(t *testing.T) {
tests := []struct {
name string
expected string
@@ -79,30 +58,3 @@ name(String): "John 2", age(Int): 12
})
}
}
func ExampleDB() {
ng := memory.NewEngine()
db, err := genji.New(ng)
if err != nil {
log.Fatal(err)
}
defer db.Close()
err = db.Update(func(tx *genji.Tx) error {
t, err := tx.CreateTable("Table")
if err != nil {
return err
}
r := record.FieldBuffer{
field.NewString("Name", "foo"),
field.NewInt("Age", 10),
}
_, err = t.Insert(r)
return err
})
if err != nil {
log.Fatal(err)
}
}

62
table_test.go Normal file
View File

@@ -0,0 +1,62 @@
package genji_test
import (
"log"
"testing"
"github.com/asdine/genji"
"github.com/asdine/genji/engine/memory"
"github.com/asdine/genji/field"
"github.com/asdine/genji/record"
"github.com/asdine/genji/table"
"github.com/asdine/genji/table/tabletest"
"github.com/stretchr/testify/require"
)
func tableBuilder(t testing.TB) func() (table.Table, func()) {
return func() (table.Table, func()) {
db, err := genji.New(memory.NewEngine())
require.NoError(t, err)
tx, err := db.Begin(true)
require.NoError(t, err)
tb, err := tx.CreateTable("test")
require.NoError(t, err)
return tb, func() {
tx.Rollback()
}
}
}
func TestTable(t *testing.T) {
tabletest.TestSuite(t, tableBuilder(t))
}
func ExampleDB() {
ng := memory.NewEngine()
db, err := genji.New(ng)
if err != nil {
log.Fatal(err)
}
defer db.Close()
err = db.Update(func(tx *genji.Tx) error {
t, err := tx.CreateTable("Table")
if err != nil {
return err
}
r := record.FieldBuffer{
field.NewString("Name", "foo"),
field.NewInt("Age", 10),
}
_, err = t.Insert(r)
return err
})
if err != nil {
log.Fatal(err)
}
}