Skip to content
Permalink
Browse files
feat(storage): add projection parameter for BucketHandle.Objects() (#…
…3549)



Co-authored-by: Chris Cotter <cjcotter@google.com>
  • Loading branch information
ava12 and tritone committed Jan 22, 2021
1 parent 6ccef89 commit 9b9c3dce3ee10af5b6c4d070821bf47a861efd5b
Showing with 72 additions and 1 deletion.
  1. +5 −1 storage/bucket.go
  2. +37 −0 storage/integration_test.go
  3. +30 −0 storage/storage.go
@@ -1204,7 +1204,11 @@ func (it *ObjectIterator) Next() (*ObjectAttrs, error) {
func (it *ObjectIterator) fetch(pageSize int, pageToken string) (string, error) {
req := it.bucket.c.raw.Objects.List(it.bucket.name)
setClientHeader(req.Header())
req.Projection("full")
projection := it.query.Projection
if projection == ProjectionDefault {
projection = ProjectionFull
}
req.Projection(projection.String())
req.Delimiter(it.query.Delimiter)
req.Prefix(it.query.Prefix)
req.StartOffset(it.query.StartOffset)
@@ -698,6 +698,7 @@ func TestIntegration_Objects(t *testing.T) {
testObjectsIterateSelectedAttrs(t, bkt, objects)
testObjectsIterateAllSelectedAttrs(t, bkt, objects)
testObjectIteratorWithOffset(t, bkt, objects)
testObjectsIterateWithProjection(t, bkt)
t.Run("testObjectsIterateSelectedAttrsDelimiter", func(t *testing.T) {
query := &Query{Prefix: "", Delimiter: "/"}
if err := query.SetAttrSelection([]string{"Name"}); err != nil {
@@ -1236,6 +1237,42 @@ func testObjectsIterateAllSelectedAttrs(t *testing.T, bkt *BucketHandle, objects
}
}

func testObjectsIterateWithProjection(t *testing.T, bkt *BucketHandle) {
projections := map[Projection]bool{
ProjectionDefault: true,
ProjectionFull: true,
ProjectionNoACL: false,
}

for projection, expectACL := range projections {
query := &Query{Projection: projection}
it := bkt.Objects(context.Background(), query)
attrs, err := it.Next()
if err == iterator.Done {
t.Fatalf("iterator: no objects")
}
if err != nil {
t.Fatalf("iterator.Next: %v", err)
}

if expectACL {
if attrs.Owner == "" {
t.Errorf("projection %q: Owner is empty, want nonempty Owner", projection)
}
if len(attrs.ACL) == 0 {
t.Errorf("projection %q: ACL is empty, want at least one ACL rule", projection)
}
} else {
if attrs.Owner != "" {
t.Errorf("projection %q: got Owner = %q, want empty Owner", projection, attrs.Owner)
}
if len(attrs.ACL) != 0 {
t.Errorf("projection %q: got %d ACL rules, want empty ACL", projection, len(attrs.ACL))
}
}
}
}

func TestIntegration_SignedURL(t *testing.T) {
if testing.Short() { // do not test during replay
t.Skip("Integration tests skipped in short mode")
@@ -1306,6 +1306,31 @@ func encodeUint32(u uint32) string {
return base64.StdEncoding.EncodeToString(b)
}

// Projection is enumerated type for Query.Projection.
type Projection int

const (
// ProjectionDefault returns all fields of objects.
ProjectionDefault Projection = iota

// ProjectionFull returns all fields of objects.
ProjectionFull

// ProjectionNoACL returns all fields of objects except for Owner and ACL.
ProjectionNoACL
)

func (p Projection) String() string {
switch p {
case ProjectionFull:
return "full"
case ProjectionNoACL:
return "noAcl"
default:
return ""
}
}

// Query represents a query to filter objects from a bucket.
type Query struct {
// Delimiter returns results in a directory-like fashion.
@@ -1341,6 +1366,11 @@ type Query struct {
// lexicographically before endOffset. If startOffset is also set, the objects
// listed will have names between startOffset (inclusive) and endOffset (exclusive).
EndOffset string

// Projection defines the set of properties to return. It will default to ProjectionFull,
// which returns all properties. Passing ProjectionNoACL will omit Owner and ACL,
// which may improve performance when listing many objects.
Projection Projection
}

// attrToFieldMap maps the field names of ObjectAttrs to the underlying field

0 comments on commit 9b9c3dc

Please sign in to comment.