mirror of
https://github.com/chaisql/chai.git
synced 2025-10-07 08:30:52 +08:00
853 lines
18 KiB
Go
853 lines
18 KiB
Go
package genji_test
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"testing"
|
|
|
|
"github.com/asdine/genji"
|
|
"github.com/asdine/genji/engine/memory"
|
|
"github.com/asdine/genji/index"
|
|
"github.com/asdine/genji/record"
|
|
"github.com/asdine/genji/value"
|
|
"github.com/pkg/errors"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func ExampleOpen() {
|
|
db, err := genji.Open(memory.NewEngine())
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer db.Close()
|
|
|
|
_, err = db.Exec("CREATE TABLE user IF NOT EXISTS")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
_, err = db.Exec("CREATE INDEX IF NOT EXISTS idx_user_Name ON user (Name)")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
_, err = db.Exec("INSERT INTO user (ID, Name, Age) VALUES (?, ?, ?)", 10, "foo", 15)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
_, err = db.Exec("INSERT INTO user RECORDS ?, ?", &User{ID: 1, Name: "bar", Age: 100}, &User{ID: 2, Name: "baz"})
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
rows, err := db.Query("SELECT * FROM user WHERE Name = ?", "bar")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
for rows.Next() {
|
|
var u User
|
|
err = rows.Scan(&u)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Println(u)
|
|
}
|
|
|
|
err = rows.Err()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
// Output: {1 bar 100}
|
|
}
|
|
|
|
func ExampleTx() {
|
|
db, err := genji.New(memory.NewEngine())
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer db.Close()
|
|
|
|
tx, err := db.Begin(false)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer tx.Rollback()
|
|
|
|
err = tx.Exec("CREATE TABLE user IF NOT EXISTS")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
err = tx.Exec("INSERT INTO user (ID, Name, Age) VALUES (?, ?, ?)", 10, "foo", 15)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
result, err := tx.Query("SELECT ID, Name, Age FROM user WHERE Name = ?", "foo")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer result.Close()
|
|
|
|
var u User
|
|
r, err := result.First()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
err = u.ScanRecord(r)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(u)
|
|
|
|
var id uint64
|
|
var name string
|
|
var age uint8
|
|
|
|
err = record.Scan(r, &id, &name, &age)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(id, name, age)
|
|
|
|
err = tx.Commit()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Output: {10 foo 15}
|
|
// 10 foo 15
|
|
}
|
|
|
|
func newTestDB(t testing.TB) (*genji.Tx, func()) {
|
|
db, err := genji.New(memory.NewEngine())
|
|
require.NoError(t, err)
|
|
|
|
tx, err := db.Begin(true)
|
|
require.NoError(t, err)
|
|
|
|
return tx, func() {
|
|
tx.Rollback()
|
|
}
|
|
}
|
|
|
|
func newTestTable(t testing.TB) (*genji.Table, func()) {
|
|
tx, fn := newTestDB(t)
|
|
|
|
err := tx.CreateTable("test", nil)
|
|
require.NoError(t, err)
|
|
tb, err := tx.GetTable("test")
|
|
require.NoError(t, err)
|
|
|
|
return tb, fn
|
|
}
|
|
|
|
func TestTxCreateIndex(t *testing.T) {
|
|
t.Run("Should create an index and return it", func(t *testing.T) {
|
|
tx, cleanup := newTestDB(t)
|
|
defer cleanup()
|
|
|
|
err := tx.CreateTable("test", nil)
|
|
require.NoError(t, err)
|
|
|
|
err = tx.CreateIndex(index.Options{
|
|
IndexName: "idxFoo", TableName: "test", FieldName: "foo",
|
|
})
|
|
require.NoError(t, err)
|
|
idx, err := tx.GetIndex("idxFoo")
|
|
require.NoError(t, err)
|
|
require.NotNil(t, idx)
|
|
})
|
|
|
|
t.Run("Should fail if it already exists", func(t *testing.T) {
|
|
tx, cleanup := newTestDB(t)
|
|
defer cleanup()
|
|
|
|
err := tx.CreateTable("test", nil)
|
|
require.NoError(t, err)
|
|
|
|
err = tx.CreateIndex(index.Options{
|
|
IndexName: "idxFoo", TableName: "test", FieldName: "foo",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
err = tx.CreateIndex(index.Options{
|
|
IndexName: "idxFoo", TableName: "test", FieldName: "foo",
|
|
})
|
|
require.Equal(t, genji.ErrIndexAlreadyExists, err)
|
|
})
|
|
|
|
t.Run("Should fail if table doesn't exists", func(t *testing.T) {
|
|
tx, cleanup := newTestDB(t)
|
|
defer cleanup()
|
|
|
|
err := tx.CreateIndex(index.Options{
|
|
IndexName: "idxFoo", TableName: "test", FieldName: "foo",
|
|
})
|
|
require.Equal(t, genji.ErrTableNotFound, err)
|
|
})
|
|
}
|
|
|
|
func TestTxDropIndex(t *testing.T) {
|
|
t.Run("Should drop an index", func(t *testing.T) {
|
|
tx, cleanup := newTestDB(t)
|
|
defer cleanup()
|
|
|
|
err := tx.CreateTable("test", nil)
|
|
require.NoError(t, err)
|
|
|
|
err = tx.CreateIndex(index.Options{
|
|
IndexName: "idxFoo", TableName: "test", FieldName: "foo",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
err = tx.DropIndex("idxFoo")
|
|
require.NoError(t, err)
|
|
|
|
_, err = tx.GetIndex("idxFoo")
|
|
require.Error(t, err)
|
|
})
|
|
|
|
t.Run("Should fail if it doesn't exist", func(t *testing.T) {
|
|
tx, cleanup := newTestDB(t)
|
|
defer cleanup()
|
|
|
|
err := tx.DropIndex("idxFoo")
|
|
require.Equal(t, genji.ErrIndexNotFound, err)
|
|
})
|
|
}
|
|
|
|
func TestTxReIndex(t *testing.T) {
|
|
newTestTableFn := func(t *testing.T) (*genji.Tx, *genji.Table, func()) {
|
|
tx, cleanup := newTestDB(t)
|
|
err := tx.CreateTable("test", nil)
|
|
require.NoError(t, err)
|
|
tb, err := tx.GetTable("test")
|
|
require.NoError(t, err)
|
|
|
|
for i := 0; i < 10; i++ {
|
|
_, err = tb.Insert(record.NewFieldBuffer(
|
|
record.NewIntField("a", i),
|
|
record.NewIntField("b", i*10),
|
|
))
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
err = tx.CreateIndex(index.Options{
|
|
IndexName: "a",
|
|
TableName: "test",
|
|
FieldName: "a",
|
|
})
|
|
require.NoError(t, err)
|
|
err = tx.CreateIndex(index.Options{
|
|
IndexName: "b",
|
|
TableName: "test",
|
|
FieldName: "b",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
return tx, tb, cleanup
|
|
}
|
|
|
|
t.Run("Should fail if not found", func(t *testing.T) {
|
|
tx, _, cleanup := newTestTableFn(t)
|
|
defer cleanup()
|
|
|
|
err := tx.ReIndex("foo")
|
|
require.Equal(t, genji.ErrIndexNotFound, err)
|
|
})
|
|
|
|
t.Run("Should reindex the right index", func(t *testing.T) {
|
|
tx, _, cleanup := newTestTableFn(t)
|
|
defer cleanup()
|
|
|
|
err := tx.ReIndex("a")
|
|
require.NoError(t, err)
|
|
|
|
idx, err := tx.GetIndex("a")
|
|
require.NoError(t, err)
|
|
|
|
var i int
|
|
err = idx.AscendGreaterOrEqual(index.EmptyPivot(value.Int), func(val value.Value, key []byte) error {
|
|
require.Equal(t, value.NewFloat64(float64(i)), val)
|
|
i++
|
|
return nil
|
|
})
|
|
require.Equal(t, 10, i)
|
|
require.NoError(t, err)
|
|
|
|
idx, err = tx.GetIndex("b")
|
|
require.NoError(t, err)
|
|
|
|
i = 0
|
|
err = idx.AscendGreaterOrEqual(index.EmptyPivot(value.Int), func(val value.Value, key []byte) error {
|
|
i++
|
|
return nil
|
|
})
|
|
require.NoError(t, err)
|
|
require.Zero(t, i)
|
|
})
|
|
}
|
|
|
|
func TestReIndexAll(t *testing.T) {
|
|
t.Run("Should succeed if not indexes", func(t *testing.T) {
|
|
tx, cleanup := newTestDB(t)
|
|
defer cleanup()
|
|
|
|
err := tx.ReIndexAll()
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("Should reindex all indexes", func(t *testing.T) {
|
|
tx, cleanup := newTestDB(t)
|
|
defer cleanup()
|
|
|
|
err := tx.CreateTable("test1", nil)
|
|
require.NoError(t, err)
|
|
tb1, err := tx.GetTable("test1")
|
|
require.NoError(t, err)
|
|
|
|
err = tx.CreateTable("test2", nil)
|
|
require.NoError(t, err)
|
|
tb2, err := tx.GetTable("test2")
|
|
require.NoError(t, err)
|
|
|
|
for i := 0; i < 10; i++ {
|
|
_, err = tb1.Insert(record.NewFieldBuffer(
|
|
record.NewIntField("a", i),
|
|
record.NewIntField("b", i*10),
|
|
))
|
|
require.NoError(t, err)
|
|
_, err = tb2.Insert(record.NewFieldBuffer(
|
|
record.NewIntField("a", i),
|
|
record.NewIntField("b", i*10),
|
|
))
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
err = tx.CreateIndex(index.Options{
|
|
IndexName: "t1a",
|
|
TableName: "test1",
|
|
FieldName: "a",
|
|
})
|
|
require.NoError(t, err)
|
|
err = tx.CreateIndex(index.Options{
|
|
IndexName: "t2a",
|
|
TableName: "test2",
|
|
FieldName: "a",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
err = tx.ReIndexAll()
|
|
require.NoError(t, err)
|
|
|
|
idx, err := tx.GetIndex("t1a")
|
|
require.NoError(t, err)
|
|
|
|
var i int
|
|
err = idx.AscendGreaterOrEqual(index.EmptyPivot(value.Int), func(val value.Value, key []byte) error {
|
|
require.Equal(t, value.NewFloat64(float64(i)), val)
|
|
i++
|
|
return nil
|
|
})
|
|
require.Equal(t, 10, i)
|
|
require.NoError(t, err)
|
|
|
|
idx, err = tx.GetIndex("t2a")
|
|
require.NoError(t, err)
|
|
|
|
i = 0
|
|
err = idx.AscendGreaterOrEqual(index.EmptyPivot(value.Int), func(val value.Value, key []byte) error {
|
|
require.Equal(t, value.NewFloat64(float64(i)), val)
|
|
i++
|
|
return nil
|
|
})
|
|
require.Equal(t, 10, i)
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
|
|
func newRecord() record.FieldBuffer {
|
|
return record.FieldBuffer([]record.Field{
|
|
record.NewStringField("fielda", "a"),
|
|
record.NewStringField("fieldb", "b"),
|
|
})
|
|
}
|
|
|
|
// TestTableIterate verifies Iterate behaviour.
|
|
func TestTableIterate(t *testing.T) {
|
|
t.Run("Should not fail with no records", func(t *testing.T) {
|
|
tb, cleanup := newTestTable(t)
|
|
defer cleanup()
|
|
|
|
i := 0
|
|
err := tb.Iterate(func(r record.Record) error {
|
|
i++
|
|
return nil
|
|
})
|
|
require.NoError(t, err)
|
|
require.Zero(t, i)
|
|
})
|
|
|
|
t.Run("Should iterate over all records", func(t *testing.T) {
|
|
tb, cleanup := newTestTable(t)
|
|
defer cleanup()
|
|
|
|
for i := 0; i < 10; i++ {
|
|
_, err := tb.Insert(newRecord())
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
m := make(map[string]int)
|
|
err := tb.Iterate(func(r record.Record) error {
|
|
m[string(r.(record.Keyer).Key())]++
|
|
return nil
|
|
})
|
|
require.NoError(t, err)
|
|
require.Len(t, m, 10)
|
|
for _, c := range m {
|
|
require.Equal(t, 1, c)
|
|
}
|
|
})
|
|
|
|
t.Run("Should stop if fn returns error", func(t *testing.T) {
|
|
tb, cleanup := newTestTable(t)
|
|
defer cleanup()
|
|
|
|
for i := 0; i < 10; i++ {
|
|
_, err := tb.Insert(newRecord())
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
i := 0
|
|
err := tb.Iterate(func(_ record.Record) error {
|
|
i++
|
|
if i >= 5 {
|
|
return errors.New("some error")
|
|
}
|
|
return nil
|
|
})
|
|
require.EqualError(t, err, "some error")
|
|
require.Equal(t, 5, i)
|
|
})
|
|
}
|
|
|
|
// TestTableRecord verifies Record behaviour.
|
|
func TestTableRecord(t *testing.T) {
|
|
t.Run("Should fail if not found", func(t *testing.T) {
|
|
tb, cleanup := newTestTable(t)
|
|
defer cleanup()
|
|
|
|
r, err := tb.GetRecord([]byte("id"))
|
|
require.Equal(t, genji.ErrRecordNotFound, err)
|
|
require.Nil(t, r)
|
|
})
|
|
|
|
t.Run("Should return the right record", func(t *testing.T) {
|
|
tb, cleanup := newTestTable(t)
|
|
defer cleanup()
|
|
|
|
// create two records, one with an additional field
|
|
rec1 := newRecord()
|
|
rec1.Add(record.NewInt64Field("fieldc", 40))
|
|
rec2 := newRecord()
|
|
|
|
key1, err := tb.Insert(rec1)
|
|
require.NoError(t, err)
|
|
_, err = tb.Insert(rec2)
|
|
require.NoError(t, err)
|
|
|
|
// fetch rec1 and make sure it returns the right one
|
|
res, err := tb.GetRecord(key1)
|
|
require.NoError(t, err)
|
|
fc, err := res.GetField("fieldc")
|
|
require.NoError(t, err)
|
|
require.Equal(t, rec1[2], fc)
|
|
})
|
|
}
|
|
|
|
// TestTableInsert verifies Insert behaviour.
|
|
func TestTableInsert(t *testing.T) {
|
|
t.Run("Should generate a key by default", func(t *testing.T) {
|
|
tb, cleanup := newTestTable(t)
|
|
defer cleanup()
|
|
|
|
rec := newRecord()
|
|
key1, err := tb.Insert(rec)
|
|
require.NoError(t, err)
|
|
require.NotEmpty(t, key1)
|
|
|
|
key2, err := tb.Insert(rec)
|
|
require.NoError(t, err)
|
|
require.NotEmpty(t, key2)
|
|
|
|
require.NotEqual(t, key1, key2)
|
|
})
|
|
|
|
t.Run("Should support PrimaryKeyer interface", func(t *testing.T) {
|
|
tb, cleanup := newTestTable(t)
|
|
defer cleanup()
|
|
|
|
var counter int64
|
|
|
|
rec := recordPker{
|
|
pkGenerator: func() ([]byte, error) {
|
|
counter += 2
|
|
return value.EncodeInt64(counter), nil
|
|
},
|
|
}
|
|
|
|
// insert
|
|
key, err := tb.Insert(rec)
|
|
require.NoError(t, err)
|
|
require.Equal(t, value.EncodeInt64(2), key)
|
|
|
|
// make sure the record is fetchable using the returned key
|
|
_, err = tb.GetRecord(key)
|
|
require.NoError(t, err)
|
|
|
|
// insert again
|
|
key, err = tb.Insert(rec)
|
|
require.NoError(t, err)
|
|
require.Equal(t, value.EncodeInt64(4), key)
|
|
})
|
|
|
|
t.Run("Should fail if Pk returns empty key", func(t *testing.T) {
|
|
tb, cleanup := newTestTable(t)
|
|
defer cleanup()
|
|
|
|
tests := [][]byte{
|
|
nil,
|
|
[]byte{},
|
|
[]byte(nil),
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("%#v", test), func(t *testing.T) {
|
|
rec := recordPker{
|
|
pkGenerator: func() ([]byte, error) {
|
|
return test, nil
|
|
},
|
|
}
|
|
|
|
_, err := tb.Insert(rec)
|
|
require.Error(t, err)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("Should return ErrDuplicate if key already exists", func(t *testing.T) {
|
|
tb, cleanup := newTestTable(t)
|
|
defer cleanup()
|
|
|
|
rec := recordPker{
|
|
pkGenerator: func() ([]byte, error) {
|
|
return value.EncodeInt64(1), nil
|
|
},
|
|
}
|
|
|
|
// insert
|
|
_, err := tb.Insert(rec)
|
|
require.NoError(t, err)
|
|
|
|
_, err = tb.Insert(rec)
|
|
require.Equal(t, genji.ErrDuplicateRecord, err)
|
|
})
|
|
|
|
t.Run("Should update indexes if there are indexed fields", func(t *testing.T) {
|
|
tx, cleanup := newTestDB(t)
|
|
defer cleanup()
|
|
|
|
err := tx.CreateTable("test", nil)
|
|
require.NoError(t, err)
|
|
|
|
err = tx.CreateIndex(index.Options{
|
|
IndexName: "idxFoo", TableName: "test", FieldName: "foo",
|
|
})
|
|
require.NoError(t, err)
|
|
idx, err := tx.GetIndex("idxFoo")
|
|
require.NoError(t, err)
|
|
|
|
tb, err := tx.GetTable("test")
|
|
require.NoError(t, err)
|
|
|
|
rec := newRecord()
|
|
foo := record.NewFloat32Field("foo", 10)
|
|
rec = append(rec, foo)
|
|
|
|
key, err := tb.Insert(rec)
|
|
require.NoError(t, err)
|
|
require.NotEmpty(t, key)
|
|
|
|
f, err := foo.DecodeToFloat64()
|
|
require.NoError(t, err)
|
|
expected := value.NewFloat64(f)
|
|
var count int
|
|
err = idx.AscendGreaterOrEqual(index.EmptyPivot(value.Float64), func(val value.Value, k []byte) error {
|
|
require.Equal(t, val, expected)
|
|
require.Equal(t, key, k)
|
|
count++
|
|
return nil
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, count)
|
|
})
|
|
}
|
|
|
|
type recordPker struct {
|
|
record.FieldBuffer
|
|
pkGenerator func() ([]byte, error)
|
|
}
|
|
|
|
func (r recordPker) PrimaryKey() ([]byte, error) {
|
|
return r.pkGenerator()
|
|
}
|
|
|
|
// TestTableDelete verifies Delete behaviour.
|
|
func TestTableDelete(t *testing.T) {
|
|
t.Run("Should fail if not found", func(t *testing.T) {
|
|
tb, cleanup := newTestTable(t)
|
|
defer cleanup()
|
|
|
|
err := tb.Delete([]byte("id"))
|
|
require.Equal(t, genji.ErrRecordNotFound, err)
|
|
})
|
|
|
|
t.Run("Should delete the right record", func(t *testing.T) {
|
|
tb, cleanup := newTestTable(t)
|
|
defer cleanup()
|
|
|
|
// create two records, one with an additional field
|
|
rec1 := newRecord()
|
|
rec1.Add(record.NewInt64Field("fieldc", 40))
|
|
rec2 := newRecord()
|
|
|
|
key1, err := tb.Insert(rec1)
|
|
require.NoError(t, err)
|
|
key2, err := tb.Insert(rec2)
|
|
require.NoError(t, err)
|
|
|
|
// delete the record
|
|
err = tb.Delete([]byte(key1))
|
|
require.NoError(t, err)
|
|
|
|
// try again, should fail
|
|
err = tb.Delete([]byte(key1))
|
|
require.Equal(t, genji.ErrRecordNotFound, err)
|
|
|
|
// make sure it didn't also delete the other one
|
|
res, err := tb.GetRecord(key2)
|
|
require.NoError(t, err)
|
|
_, err = res.GetField("fieldc")
|
|
require.Error(t, err)
|
|
})
|
|
}
|
|
|
|
// TestTableReplace verifies Replace behaviour.
|
|
func TestTableReplace(t *testing.T) {
|
|
t.Run("Should fail if not found", func(t *testing.T) {
|
|
tb, cleanup := newTestTable(t)
|
|
defer cleanup()
|
|
|
|
err := tb.Replace([]byte("id"), newRecord())
|
|
require.Equal(t, genji.ErrRecordNotFound, err)
|
|
})
|
|
|
|
t.Run("Should replace the right record", func(t *testing.T) {
|
|
tb, cleanup := newTestTable(t)
|
|
defer cleanup()
|
|
|
|
// create two different records
|
|
rec1 := newRecord()
|
|
rec2 := record.FieldBuffer([]record.Field{
|
|
record.NewStringField("fielda", "c"),
|
|
record.NewStringField("fieldb", "d"),
|
|
})
|
|
|
|
key1, err := tb.Insert(rec1)
|
|
require.NoError(t, err)
|
|
key2, err := tb.Insert(rec2)
|
|
require.NoError(t, err)
|
|
|
|
// create a third record
|
|
rec3 := record.FieldBuffer([]record.Field{
|
|
record.NewStringField("fielda", "e"),
|
|
record.NewStringField("fieldb", "f"),
|
|
})
|
|
|
|
// replace rec1 with rec3
|
|
err = tb.Replace(key1, rec3)
|
|
require.NoError(t, err)
|
|
|
|
// make sure it replaced it correctly
|
|
res, err := tb.GetRecord(key1)
|
|
require.NoError(t, err)
|
|
f, err := res.GetField("fielda")
|
|
require.NoError(t, err)
|
|
require.Equal(t, "e", string(f.Data))
|
|
|
|
// make sure it didn't also replace the other one
|
|
res, err = tb.GetRecord(key2)
|
|
require.NoError(t, err)
|
|
f, err = res.GetField("fielda")
|
|
require.NoError(t, err)
|
|
require.Equal(t, "c", string(f.Data))
|
|
})
|
|
}
|
|
|
|
// TestTableTruncate verifies Truncate behaviour.
|
|
func TestTableTruncate(t *testing.T) {
|
|
t.Run("Should succeed if table empty", func(t *testing.T) {
|
|
tb, cleanup := newTestTable(t)
|
|
defer cleanup()
|
|
|
|
err := tb.Truncate()
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("Should truncate the table", func(t *testing.T) {
|
|
tb, cleanup := newTestTable(t)
|
|
defer cleanup()
|
|
|
|
// create two records
|
|
rec1 := newRecord()
|
|
rec2 := newRecord()
|
|
|
|
_, err := tb.Insert(rec1)
|
|
require.NoError(t, err)
|
|
_, err = tb.Insert(rec2)
|
|
require.NoError(t, err)
|
|
|
|
err = tb.Truncate()
|
|
require.NoError(t, err)
|
|
|
|
err = tb.Iterate(func(_ record.Record) error {
|
|
return errors.New("should not iterate")
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
|
|
func TestTableIndexes(t *testing.T) {
|
|
t.Run("Should succeed if table has no indexes", func(t *testing.T) {
|
|
tb, cleanup := newTestTable(t)
|
|
defer cleanup()
|
|
|
|
m, err := tb.Indexes()
|
|
require.NoError(t, err)
|
|
require.Empty(t, m)
|
|
})
|
|
|
|
t.Run("Should return a map of all the indexes", func(t *testing.T) {
|
|
tx, cleanup := newTestDB(t)
|
|
defer cleanup()
|
|
|
|
err := tx.CreateTable("test1", nil)
|
|
require.NoError(t, err)
|
|
tb, err := tx.GetTable("test1")
|
|
require.NoError(t, err)
|
|
|
|
err = tx.CreateTable("test2", nil)
|
|
require.NoError(t, err)
|
|
|
|
err = tx.CreateIndex(index.Options{
|
|
Unique: true,
|
|
IndexName: "idx1a",
|
|
TableName: "test1",
|
|
FieldName: "a",
|
|
})
|
|
require.NoError(t, err)
|
|
err = tx.CreateIndex(index.Options{
|
|
Unique: false,
|
|
IndexName: "idx1b",
|
|
TableName: "test1",
|
|
FieldName: "b",
|
|
})
|
|
require.NoError(t, err)
|
|
err = tx.CreateIndex(index.Options{
|
|
Unique: false,
|
|
IndexName: "ifx2a",
|
|
TableName: "test2",
|
|
FieldName: "a",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
m, err := tb.Indexes()
|
|
require.NoError(t, err)
|
|
require.Len(t, m, 2)
|
|
idx1a, ok := m["a"]
|
|
require.True(t, ok)
|
|
require.NotNil(t, idx1a)
|
|
idx1b, ok := m["b"]
|
|
require.True(t, ok)
|
|
require.NotNil(t, idx1b)
|
|
})
|
|
}
|
|
|
|
// BenchmarkTableInsert benchmarks the Insert method with 1, 10, 1000 and 10000 successive insertions.
|
|
func BenchmarkTableInsert(b *testing.B) {
|
|
for size := 1; size <= 10000; size *= 10 {
|
|
b.Run(fmt.Sprintf("%.05d", size), func(b *testing.B) {
|
|
var fields []record.Field
|
|
|
|
for i := int64(0); i < 10; i++ {
|
|
fields = append(fields, record.NewInt64Field(fmt.Sprintf("name-%d", i), i))
|
|
}
|
|
|
|
rec := record.FieldBuffer(fields)
|
|
|
|
b.ResetTimer()
|
|
b.StopTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
tb, cleanup := newTestTable(b)
|
|
|
|
b.StartTimer()
|
|
for j := 0; j < size; j++ {
|
|
tb.Insert(rec)
|
|
}
|
|
b.StopTimer()
|
|
cleanup()
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// BenchmarkTableScan benchmarks the Scan method with 1, 10, 1000 and 10000 successive insertions.
|
|
func BenchmarkTableScan(b *testing.B) {
|
|
for size := 1; size <= 10000; size *= 10 {
|
|
b.Run(fmt.Sprintf("%.05d", size), func(b *testing.B) {
|
|
tb, cleanup := newTestTable(b)
|
|
defer cleanup()
|
|
|
|
var fields []record.Field
|
|
|
|
for i := int64(0); i < 10; i++ {
|
|
fields = append(fields, record.NewInt64Field(fmt.Sprintf("name-%d", i), i))
|
|
}
|
|
|
|
rec := record.FieldBuffer(fields)
|
|
|
|
for i := 0; i < size; i++ {
|
|
_, err := tb.Insert(rec)
|
|
require.NoError(b, err)
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
tb.Iterate(func(record.Record) error {
|
|
return nil
|
|
})
|
|
}
|
|
b.StopTimer()
|
|
})
|
|
}
|
|
}
|