2019-01-24 20:15:10 +00:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
2018-09-05 17:10:35 +01:00
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package storage
|
|
|
|
|
2018-09-07 15:20:15 +01:00
|
|
|
import (
|
2019-06-05 15:23:10 +01:00
|
|
|
"context"
|
2018-09-07 15:20:15 +01:00
|
|
|
)
|
2018-09-05 17:10:35 +01:00
|
|
|
|
|
|
|
// ListOptions are items that are optional for the LIST method
|
|
|
|
type ListOptions struct {
|
|
|
|
Prefix Key
|
|
|
|
StartAfter Key // StartAfter is relative to Prefix
|
|
|
|
Recursive bool
|
|
|
|
IncludeValue bool
|
2018-09-07 15:20:15 +01:00
|
|
|
Limit int
|
2018-09-05 17:10:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ListV2 lists all keys corresponding to ListOptions
|
2018-09-07 10:00:00 +01:00
|
|
|
// limit is capped to LookupLimit
|
2018-09-07 15:20:15 +01:00
|
|
|
//
|
|
|
|
// more indicates if the result was truncated. If false
|
|
|
|
// then the result []ListItem includes all requested keys.
|
|
|
|
// If true then the caller must call List again to get more
|
2019-09-25 22:30:41 +01:00
|
|
|
// results by setting `StartAfter` appropriately.
|
2019-06-05 15:23:10 +01:00
|
|
|
func ListV2(ctx context.Context, store KeyValueStore, opts ListOptions) (result Items, more bool, err error) {
|
|
|
|
defer mon.Task()(&ctx)(&err)
|
2018-09-05 17:10:35 +01:00
|
|
|
|
|
|
|
limit := opts.Limit
|
2018-09-07 15:20:15 +01:00
|
|
|
if limit <= 0 || limit > LookupLimit {
|
|
|
|
limit = LookupLimit
|
2018-09-05 17:10:35 +01:00
|
|
|
}
|
|
|
|
|
2018-09-07 15:20:15 +01:00
|
|
|
more = true
|
2018-09-05 17:10:35 +01:00
|
|
|
|
2019-09-25 22:30:41 +01:00
|
|
|
first := opts.StartAfter
|
2019-06-05 15:23:10 +01:00
|
|
|
iterate := func(ctx context.Context, it Iterator) error {
|
2018-09-05 17:10:35 +01:00
|
|
|
var item ListItem
|
|
|
|
skipFirst := true
|
|
|
|
for ; limit > 0; limit-- {
|
2019-06-05 15:23:10 +01:00
|
|
|
if !it.Next(ctx, &item) {
|
2018-09-05 17:10:35 +01:00
|
|
|
more = false
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
relativeKey := item.Key[len(opts.Prefix):]
|
|
|
|
if skipFirst {
|
|
|
|
skipFirst = false
|
|
|
|
if relativeKey.Equal(first) {
|
|
|
|
// skip the first element in iteration
|
|
|
|
// if it matches the search key
|
|
|
|
limit++
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if opts.IncludeValue {
|
|
|
|
result = append(result, ListItem{
|
|
|
|
Key: CloneKey(relativeKey),
|
|
|
|
Value: CloneValue(item.Value),
|
|
|
|
IsPrefix: item.IsPrefix,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
result = append(result, ListItem{
|
|
|
|
Key: CloneKey(relativeKey),
|
|
|
|
IsPrefix: item.IsPrefix,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2018-09-07 15:20:15 +01:00
|
|
|
|
|
|
|
// we still need to consume one item for the more flag
|
2019-06-05 15:23:10 +01:00
|
|
|
more = it.Next(ctx, &item)
|
2018-09-05 17:10:35 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var firstFull Key
|
2019-09-25 22:30:41 +01:00
|
|
|
if !opts.StartAfter.IsZero() {
|
2018-09-05 17:10:35 +01:00
|
|
|
firstFull = joinKey(opts.Prefix, opts.StartAfter)
|
|
|
|
}
|
2019-06-05 15:23:10 +01:00
|
|
|
err = store.Iterate(ctx, IterateOptions{
|
2018-09-05 17:10:35 +01:00
|
|
|
Prefix: opts.Prefix,
|
|
|
|
First: firstFull,
|
|
|
|
Recurse: opts.Recursive,
|
|
|
|
}, iterate)
|
|
|
|
|
|
|
|
return result, more, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func joinKey(a, b Key) Key {
|
|
|
|
return append(append(Key{}, a...), b...)
|
|
|
|
}
|