mirror of
https://github.com/chaisql/chai.git
synced 2025-09-26 19:51:21 +08:00
add tree iterator
This commit is contained in:
@@ -43,10 +43,8 @@ func ExecSQL(ctx context.Context, db *chai.DB, r io.Reader, w io.Writer) error {
|
||||
}
|
||||
|
||||
err = res.Iterate(func(r database.Row) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
if err := ctx.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return enc.Encode(r)
|
||||
|
@@ -166,7 +166,6 @@ func (sh *Shell) runExecutor(ctx context.Context, promptExecCh chan queryTask) e
|
||||
continue
|
||||
}
|
||||
|
||||
// if showtime is true, ensure it's a query, and it was executed.
|
||||
if displayTime {
|
||||
fmt.Fprintf(input.w, "Time: %s\n", time.Since(start))
|
||||
}
|
||||
|
@@ -279,11 +279,9 @@ func (rs *Rows) iterate(ctx context.Context) {
|
||||
if errors.Is(err, errStop) || err == nil {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
rs.c <- Row{
|
||||
err: err,
|
||||
}
|
||||
return
|
||||
|
||||
rs.c <- Row{
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
|
16
go.work.sum
16
go.work.sum
@@ -169,6 +169,7 @@ github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20190129172621-c8b1d7a94ddf
|
||||
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
|
||||
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
|
||||
github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM=
|
||||
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM=
|
||||
github.com/aclements/go-gg v0.0.0-20170118225347-6dbb4e4fefb0/go.mod h1:55qNq4vcpkIuHowELi5C8e+1yUHtoLoOUR9QU5j7Tes=
|
||||
@@ -188,6 +189,7 @@ github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHG
|
||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
|
||||
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
@@ -205,16 +207,7 @@ github.com/charmbracelet/bubbletea v1.3.4/go.mod h1:dtcUCyCGEX3g9tosuYiut3MXgY/J
|
||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
|
||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
|
||||
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
|
||||
github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo=
|
||||
github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
|
||||
github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
|
||||
github.com/charmbracelet/x/ansi v0.9.3 h1:BXt5DHS/MKF+LjuK4huWrC6NCvHtexww7dMayh6GXd0=
|
||||
github.com/charmbracelet/x/ansi v0.9.3/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
|
||||
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
@@ -239,6 +232,7 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
|
||||
github.com/djherbis/atime v1.1.0/go.mod h1:28OF6Y8s3NQWwacXc5eZTsEsiMzp7LF8MbXE+XJPdBE=
|
||||
github.com/dromara/carbon/v2 v2.3.12/go.mod h1:HNsedGzXGuNciZImYP2OMnpiwq/vhIstR/vn45ib5cI=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
@@ -722,8 +716,6 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -791,8 +783,6 @@ golang.org/x/telemetry v0.0.0-20250807160809-1a19826ec488/go.mod h1:fGb/2+tgXXjh
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
||||
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
|
@@ -79,20 +79,24 @@ func (idx *Index) Exists(vs []types.Value) (bool, *tree.Key, error) {
|
||||
var found bool
|
||||
var dKey *tree.Key
|
||||
|
||||
err := idx.Tree.IterateOnRange(&tree.Range{Min: seek, Max: seek}, false, func(k *tree.Key, _ []byte) error {
|
||||
values, err := k.Decode()
|
||||
it, err := idx.Tree.Iterator(&tree.Range{Min: seek, Max: seek})
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
defer it.Close()
|
||||
|
||||
for it.First(); it.Valid(); it.Next() {
|
||||
k, err := it.Key().Decode()
|
||||
if err != nil {
|
||||
return err
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
dKey = tree.NewEncodedKey(types.AsByteSlice(values[len(values)-1]))
|
||||
dKey = tree.NewEncodedKey(types.AsByteSlice(k[len(k)-1]))
|
||||
found = true
|
||||
return errStop
|
||||
})
|
||||
if err == errStop {
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
return found, dKey, err
|
||||
|
||||
return found, dKey, it.Error()
|
||||
}
|
||||
|
||||
// Delete all the references to the key from the index.
|
||||
@@ -132,11 +136,20 @@ func (idx *Index) IterateOnRange(rng *tree.Range, reverse bool, fn func(key *tre
|
||||
}
|
||||
|
||||
func (idx *Index) iterateOnRange(rng *tree.Range, reverse bool, fn func(itmKey *tree.Key, key *tree.Key) error) error {
|
||||
return idx.Tree.IterateOnRange(rng, reverse, idx.iterator(fn))
|
||||
}
|
||||
it, err := idx.Tree.Iterator(rng)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer it.Close()
|
||||
|
||||
func (idx *Index) iterator(fn func(itmKey *tree.Key, key *tree.Key) error) func(k *tree.Key, d []byte) error {
|
||||
return func(k *tree.Key, _ []byte) error {
|
||||
if !reverse {
|
||||
it.First()
|
||||
} else {
|
||||
it.Last()
|
||||
}
|
||||
|
||||
for it.Valid() {
|
||||
k := it.Key()
|
||||
// we don't care about the value, we just want to extract the key
|
||||
// which is the last element of the encoded array
|
||||
values, err := k.Decode()
|
||||
@@ -146,8 +159,19 @@ func (idx *Index) iterator(fn func(itmKey *tree.Key, key *tree.Key) error) func(
|
||||
|
||||
pk := tree.NewEncodedKey(types.AsByteSlice(values[len(values)-1]))
|
||||
|
||||
return fn(k, pk)
|
||||
err = fn(k, pk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !reverse {
|
||||
it.Next()
|
||||
} else {
|
||||
it.Prev()
|
||||
}
|
||||
}
|
||||
|
||||
return it.Error()
|
||||
}
|
||||
|
||||
// Truncate deletes all the index data.
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
type Row interface {
|
||||
// Iterate goes through all the fields of the row and calls the given function
|
||||
// Iterate goes through all the columns of the row and calls the given function
|
||||
// by passing the column name
|
||||
Iterate(fn func(column string, value types.Value) error) error
|
||||
|
||||
|
@@ -36,7 +36,7 @@ func (t *Table) Insert(r row.Row) (*tree.Key, Row, error) {
|
||||
return nil, nil, errors.New("cannot write to read-only table")
|
||||
}
|
||||
|
||||
key, isRowid, err := t.generateKey(t.Info, r)
|
||||
key, isRowid, err := t.generateKey(r)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -167,11 +167,39 @@ func (t *Table) IterateOnRange(rng *Range, reverse bool, fn func(key *tree.Key,
|
||||
Row: &e,
|
||||
}
|
||||
|
||||
return t.Tree.IterateOnRange(r, reverse, func(k *tree.Key, enc []byte) error {
|
||||
it, err := t.Tree.Iterator(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer it.Close()
|
||||
|
||||
if reverse {
|
||||
it.Last()
|
||||
} else {
|
||||
it.First()
|
||||
}
|
||||
|
||||
for it.Valid() {
|
||||
k := it.Key()
|
||||
enc, err := it.Value()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
row.key = k
|
||||
e.encoded = enc
|
||||
return fn(k, &row)
|
||||
})
|
||||
if err := fn(k, &row); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if reverse {
|
||||
it.Prev()
|
||||
} else {
|
||||
it.Next()
|
||||
}
|
||||
}
|
||||
|
||||
return it.Error()
|
||||
}
|
||||
|
||||
// GetRow returns one row by key.
|
||||
@@ -198,7 +226,7 @@ func (t *Table) GetRow(key *tree.Key) (Row, error) {
|
||||
// if there are no primary key in the table, a default
|
||||
// key is generated, called the rowid.
|
||||
// It returns a boolean indicating whether the key is a rowid or not.
|
||||
func (t *Table) generateKey(info *TableInfo, r row.Row) (*tree.Key, bool, error) {
|
||||
func (t *Table) generateKey(r row.Row) (*tree.Key, bool, error) {
|
||||
if pk := t.Info.PrimaryKey; pk != nil {
|
||||
vs := make([]types.Value, 0, len(pk.Columns))
|
||||
for _, c := range pk.Columns {
|
||||
|
@@ -4,7 +4,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/chaisql/chai/internal/testutil"
|
||||
"github.com/chaisql/chai/internal/tree"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -71,11 +70,14 @@ func TestReIndex(t *testing.T) {
|
||||
}
|
||||
|
||||
i := 0
|
||||
err = idx.Tree.IterateOnRange(nil, false, func(*tree.Key, []byte) error {
|
||||
i++
|
||||
return nil
|
||||
})
|
||||
it, err := idx.Tree.Iterator(nil)
|
||||
require.NoError(t, err)
|
||||
defer it.Close()
|
||||
|
||||
for it.First(); it.Valid(); it.Next() {
|
||||
i++
|
||||
}
|
||||
require.NoError(t, it.Error())
|
||||
if shouldBeIndexed {
|
||||
require.Equal(t, 2, i)
|
||||
} else {
|
||||
|
@@ -113,7 +113,26 @@ func (op *TempTreeSortOperator) Iterate(in *environment.Environment, fn func(out
|
||||
var newEnv environment.Environment
|
||||
newEnv.SetOuter(in)
|
||||
var br database.BasicRow
|
||||
return tr.IterateOnRange(nil, op.Desc, func(k *tree.Key, data []byte) error {
|
||||
|
||||
it, err := tr.Iterator(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer it.Close()
|
||||
|
||||
if op.Desc {
|
||||
it.Last()
|
||||
} else {
|
||||
it.First()
|
||||
}
|
||||
|
||||
for it.Valid() {
|
||||
k := it.Key()
|
||||
data, err := it.Value()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
kv, err := k.Decode()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -137,8 +156,19 @@ func (op *TempTreeSortOperator) Iterate(in *environment.Environment, fn func(out
|
||||
|
||||
newEnv.SetRow(&br)
|
||||
|
||||
return fn(&newEnv)
|
||||
})
|
||||
err = fn(&newEnv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if op.Desc {
|
||||
it.Prev()
|
||||
} else {
|
||||
it.Next()
|
||||
}
|
||||
}
|
||||
|
||||
return it.Error()
|
||||
}
|
||||
|
||||
func (op *TempTreeSortOperator) String() string {
|
||||
|
@@ -43,7 +43,7 @@ func (it *UnionOperator) Columns(env *environment.Environment) ([]string, error)
|
||||
}
|
||||
|
||||
// Iterate iterates over all the streams and returns their union.
|
||||
func (it *UnionOperator) Iterate(in *environment.Environment, fn func(out *environment.Environment) error) (err error) {
|
||||
func (op *UnionOperator) Iterate(in *environment.Environment, fn func(out *environment.Environment) error) (err error) {
|
||||
var temp *tree.Tree
|
||||
var cleanup func() error
|
||||
|
||||
@@ -60,7 +60,7 @@ func (it *UnionOperator) Iterate(in *environment.Environment, fn func(out *envir
|
||||
// to deduplicate them
|
||||
var buf []byte
|
||||
|
||||
for _, s := range it.Streams {
|
||||
for _, s := range op.Streams {
|
||||
err := s.Iterate(in, func(out *environment.Environment) error {
|
||||
buf = buf[:0]
|
||||
|
||||
@@ -123,8 +123,21 @@ func (it *UnionOperator) Iterate(in *environment.Environment, fn func(out *envir
|
||||
newEnv.SetOuter(in)
|
||||
|
||||
var basicRow database.BasicRow
|
||||
|
||||
// iterate over the temporary index
|
||||
return temp.IterateOnRange(nil, false, func(key *tree.Key, value []byte) error {
|
||||
it, err := temp.Iterator(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer it.Close()
|
||||
|
||||
for it.First(); it.Valid(); it.Next() {
|
||||
key := it.Key()
|
||||
value, err := it.Value()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
kv, err := key.Decode()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -144,8 +157,13 @@ func (it *UnionOperator) Iterate(in *environment.Environment, fn func(out *envir
|
||||
basicRow.ResetWith(tableName, pk, obj)
|
||||
|
||||
newEnv.SetRow(&basicRow)
|
||||
return fn(&newEnv)
|
||||
})
|
||||
err = fn(&newEnv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return it.Error()
|
||||
}
|
||||
|
||||
func (it *UnionOperator) String() string {
|
||||
|
@@ -76,12 +76,16 @@ func NewTransient(session engine.Session, ns Namespace, order SortOrder) (*Tree,
|
||||
}
|
||||
|
||||
// ensure the namespace is not in use
|
||||
err := t.IterateOnRange(nil, false, func(k *Key, b []byte) error {
|
||||
return errors.Errorf("namespace %d is already in use", ns)
|
||||
})
|
||||
it, err := t.Iterator(nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer it.Close()
|
||||
|
||||
it.First()
|
||||
if it.Valid() {
|
||||
return nil, nil, errors.Errorf("namespace %d is already in use", ns)
|
||||
}
|
||||
|
||||
return &t, t.Truncate, nil
|
||||
}
|
||||
@@ -163,8 +167,19 @@ func (t *Tree) Truncate() error {
|
||||
return t.Session.DeleteRange(encoding.EncodeInt(nil, int64(t.Namespace)), encoding.EncodeInt(nil, int64(t.Namespace)+1))
|
||||
}
|
||||
|
||||
// IterateOnRange iterates on all keys that are in the given range.
|
||||
func (t *Tree) IterateOnRange(rng *Range, reverse bool, fn func(*Key, []byte) error) error {
|
||||
type Iterator struct {
|
||||
engine.Iterator
|
||||
k Key
|
||||
}
|
||||
|
||||
func (it *Iterator) Key() *Key {
|
||||
it.k.Encoded = it.Iterator.Key()
|
||||
it.k.values = nil
|
||||
|
||||
return &it.k
|
||||
}
|
||||
|
||||
func (t *Tree) Iterator(rng *Range) (*Iterator, error) {
|
||||
var start, end []byte
|
||||
var err error
|
||||
|
||||
@@ -186,7 +201,7 @@ func (t *Tree) IterateOnRange(rng *Range, reverse bool, fn func(*Key, []byte) er
|
||||
start, end, err = t.buildExclusiveBoundaries(min, max, desc)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
opts := engine.IterOptions{
|
||||
@@ -195,42 +210,12 @@ func (t *Tree) IterateOnRange(rng *Range, reverse bool, fn func(*Key, []byte) er
|
||||
}
|
||||
it, err := t.Session.Iterator(&opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer it.Close()
|
||||
|
||||
if !reverse {
|
||||
it.First()
|
||||
} else {
|
||||
it.Last()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var k Key
|
||||
for it.Valid() {
|
||||
k.Encoded = it.Key()
|
||||
k.values = nil
|
||||
|
||||
v, err := it.Value()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(v) == 0 || v[0] == 0 {
|
||||
v = nil
|
||||
}
|
||||
|
||||
err = fn(&k, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !reverse {
|
||||
it.Next()
|
||||
} else {
|
||||
it.Prev()
|
||||
}
|
||||
}
|
||||
|
||||
return it.Error()
|
||||
return &Iterator{
|
||||
Iterator: it,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *Tree) isDescRange(rng *Range) bool {
|
||||
@@ -248,7 +233,7 @@ func (t *Tree) buildInclusiveBoundaries(min, max *Key, desc bool) (start []byte,
|
||||
if min == nil {
|
||||
start, err = t.buildMinKeyForType(max, desc)
|
||||
} else {
|
||||
start, err = t.buildStartKeyInclusive(min, desc)
|
||||
start, err = t.buildStartKeyInclusive(min)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
@@ -256,7 +241,7 @@ func (t *Tree) buildInclusiveBoundaries(min, max *Key, desc bool) (start []byte,
|
||||
if max == nil {
|
||||
end, err = t.buildMaxKeyForType(min, desc)
|
||||
} else {
|
||||
end, err = t.buildEndKeyInclusive(max, desc)
|
||||
end, err = t.buildEndKeyInclusive(max)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -265,7 +250,7 @@ func (t *Tree) buildExclusiveBoundaries(min, max *Key, desc bool) (start []byte,
|
||||
if min == nil {
|
||||
start, err = t.buildMinKeyForType(max, desc)
|
||||
} else {
|
||||
start, err = t.buildStartKeyExclusive(min, desc)
|
||||
start, err = t.buildStartKeyExclusive(min)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
@@ -273,7 +258,7 @@ func (t *Tree) buildExclusiveBoundaries(min, max *Key, desc bool) (start []byte,
|
||||
if max == nil {
|
||||
end, err = t.buildMaxKeyForType(min, desc)
|
||||
} else {
|
||||
end, err = t.buildEndKeyExclusive(max, desc)
|
||||
end, err = t.buildEndKeyExclusive(max)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -343,11 +328,11 @@ func (t *Tree) buildLastKey() []byte {
|
||||
return append(buf, 0xFF)
|
||||
}
|
||||
|
||||
func (t *Tree) buildStartKeyInclusive(key *Key, desc bool) ([]byte, error) {
|
||||
func (t *Tree) buildStartKeyInclusive(key *Key) ([]byte, error) {
|
||||
return key.Encode(t.Namespace, t.Order)
|
||||
}
|
||||
|
||||
func (t *Tree) buildStartKeyExclusive(key *Key, desc bool) ([]byte, error) {
|
||||
func (t *Tree) buildStartKeyExclusive(key *Key) ([]byte, error) {
|
||||
b, err := key.Encode(t.Namespace, t.Order)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -356,7 +341,7 @@ func (t *Tree) buildStartKeyExclusive(key *Key, desc bool) ([]byte, error) {
|
||||
return append(b, 0xFF), nil
|
||||
}
|
||||
|
||||
func (t *Tree) buildEndKeyInclusive(key *Key, desc bool) ([]byte, error) {
|
||||
func (t *Tree) buildEndKeyInclusive(key *Key) ([]byte, error) {
|
||||
b, err := key.Encode(t.Namespace, t.Order)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -365,7 +350,7 @@ func (t *Tree) buildEndKeyInclusive(key *Key, desc bool) ([]byte, error) {
|
||||
return append(b, 0xFF), nil
|
||||
}
|
||||
|
||||
func (t *Tree) buildEndKeyExclusive(key *Key, desc bool) ([]byte, error) {
|
||||
func (t *Tree) buildEndKeyExclusive(key *Key) ([]byte, error) {
|
||||
return key.Encode(t.Namespace, t.Order)
|
||||
}
|
||||
|
||||
|
@@ -106,10 +106,14 @@ func TestTreeTruncate(t *testing.T) {
|
||||
err = tr.Truncate()
|
||||
require.NoError(t, err)
|
||||
|
||||
err = tr.IterateOnRange(nil, false, func(k *tree.Key, b []byte) error {
|
||||
return fmt.Errorf("expected no keys")
|
||||
})
|
||||
it, err := tr.Iterator(nil)
|
||||
require.NoError(t, err)
|
||||
defer it.Close()
|
||||
|
||||
it.First()
|
||||
if it.Valid() {
|
||||
t.Errorf("expected no keys")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -321,11 +325,28 @@ func TestTreeIterateOnRange(t *testing.T) {
|
||||
|
||||
var results []string
|
||||
|
||||
err := tt.IterateOnRange(&rng, reversed, func(k *tree.Key, _ []byte) error {
|
||||
results = append(results, k.String())
|
||||
return nil
|
||||
})
|
||||
it, err := tt.Iterator(&rng)
|
||||
require.NoError(t, err)
|
||||
defer it.Close()
|
||||
|
||||
if reversed {
|
||||
it.Last()
|
||||
} else {
|
||||
it.First()
|
||||
}
|
||||
|
||||
for it.Valid() {
|
||||
k := it.Key()
|
||||
results = append(results, k.String())
|
||||
|
||||
if reversed {
|
||||
it.Prev()
|
||||
} else {
|
||||
it.Next()
|
||||
}
|
||||
}
|
||||
|
||||
require.NoError(t, it.Error())
|
||||
|
||||
var want []string
|
||||
if !reversed {
|
||||
|
Reference in New Issue
Block a user