From 516d7b3486df2062f0900aa39ec17d343a381846 Mon Sep 17 00:00:00 2001 From: Johan Brandhorst-Satzkorn Date: Wed, 1 Nov 2023 21:14:50 -0700 Subject: [PATCH] internal/storage: support pagination for storage buckets --- internal/storage/plugin/options.go | 32 ++++++++++++++++------- internal/storage/plugin/options_test.go | 24 +++++++++++++++++ internal/storage/plugin/storage_bucket.go | 16 ++++++++++++ 3 files changed, 62 insertions(+), 10 deletions(-) diff --git a/internal/storage/plugin/options.go b/internal/storage/plugin/options.go index 40c0fa6ed..473c1463c 100644 --- a/internal/storage/plugin/options.go +++ b/internal/storage/plugin/options.go @@ -3,7 +3,10 @@ package plugin -import "google.golang.org/protobuf/types/known/structpb" +import ( + "github.com/hashicorp/boundary/internal/pagination" + "google.golang.org/protobuf/types/known/structpb" +) const ( // DefaultChunkSize is the default chunk size for streaming @@ -24,15 +27,16 @@ type Option func(*options) // options = how options are represented type options struct { - withChunkSize uint32 - withName string - withDescription string - withAttributes *structpb.Struct - withSecrets *structpb.Struct - withWorkerFilter string - withBucketPrefix string - withLimit int - withVersion uint32 + withChunkSize uint32 + withName string + withDescription string + withAttributes *structpb.Struct + withSecrets *structpb.Struct + withWorkerFilter string + withBucketPrefix string + withLimit int + withVersion uint32 + withStartPageAfterItem pagination.Item } func getDefaultOptions() options { @@ -111,3 +115,11 @@ func WithVersion(v uint32) Option { o.withVersion = v } } + +// WithStartPageAfterItem is used to paginate over the results. +// The next page will start after the provided item. +func WithStartPageAfterItem(item pagination.Item) Option { + return func(o *options) { + o.withStartPageAfterItem = item + } +} diff --git a/internal/storage/plugin/options_test.go b/internal/storage/plugin/options_test.go index c7b26184a..4fb113191 100644 --- a/internal/storage/plugin/options_test.go +++ b/internal/storage/plugin/options_test.go @@ -5,11 +5,28 @@ package plugin import ( "testing" + "time" + "github.com/hashicorp/boundary/internal/db/timestamp" + "github.com/hashicorp/boundary/internal/pagination" "github.com/stretchr/testify/assert" "google.golang.org/protobuf/types/known/structpb" ) +type fakeItem struct { + pagination.Item + publicId string + updateTime time.Time +} + +func (p *fakeItem) GetPublicId() string { + return p.publicId +} + +func (p *fakeItem) GetUpdateTime() *timestamp.Timestamp { + return timestamp.New(p.updateTime) +} + func Test_GetOpts(t *testing.T) { t.Parallel() t.Run("WithChunkSize", func(t *testing.T) { @@ -68,4 +85,11 @@ func Test_GetOpts(t *testing.T) { testOpts.withLimit = 12345 assert.Equal(t, opts, testOpts) }) + t.Run("WithStartPageAfterItem", func(t *testing.T) { + t.Parallel() + updateTime := time.Now() + opts := getOpts(WithStartPageAfterItem(&fakeItem{nil, "s_1", updateTime})) + assert.Equal(t, opts.withStartPageAfterItem.GetPublicId(), "s_1") + assert.Equal(t, opts.withStartPageAfterItem.GetUpdateTime(), timestamp.New(updateTime)) + }) } diff --git a/internal/storage/plugin/storage_bucket.go b/internal/storage/plugin/storage_bucket.go index 7a3bc42dd..275e24718 100644 --- a/internal/storage/plugin/storage_bucket.go +++ b/internal/storage/plugin/storage_bucket.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/boundary/internal/libs/crypto" "github.com/hashicorp/boundary/internal/oplog" "github.com/hashicorp/boundary/internal/storage/plugin/store" + "github.com/hashicorp/boundary/internal/types/resource" "github.com/hashicorp/boundary/internal/util" "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/storagebuckets" wrapping "github.com/hashicorp/go-kms-wrapping/v2" @@ -65,6 +66,11 @@ func (s *StorageBucket) SetTableName(n string) { s.tableName = n } +// GetResourceType implements the boundary.Resource interface. +func (s *StorageBucket) GetResourceType() resource.Type { + return resource.StorageBucket +} + func (s *StorageBucket) oplog(op oplog.OpType) oplog.Metadata { metadata := oplog.Metadata{ "resource-public-id": []string{s.PublicId}, @@ -252,3 +258,13 @@ func (sba *storageBucketAgg) toStorageBucketAndSecret() (*StorageBucket, *Storag } return sb, sbs } + +type deletedStorageBucket struct { + PublicId string `gorm:"primary_key"` + DeleteTime *timestamp.Timestamp +} + +// TableName returns the tablename to override the default gorm table name +func (s *deletedStorageBucket) TableName() string { + return "storage_plugin_storage_bucket_deleted" +}