555 lines
11 KiB
Go
555 lines
11 KiB
Go
package storm
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/asdine/storm/codec/json"
|
|
"github.com/asdine/storm/q"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
type Score struct {
|
|
ID int `storm:"increment"`
|
|
Value int
|
|
}
|
|
|
|
func prepareScoreDB(t *testing.T) (*DB, func()) {
|
|
db, cleanup := createDB(t)
|
|
|
|
for i := 0; i < 20; i++ {
|
|
err := db.Save(&Score{
|
|
Value: i,
|
|
})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
return db, cleanup
|
|
}
|
|
|
|
func TestSelectFind(t *testing.T) {
|
|
db, cleanup := prepareScoreDB(t)
|
|
defer cleanup()
|
|
|
|
var scores []Score
|
|
var scoresPtr []*Score
|
|
|
|
err := db.Select(q.Eq("Value", 5)).Find(&scores)
|
|
require.NoError(t, err)
|
|
require.Len(t, scores, 1)
|
|
require.Equal(t, 5, scores[0].Value)
|
|
|
|
err = db.Select(q.Eq("Value", 5)).Find(&scoresPtr)
|
|
require.NoError(t, err)
|
|
require.Len(t, scoresPtr, 1)
|
|
require.Equal(t, 5, scoresPtr[0].Value)
|
|
|
|
err = db.Select(
|
|
q.Or(
|
|
q.Eq("Value", 5),
|
|
q.Eq("Value", 6),
|
|
),
|
|
).Find(&scores)
|
|
require.NoError(t, err)
|
|
require.Len(t, scores, 2)
|
|
require.Equal(t, 5, scores[0].Value)
|
|
require.Equal(t, 6, scores[1].Value)
|
|
|
|
err = db.Select(q.Or(
|
|
q.Eq("Value", 5),
|
|
q.Or(
|
|
q.Lte("Value", 2),
|
|
q.Gte("Value", 18),
|
|
),
|
|
)).Find(&scores)
|
|
require.NoError(t, err)
|
|
require.Len(t, scores, 6)
|
|
require.Equal(t, 0, scores[0].Value)
|
|
require.Equal(t, 1, scores[1].Value)
|
|
require.Equal(t, 2, scores[2].Value)
|
|
require.Equal(t, 5, scores[3].Value)
|
|
require.Equal(t, 18, scores[4].Value)
|
|
require.Equal(t, 19, scores[5].Value)
|
|
|
|
err = db.Select(q.Or(
|
|
q.Eq("Value", 5),
|
|
q.Or(
|
|
q.Lte("Value", 2),
|
|
q.Gte("Value", 18),
|
|
),
|
|
)).Reverse().Find(&scores)
|
|
require.NoError(t, err)
|
|
require.Len(t, scores, 6)
|
|
require.Equal(t, 19, scores[0].Value)
|
|
require.Equal(t, 18, scores[1].Value)
|
|
require.Equal(t, 5, scores[2].Value)
|
|
require.Equal(t, 2, scores[3].Value)
|
|
require.Equal(t, 1, scores[4].Value)
|
|
require.Equal(t, 0, scores[5].Value)
|
|
}
|
|
|
|
func TestSelectFindSkip(t *testing.T) {
|
|
db, cleanup := prepareScoreDB(t)
|
|
defer cleanup()
|
|
|
|
var scores []Score
|
|
|
|
err := db.Select(q.Or(
|
|
q.Eq("Value", 5),
|
|
q.Or(
|
|
q.Lte("Value", 2),
|
|
q.Gte("Value", 18),
|
|
),
|
|
)).Skip(4).Find(&scores)
|
|
require.NoError(t, err)
|
|
require.Len(t, scores, 2)
|
|
require.Equal(t, 18, scores[0].Value)
|
|
require.Equal(t, 19, scores[1].Value)
|
|
|
|
err = db.Select(q.Or(
|
|
q.Eq("Value", 5),
|
|
q.Or(
|
|
q.Lte("Value", 2),
|
|
q.Gte("Value", 18),
|
|
),
|
|
)).Skip(-10).Find(&scores)
|
|
require.NoError(t, err)
|
|
require.Len(t, scores, 6)
|
|
require.Equal(t, 0, scores[0].Value)
|
|
|
|
scores = nil
|
|
err = db.Select(q.Or(
|
|
q.Eq("Value", 5),
|
|
q.Or(
|
|
q.Lte("Value", 2),
|
|
q.Gte("Value", 18),
|
|
),
|
|
)).Skip(1000).Find(&scores)
|
|
require.Error(t, err)
|
|
require.True(t, ErrNotFound == err)
|
|
require.Len(t, scores, 0)
|
|
}
|
|
|
|
func TestSelectFindLimit(t *testing.T) {
|
|
db, cleanup := prepareScoreDB(t)
|
|
defer cleanup()
|
|
var scores []Score
|
|
|
|
err := db.Select(q.Or(
|
|
q.Eq("Value", 5),
|
|
q.Or(
|
|
q.Lte("Value", 2),
|
|
q.Gte("Value", 18),
|
|
),
|
|
)).Limit(2).Find(&scores)
|
|
require.NoError(t, err)
|
|
require.Len(t, scores, 2)
|
|
require.Equal(t, 0, scores[0].Value)
|
|
require.Equal(t, 1, scores[1].Value)
|
|
|
|
err = db.Select(q.Or(
|
|
q.Eq("Value", 5),
|
|
q.Or(
|
|
q.Lte("Value", 2),
|
|
q.Gte("Value", 18),
|
|
),
|
|
)).Limit(-10).Find(&scores)
|
|
require.NoError(t, err)
|
|
require.Len(t, scores, 6)
|
|
require.Equal(t, 0, scores[0].Value)
|
|
|
|
scores = nil
|
|
err = db.Select(q.Or(
|
|
q.Eq("Value", 5),
|
|
q.Or(
|
|
q.Lte("Value", 2),
|
|
q.Gte("Value", 18),
|
|
),
|
|
)).Limit(0).Find(&scores)
|
|
require.Error(t, err)
|
|
require.True(t, ErrNotFound == err)
|
|
require.Len(t, scores, 0)
|
|
}
|
|
|
|
func TestSelectFindLimitSkip(t *testing.T) {
|
|
db, cleanup := prepareScoreDB(t)
|
|
defer cleanup()
|
|
|
|
var scores []Score
|
|
|
|
err := db.Select(q.Or(
|
|
q.Eq("Value", 5),
|
|
q.Or(
|
|
q.Lte("Value", 2),
|
|
q.Gte("Value", 18),
|
|
),
|
|
)).Limit(2).Skip(2).Find(&scores)
|
|
require.NoError(t, err)
|
|
require.Len(t, scores, 2)
|
|
require.Equal(t, 2, scores[0].Value)
|
|
require.Equal(t, 5, scores[1].Value)
|
|
|
|
err = db.Select(q.Or(
|
|
q.Eq("Value", 5),
|
|
q.Or(
|
|
q.Lte("Value", 2),
|
|
q.Gte("Value", 18),
|
|
),
|
|
)).Limit(2).Skip(5).Find(&scores)
|
|
require.NoError(t, err)
|
|
require.Len(t, scores, 1)
|
|
require.Equal(t, 19, scores[0].Value)
|
|
}
|
|
|
|
func TestSelectFindOrderBy(t *testing.T) {
|
|
db, cleanup := createDB(t)
|
|
defer cleanup()
|
|
|
|
type T struct {
|
|
ID int `storm:"increment"`
|
|
Str string
|
|
Int int
|
|
Rnd int
|
|
}
|
|
|
|
strs := []string{"e", "b", "d", "a", "c", "d"}
|
|
ints := []int{2, 3, 5, 4, 2, 1}
|
|
for i := 0; i < 6; i++ {
|
|
record := T{
|
|
Str: strs[i],
|
|
Int: ints[i],
|
|
}
|
|
if i == 3 {
|
|
record.Rnd = 3
|
|
}
|
|
|
|
err := db.Save(&record)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
var list []T
|
|
err := db.Select().OrderBy("ID").Find(&list)
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 6)
|
|
for i, j := 0, 0; i < 6; i, j = i+1, j+1 {
|
|
if i == 2 {
|
|
j--
|
|
}
|
|
require.Equal(t, i+1, list[i].ID)
|
|
}
|
|
|
|
list = nil
|
|
err = db.Select().OrderBy("Str").Find(&list)
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 6)
|
|
for i, j := 0, 0; i < 6; i, j = i+1, j+1 {
|
|
if i == 4 {
|
|
j--
|
|
}
|
|
require.Equal(t, string([]byte{'a' + byte(j)}), list[i].Str)
|
|
}
|
|
|
|
list = nil
|
|
err = db.Select().OrderBy("Int").Find(&list)
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 6)
|
|
for i, j := 0, 0; i < 6; i, j = i+1, j+1 {
|
|
if i == 2 {
|
|
j--
|
|
}
|
|
require.Equal(t, j+1, list[i].Int)
|
|
}
|
|
|
|
list = nil
|
|
err = db.Select().OrderBy("Rnd").Find(&list)
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 6)
|
|
require.Equal(t, 1, list[0].ID)
|
|
require.Equal(t, 2, list[1].ID)
|
|
require.Equal(t, 3, list[2].ID)
|
|
require.Equal(t, 5, list[3].ID)
|
|
require.Equal(t, 6, list[4].ID)
|
|
require.Equal(t, 4, list[5].ID)
|
|
|
|
list = nil
|
|
err = db.Select().OrderBy("Int").Reverse().Find(&list)
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 6)
|
|
for i, j := 0, 0; i < 6; i, j = i+1, j+1 {
|
|
if i == 4 {
|
|
j--
|
|
}
|
|
require.Equal(t, 5-j, list[i].Int)
|
|
}
|
|
|
|
list = nil
|
|
err = db.Select().OrderBy("Int").Reverse().Limit(2).Find(&list)
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 2)
|
|
for i := 0; i < 2; i++ {
|
|
require.Equal(t, 5-i, list[i].Int)
|
|
}
|
|
|
|
list = nil
|
|
err = db.Select().OrderBy("Int").Reverse().Skip(2).Find(&list)
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 4)
|
|
for i, j := 0, 0; i < 3; i, j = i+1, j+1 {
|
|
if i == 2 {
|
|
j--
|
|
}
|
|
require.Equal(t, 3-j, list[i].Int)
|
|
}
|
|
|
|
list = nil
|
|
err = db.Select().OrderBy("Int").Reverse().Skip(5).Limit(2).Find(&list)
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 1)
|
|
require.Equal(t, 1, list[0].Int)
|
|
|
|
list = nil
|
|
err = db.Select().OrderBy("Str", "Int").Find(&list)
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 6)
|
|
require.Equal(t, "a", list[0].Str)
|
|
require.Equal(t, 4, list[0].Int)
|
|
require.Equal(t, "b", list[1].Str)
|
|
require.Equal(t, 3, list[1].Int)
|
|
require.Equal(t, "c", list[2].Str)
|
|
require.Equal(t, 2, list[2].Int)
|
|
require.Equal(t, "d", list[3].Str)
|
|
require.Equal(t, 1, list[3].Int)
|
|
require.Equal(t, "d", list[4].Str)
|
|
require.Equal(t, 5, list[4].Int)
|
|
require.Equal(t, "e", list[5].Str)
|
|
require.Equal(t, 2, list[5].Int)
|
|
}
|
|
|
|
func TestSelectFirst(t *testing.T) {
|
|
db, cleanup := prepareScoreDB(t)
|
|
defer cleanup()
|
|
|
|
var score Score
|
|
|
|
err := db.Select(q.Or(
|
|
q.Eq("Value", 5),
|
|
q.Or(
|
|
q.Lte("Value", 2),
|
|
q.Gte("Value", 18),
|
|
),
|
|
)).Skip(2).First(&score)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 2, score.Value)
|
|
|
|
err = db.Select(q.Or(
|
|
q.Eq("Value", 5),
|
|
q.Or(
|
|
q.Lte("Value", 2),
|
|
q.Gte("Value", 18),
|
|
),
|
|
)).Skip(1).Reverse().First(&score)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 18, score.Value)
|
|
}
|
|
|
|
func TestSelectFirstOrderBy(t *testing.T) {
|
|
db, cleanup := createDB(t)
|
|
defer cleanup()
|
|
|
|
type T struct {
|
|
ID int `storm:"increment"`
|
|
Str string
|
|
Int int
|
|
}
|
|
|
|
strs := []string{"e", "b", "a", "c", "d"}
|
|
ints := []int{2, 3, 1, 4, 5}
|
|
for i := 0; i < 5; i++ {
|
|
err := db.Save(&T{
|
|
Str: strs[i],
|
|
Int: ints[i],
|
|
})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
var record T
|
|
err := db.Select().OrderBy("ID").First(&record)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, record.ID)
|
|
|
|
err = db.Select().OrderBy("Str").First(&record)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "a", record.Str)
|
|
|
|
err = db.Select().OrderBy("Int").First(&record)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, record.Int)
|
|
|
|
err = db.Select().OrderBy("Int").Reverse().First(&record)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 5, record.Int)
|
|
|
|
err = db.Select().OrderBy("Int").Reverse().Limit(2).First(&record)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 5, record.Int)
|
|
|
|
err = db.Select().OrderBy("Int").Reverse().Skip(2).First(&record)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 3, record.Int)
|
|
|
|
err = db.Select().OrderBy("Int").Reverse().Skip(4).Limit(2).First(&record)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, record.Int)
|
|
}
|
|
|
|
func TestSelectDelete(t *testing.T) {
|
|
db, cleanup := prepareScoreDB(t)
|
|
defer cleanup()
|
|
|
|
err := db.Select(q.Or(
|
|
q.Eq("Value", 5),
|
|
q.Or(
|
|
q.Lte("Value", 2),
|
|
q.Gte("Value", 18),
|
|
),
|
|
)).Skip(2).Delete(&Score{})
|
|
require.NoError(t, err)
|
|
|
|
var scores []Score
|
|
err = db.Select(q.Or(
|
|
q.Eq("Value", 5),
|
|
q.Or(
|
|
q.Lte("Value", 2),
|
|
q.Gte("Value", 18),
|
|
),
|
|
)).Find(&scores)
|
|
require.NoError(t, err)
|
|
require.Len(t, scores, 2)
|
|
require.Equal(t, 0, scores[0].Value)
|
|
require.Equal(t, 1, scores[1].Value)
|
|
|
|
for i := 0; i < 10; i++ {
|
|
w := User{ID: i + 1, Name: fmt.Sprintf("John%d", i+1)}
|
|
err = db.Save(&w)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
err = db.Select(q.Gte("ID", 5)).Delete(&User{})
|
|
require.NoError(t, err)
|
|
|
|
var user User
|
|
err = db.One("Name", "John6", &user)
|
|
require.Error(t, err)
|
|
require.Equal(t, ErrNotFound, err)
|
|
|
|
err = db.One("Name", "John4", &user)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestSelectCount(t *testing.T) {
|
|
db, cleanup := prepareScoreDB(t)
|
|
defer cleanup()
|
|
|
|
total, err := db.Select(q.Or(
|
|
q.Eq("Value", 5),
|
|
q.Or(
|
|
q.Lte("Value", 2),
|
|
q.Gte("Value", 18),
|
|
),
|
|
)).Count(&Score{})
|
|
require.NoError(t, err)
|
|
require.Equal(t, 6, total)
|
|
|
|
total, err = db.Select(q.Or(
|
|
q.Eq("Value", 5),
|
|
q.Or(
|
|
q.Lte("Value", 2),
|
|
q.Gte("Value", 18),
|
|
),
|
|
)).Skip(2).Count(&Score{})
|
|
require.NoError(t, err)
|
|
require.Equal(t, 4, total)
|
|
|
|
total, err = db.Select(q.Or(
|
|
q.Eq("Value", 5),
|
|
q.Or(
|
|
q.Lte("Value", 2),
|
|
q.Gte("Value", 18),
|
|
),
|
|
)).Skip(2).Limit(2).Count(&Score{})
|
|
require.NoError(t, err)
|
|
require.Equal(t, 2, total)
|
|
|
|
total, err = db.Select(q.Or(
|
|
q.Eq("Value", 5),
|
|
q.Or(
|
|
q.Lte("Value", 2),
|
|
q.Gte("Value", 18),
|
|
),
|
|
)).Skip(5).Limit(2).Count(&Score{})
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, total)
|
|
}
|
|
|
|
func TestSelectRaw(t *testing.T) {
|
|
db, cleanup := createDB(t, Codec(json.Codec))
|
|
defer cleanup()
|
|
|
|
for i := 0; i < 20; i++ {
|
|
err := db.Save(&Score{
|
|
Value: i,
|
|
})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
list, err := db.Select().Bucket("Score").Raw()
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 20)
|
|
|
|
list, err = db.Select().Bucket("Score").Skip(18).Limit(5).Raw()
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 2)
|
|
|
|
i := 0
|
|
err = db.Select().Bucket("Score").Skip(18).Limit(5).RawEach(func(k []byte, v []byte) error {
|
|
i++
|
|
return nil
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, i, 2)
|
|
}
|
|
|
|
func TestSelectEach(t *testing.T) {
|
|
db, cleanup := createDB(t, Codec(json.Codec))
|
|
defer cleanup()
|
|
|
|
for i := 0; i < 20; i++ {
|
|
err := db.Save(&Score{
|
|
Value: i,
|
|
})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
i := 0
|
|
err := db.Select().Each(new(Score), func(record interface{}) error {
|
|
s, ok := record.(*Score)
|
|
require.True(t, ok)
|
|
require.Equal(t, i, s.Value)
|
|
i++
|
|
return nil
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, 20, i)
|
|
|
|
i = 0
|
|
err = db.Select().Skip(18).Limit(5).Each(new(Score), func(record interface{}) error {
|
|
s, ok := record.(*Score)
|
|
require.True(t, ok)
|
|
require.Equal(t, i+18, s.Value)
|
|
i++
|
|
return nil
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, 2, i)
|
|
}
|