mirror of
https://github.com/chaisql/chai.git
synced 2025-10-07 16:41:03 +08:00
Test FieldBuffer
This commit is contained in:
11
doc.go
11
doc.go
@@ -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.
|
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.
|
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.
|
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.
|
Genji defines its own semantic to describe data.
|
||||||
Data stored in Genji being schemaless, the usual SQL triplet "column", "row", "table" wasn't chosen
|
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
|
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
|
is to map structures and maps to tables, though it's not limited to that.
|
||||||
to what people are used to in this language.
|
|
||||||
|
|
||||||
That's why the triplet "field", "record" and "table" was chosen.
|
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
|
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.
|
// 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) Iterate(fn func(field.Field) error) error {}
|
||||||
func (u *User) ScanRecord(rec record.Record) error {}
|
func (u *User) ScanRecord(rec record.Record) error {}
|
||||||
func (u *User) PrimaryKey() ([]byte, 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 {}
|
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
|
package genji
|
||||||
|
@@ -25,6 +25,11 @@ type Scanner interface {
|
|||||||
// FieldBuffer is slice of fields which implements the Record interface.
|
// FieldBuffer is slice of fields which implements the Record interface.
|
||||||
type FieldBuffer []field.Field
|
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.
|
// Add a field to the buffer.
|
||||||
func (fb *FieldBuffer) Add(f field.Field) {
|
func (fb *FieldBuffer) Add(f field.Field) {
|
||||||
*fb = append(*fb, f)
|
*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.
|
// Set replaces a field if it already exists or creates one if not.
|
||||||
func (fb FieldBuffer) Set(f field.Field) {
|
func (fb *FieldBuffer) Set(f field.Field) {
|
||||||
for i := range fb {
|
s := *fb
|
||||||
if fb[i].Name == f.Name {
|
for i := range s {
|
||||||
fb[i] = f
|
if s[i].Name == f.Name {
|
||||||
|
(*fb)[i] = f
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,7 +93,7 @@ func (fb *FieldBuffer) Delete(name string) error {
|
|||||||
return fmt.Errorf("field %q not found", name)
|
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 {
|
func (fb *FieldBuffer) Replace(name string, f field.Field) error {
|
||||||
s := *fb
|
s := *fb
|
||||||
for i := range s {
|
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.
|
// DumpRecord is helper that dumps the content of a record into the given writer.
|
||||||
|
@@ -11,20 +11,120 @@ import (
|
|||||||
var _ record.Record = new(record.FieldBuffer)
|
var _ record.Record = new(record.FieldBuffer)
|
||||||
|
|
||||||
func TestFieldBuffer(t *testing.T) {
|
func TestFieldBuffer(t *testing.T) {
|
||||||
b := record.FieldBuffer([]field.Field{
|
buf := record.NewFieldBuffer(
|
||||||
field.NewInt64("a", 10),
|
field.NewInt64("a", 10),
|
||||||
field.NewString("b", "hello"),
|
field.NewString("b", "hello"),
|
||||||
})
|
)
|
||||||
|
|
||||||
|
t.Run("Iterate", func(t *testing.T) {
|
||||||
var i int
|
var i int
|
||||||
err := b.Iterate(func(f field.Field) error {
|
err := buf.Iterate(func(f field.Field) error {
|
||||||
require.NotEmpty(t, f)
|
require.NotEmpty(t, f)
|
||||||
require.Equal(t, f, b[i])
|
require.Equal(t, f, buf[i])
|
||||||
i++
|
i++
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 2, i)
|
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) {
|
func TestNewFromMap(t *testing.T) {
|
||||||
|
@@ -1,9 +1,8 @@
|
|||||||
package genji_test
|
package table_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -12,32 +11,12 @@ import (
|
|||||||
"github.com/asdine/genji/field"
|
"github.com/asdine/genji/field"
|
||||||
"github.com/asdine/genji/record"
|
"github.com/asdine/genji/record"
|
||||||
"github.com/asdine/genji/table"
|
"github.com/asdine/genji/table"
|
||||||
"github.com/asdine/genji/table/tabletest"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func tableBuilder(t testing.TB) func() (table.Table, func()) {
|
var _ table.Reader = (*genji.Table)(nil)
|
||||||
return func() (table.Table, func()) {
|
|
||||||
db, err := genji.New(memory.NewEngine())
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
tx, err := db.Begin(true)
|
func TestDump(t *testing.T) {
|
||||||
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) {
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
expected 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
62
table_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user