From 30dbc4eefe1a53b4224c8379eba1e8e633939774 Mon Sep 17 00:00:00 2001 From: Leon Mika Date: Thu, 24 Mar 2022 15:44:57 +1100 Subject: [PATCH] sqs-browse: added notion of workspaces in sqs-browse Also added a tool to generate test tables --- cmd/sqs-browse/main.go | 17 ++++- go.mod | 4 + go.sum | 9 +++ .../common/ui/commandctrl/commandctrl_test.go | 2 +- .../controllers/tablewrite_test.go | 4 +- internal/dynamo-browse/models/modexpr/ast.go | 18 ++--- .../dynamo-browse/models/modexpr/astmods.go | 31 ++++++++ internal/dynamo-browse/models/modexpr/expr.go | 15 ++-- .../dynamo-browse/models/modexpr/expr_test.go | 16 ++++ internal/dynamo-browse/models/modexpr/mods.go | 19 +++++ .../dynamo-browse/models/modexpr/values.go | 15 ++++ internal/dynamo-browse/ui/model.go | 8 +- internal/sqs-browse/models/message.go | 6 +- .../sqs-browse/providers/memstore/memstore.go | 31 -------- .../providers/stormstore/memstore.go | 30 ++++++++ test/cmd/load-test-table/main.go | 74 +++++++++++++++++++ 16 files changed, 239 insertions(+), 60 deletions(-) create mode 100644 internal/dynamo-browse/models/modexpr/astmods.go create mode 100644 internal/dynamo-browse/models/modexpr/mods.go create mode 100644 internal/dynamo-browse/models/modexpr/values.go delete mode 100644 internal/sqs-browse/providers/memstore/memstore.go create mode 100644 internal/sqs-browse/providers/stormstore/memstore.go create mode 100644 test/cmd/load-test-table/main.go diff --git a/cmd/sqs-browse/main.go b/cmd/sqs-browse/main.go index 18daa58..ce866a3 100644 --- a/cmd/sqs-browse/main.go +++ b/cmd/sqs-browse/main.go @@ -10,8 +10,8 @@ import ( "github.com/lmika/awstools/internal/common/ui/dispatcher" "github.com/lmika/awstools/internal/sqs-browse/controllers" "github.com/lmika/awstools/internal/sqs-browse/models" - "github.com/lmika/awstools/internal/sqs-browse/providers/memstore" sqsprovider "github.com/lmika/awstools/internal/sqs-browse/providers/sqs" + "github.com/lmika/awstools/internal/sqs-browse/providers/stormstore" "github.com/lmika/awstools/internal/sqs-browse/services/messages" "github.com/lmika/awstools/internal/sqs-browse/services/pollmessage" "github.com/lmika/awstools/internal/sqs-browse/ui" @@ -35,7 +35,18 @@ func main() { bus := events.New() - msgStore := memstore.NewStore() + workspaceFile, err := os.CreateTemp("", "sqs-browse*.workspace") + if err != nil { + cli.Fatalf("cannot create workspace file: %v", err) + } + workspaceFile.Close() // We just need the filename + + msgStore, err := stormstore.NewStore(workspaceFile.Name()) + if err != nil { + cli.Fatalf("cannot open workspace: %v", err) + } + defer msgStore.Close() + sqsProvider := sqsprovider.NewProvider(sqsClient) messageService := messages.NewService(sqsProvider) @@ -59,6 +70,8 @@ func main() { } defer f.Close() + log.Printf("workspace file: %v", workspaceFile.Name()) + go func() { if err := pollService.Poll(context.Background()); err != nil { log.Printf("cannot start poller: %v", err) diff --git a/go.mod b/go.mod index fa1f6cb..c06ea6e 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( require ( github.com/alecthomas/participle/v2 v2.0.0-alpha7 // indirect + github.com/asdine/storm v2.1.2+incompatible // indirect github.com/atotto/clipboard v0.1.4 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.10.0 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.6 // indirect @@ -33,8 +34,10 @@ require ( github.com/aws/aws-sdk-go-v2/service/sso v1.9.0 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.14.0 // indirect github.com/aws/smithy-go v1.11.1 // indirect + github.com/brianvoe/gofakeit/v6 v6.15.0 // indirect github.com/containerd/console v1.0.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/google/uuid v1.3.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/juju/ansiterm v0.0.0-20210929141451-8b71cc96ebdc // indirect github.com/lmika/shellwords v0.0.0-20140714114018-ce258dd729fe // indirect @@ -47,6 +50,7 @@ require ( github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect + go.etcd.io/bbolt v1.3.6 // indirect golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect diff --git a/go.sum b/go.sum index eb66876..386946f 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/alecthomas/participle v0.7.1 h1:2bN7reTw//5f0cugJcTOnY/NYZcWQOaajW+Bw github.com/alecthomas/participle/v2 v2.0.0-alpha7 h1:cK4vjj0VSgb3lN1nuKA5F7dw+1s1pWBe5bx7nNCnN+c= github.com/alecthomas/participle/v2 v2.0.0-alpha7/go.mod h1:NumScqsC42o9x+dGj8/YqsIfhrIQjFEOFovxotbBirA= github.com/alecthomas/repr v0.0.0-20181024024818-d37bc2a10ba1/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ= +github.com/asdine/storm v2.1.2+incompatible h1:dczuIkyqwY2LrtXPz8ixMrU/OFgZp71kbKTHGrXYt/Q= +github.com/asdine/storm v2.1.2+incompatible/go.mod h1:RarYDc9hq1UPLImuiXK3BIWPJLdIygvV3PsInK0FbVQ= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aws/aws-sdk-go-v2 v1.13.0 h1:1XIXAfxsEmbhbj5ry3D3vX+6ZcUYvIqSm4CWWEuGZCA= @@ -46,6 +48,8 @@ github.com/aws/smithy-go v1.10.0 h1:gsoZQMNHnX+PaghNw4ynPsyGP7aUCqx5sY2dlPQsZ0w= github.com/aws/smithy-go v1.10.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.11.1 h1:IQ+lPZVkSM3FRtyaDox41R8YS6iwPMYIreejOgPW49g= github.com/aws/smithy-go v1.11.1/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM= +github.com/brianvoe/gofakeit/v6 v6.15.0 h1:lJPGJZ2/07TRGDazyTzD5b18N3y4tmmJpdhCUw18FlI= +github.com/brianvoe/gofakeit/v6 v6.15.0/go.mod h1:Ow6qC71xtwm79anlwKRlWZW6zVq9D2XHE4QSSMP/rU8= github.com/calyptia/go-bubble-table v0.1.0 h1:mXpaaBlrHGH4K8v5PvM8YqBFT9jlysS1YOycU2u3gEQ= github.com/calyptia/go-bubble-table v0.1.0/go.mod h1:2nnweuFos+eEIIbgweXvZuX+ROOatsMwB3NHnX/vTC4= github.com/charmbracelet/bubbles v0.10.3 h1:fKarbRaObLn/DCsZO4Y3vKCwRUzynQD9L+gGev1E/ho= @@ -66,6 +70,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= @@ -115,8 +121,11 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/internal/common/ui/commandctrl/commandctrl_test.go b/internal/common/ui/commandctrl/commandctrl_test.go index 85ef20a..0391107 100644 --- a/internal/common/ui/commandctrl/commandctrl_test.go +++ b/internal/common/ui/commandctrl/commandctrl_test.go @@ -11,7 +11,7 @@ import ( func TestCommandController_Prompt(t *testing.T) { t.Run("prompt user for a command", func(t *testing.T) { - cmd := commandctrl.NewCommandController() + cmd := commandctrl.NewCommandController(nil) ctx, uiCtx := testuictx.New(context.Background()) err := cmd.Prompt().Execute(ctx) diff --git a/internal/dynamo-browse/controllers/tablewrite_test.go b/internal/dynamo-browse/controllers/tablewrite_test.go index c8f8722..b9021db 100644 --- a/internal/dynamo-browse/controllers/tablewrite_test.go +++ b/internal/dynamo-browse/controllers/tablewrite_test.go @@ -55,7 +55,7 @@ func TestTableWriteController_Delete(t *testing.T) { ctx = controllers.ContextWithState(ctx, controllers.State{ ResultSet: resultSet, SelectedItem: resultSet.Items[1], - InReadWriteMode: false, + InReadWriteMode: true, }) op := twc.Delete() @@ -91,7 +91,7 @@ func TestTableWriteController_Delete(t *testing.T) { ctx = controllers.ContextWithState(ctx, controllers.State{ ResultSet: resultSet, SelectedItem: resultSet.Items[1], - InReadWriteMode: false, + InReadWriteMode: true, }) op := twc.Delete() diff --git a/internal/dynamo-browse/models/modexpr/ast.go b/internal/dynamo-browse/models/modexpr/ast.go index 70a2845..dc2aa2c 100644 --- a/internal/dynamo-browse/models/modexpr/ast.go +++ b/internal/dynamo-browse/models/modexpr/ast.go @@ -2,9 +2,7 @@ package modexpr import ( "github.com/alecthomas/participle/v2" - "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" "github.com/pkg/errors" - "strconv" ) type astExpr struct { @@ -12,19 +10,17 @@ type astExpr struct { } type astAttribute struct { - Name string `parser:"@Ident '='"` - Value string `parser:"@String"` + Names *astKeyList `parser:"@@ '='"` + Value *astLiteralValue `parser:"@@"` } -func (a astAttribute) dynamoValue() (types.AttributeValue, error) { - // TODO: should be based on type - s, err := strconv.Unquote(a.Value) - if err != nil { - return nil, errors.Wrap(err, "cannot unquote string") - } - return &types.AttributeValueMemberS{Value: s}, nil +type astKeyList struct { + Names []string `parser:"@Ident ('/' @Ident)*"` } +type astLiteralValue struct { + String string `parser:"@String"` +} var parser = participle.MustBuild(&astExpr{}) diff --git a/internal/dynamo-browse/models/modexpr/astmods.go b/internal/dynamo-browse/models/modexpr/astmods.go new file mode 100644 index 0000000..0247bf7 --- /dev/null +++ b/internal/dynamo-browse/models/modexpr/astmods.go @@ -0,0 +1,31 @@ +package modexpr + +import "github.com/lmika/awstools/internal/dynamo-browse/models" + +func (a *astExpr) calcPatchMods(item models.Item) ([]patchMod, error) { + patchMods := make([]patchMod, 0) + + for _, attr := range a.Attributes { + attrPatchMods, err := attr.calcPatchMods(item) + if err != nil { + return nil, err + } + patchMods = append(patchMods, attrPatchMods...) + } + + return patchMods, nil +} + +func (a *astAttribute) calcPatchMods(item models.Item) ([]patchMod, error) { + value, err := a.Value.dynamoValue() + if err != nil { + return nil, err + } + + patchMods := make([]patchMod, 0) + for _, key := range a.Names.Names { + patchMods = append(patchMods, setAttributeMod{key: key, to: value}) + } + + return patchMods, nil +} diff --git a/internal/dynamo-browse/models/modexpr/expr.go b/internal/dynamo-browse/models/modexpr/expr.go index 2f381b8..7f26e59 100644 --- a/internal/dynamo-browse/models/modexpr/expr.go +++ b/internal/dynamo-browse/models/modexpr/expr.go @@ -7,15 +7,14 @@ type ModExpr struct { } func (me *ModExpr) Patch(item models.Item) (models.Item, error) { - newItem := item.Clone() + mods, err := me.ast.calcPatchMods(item) + if err != nil { + return nil, err + } - for _, attribute := range me.ast.Attributes { - var err error - name := attribute.Name - newItem[name], err = attribute.dynamoValue() - if err != nil { - return nil, err - } + newItem := item.Clone() + for _, mod := range mods { + mod.Apply(newItem) } return newItem, nil diff --git a/internal/dynamo-browse/models/modexpr/expr_test.go b/internal/dynamo-browse/models/modexpr/expr_test.go index b6213fa..7978665 100644 --- a/internal/dynamo-browse/models/modexpr/expr_test.go +++ b/internal/dynamo-browse/models/modexpr/expr_test.go @@ -36,4 +36,20 @@ func TestModExpr_Patch(t *testing.T) { assert.Equal(t, "new value", newItem["alpha"].(*types.AttributeValueMemberS).Value) assert.Equal(t, "another new value", newItem["beta"].(*types.AttributeValueMemberS).Value) }) + + t.Run("patch with key tuple", func(t *testing.T) { + modExpr, err := modexpr.Parse(`alpha/beta="new value"`) + assert.NoError(t, err) + + oldItem := models.Item{ + "old": &types.AttributeValueMemberS{Value: "before"}, + "beta": &types.AttributeValueMemberS{Value: "before beta"}, + } + newItem, err := modExpr.Patch(oldItem) + assert.NoError(t, err) + + assert.Equal(t, "before", newItem["old"].(*types.AttributeValueMemberS).Value) + assert.Equal(t, "new value", newItem["alpha"].(*types.AttributeValueMemberS).Value) + assert.Equal(t, "new value", newItem["beta"].(*types.AttributeValueMemberS).Value) + }) } diff --git a/internal/dynamo-browse/models/modexpr/mods.go b/internal/dynamo-browse/models/modexpr/mods.go new file mode 100644 index 0000000..7a18bff --- /dev/null +++ b/internal/dynamo-browse/models/modexpr/mods.go @@ -0,0 +1,19 @@ +package modexpr + +import ( + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" + "github.com/lmika/awstools/internal/dynamo-browse/models" +) + +type patchMod interface { + Apply(item models.Item) +} + +type setAttributeMod struct { + key string + to types.AttributeValue +} + +func (sa setAttributeMod) Apply(item models.Item) { + item[sa.key] = sa.to +} diff --git a/internal/dynamo-browse/models/modexpr/values.go b/internal/dynamo-browse/models/modexpr/values.go new file mode 100644 index 0000000..7e2222a --- /dev/null +++ b/internal/dynamo-browse/models/modexpr/values.go @@ -0,0 +1,15 @@ +package modexpr + +import ( + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" + "github.com/pkg/errors" + "strconv" +) + +func (a *astLiteralValue) dynamoValue() (types.AttributeValue, error) { + s, err := strconv.Unquote(a.String) + if err != nil { + return nil, errors.Wrap(err, "cannot unquote string") + } + return &types.AttributeValueMemberS{Value: s}, nil +} diff --git a/internal/dynamo-browse/ui/model.go b/internal/dynamo-browse/ui/model.go index 65754ab..6a5efec 100644 --- a/internal/dynamo-browse/ui/model.go +++ b/internal/dynamo-browse/ui/model.go @@ -155,10 +155,14 @@ func (m uiModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // Tea events case tea.WindowSizeMsg: fixedViewsHeight := lipgloss.Height(m.headerView()) + lipgloss.Height(m.splitterView()) + lipgloss.Height(m.footerView()) - tableHeight := msg.Height / 2 + viewportHeight := msg.Height / 2 // TODO: make this dynamic + if viewportHeight > 15 { + viewportHeight = 15 + } + tableHeight := msg.Height - fixedViewsHeight - viewportHeight if !m.ready { - m.viewport = viewport.New(msg.Width, msg.Height-tableHeight-fixedViewsHeight) + m.viewport = viewport.New(msg.Width, viewportHeight) m.viewport.SetContent("(no message selected)") m.ready = true } else { diff --git a/internal/sqs-browse/models/message.go b/internal/sqs-browse/models/message.go index 0d3b5e5..f8996a6 100644 --- a/internal/sqs-browse/models/message.go +++ b/internal/sqs-browse/models/message.go @@ -3,9 +3,9 @@ package models import "time" type Message struct { - ID uint64 - ExtID string - Queue string + ID uint64 `storm:"id,increment"` + ExtID string `storm:"unique"` + Queue string `storm:"index"` Received time.Time Data string } diff --git a/internal/sqs-browse/providers/memstore/memstore.go b/internal/sqs-browse/providers/memstore/memstore.go deleted file mode 100644 index 23cf339..0000000 --- a/internal/sqs-browse/providers/memstore/memstore.go +++ /dev/null @@ -1,31 +0,0 @@ -package memstore - -import ( - "context" - "github.com/lmika/awstools/internal/sqs-browse/models" - "sync" -) - -type Store struct { - messages []models.Message - - mtx *sync.Mutex - currSeqNo uint64 -} - -func (s *Store) Save(ctx context.Context, msg *models.Message) error { - s.mtx.Lock() - defer s.mtx.Unlock() - - s.currSeqNo++ - msg.ID = s.currSeqNo - s.messages = append(s.messages, *msg) - return nil -} - -func NewStore() *Store { - return &Store{ - messages: make([]models.Message, 0), - mtx: new(sync.Mutex), - } -} diff --git a/internal/sqs-browse/providers/stormstore/memstore.go b/internal/sqs-browse/providers/stormstore/memstore.go new file mode 100644 index 0000000..813565f --- /dev/null +++ b/internal/sqs-browse/providers/stormstore/memstore.go @@ -0,0 +1,30 @@ +package stormstore + +import ( + "context" + "github.com/asdine/storm" + "github.com/lmika/awstools/internal/sqs-browse/models" + "github.com/pkg/errors" +) + +type Store struct { + db *storm.DB +} + +// TODO: should probably be a workspace provider +func NewStore(filename string) (*Store, error) { + db, err := storm.Open(filename) + if err != nil { + return nil, errors.Wrapf(err, "cannot open store %v", filename) + } + + return &Store{db: db}, nil +} + +func (s *Store) Close() { + s.db.Close() +} + +func (s *Store) Save(ctx context.Context, msg *models.Message) error { + return s.db.Save(msg) +} diff --git a/test/cmd/load-test-table/main.go b/test/cmd/load-test-table/main.go new file mode 100644 index 0000000..9493caa --- /dev/null +++ b/test/cmd/load-test-table/main.go @@ -0,0 +1,74 @@ +package main + +import ( + "context" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" + "github.com/brianvoe/gofakeit/v6" + "github.com/google/uuid" + "github.com/lmika/awstools/internal/dynamo-browse/models" + "github.com/lmika/awstools/internal/dynamo-browse/providers/dynamo" + "github.com/lmika/awstools/internal/dynamo-browse/services/tables" + "github.com/lmika/gopkgs/cli" + "log" +) + +func main() { + ctx := context.Background() + tableName := "awstools-test" + totalItems := 300 + + cfg, err := config.LoadDefaultConfig(ctx) + if err != nil { + cli.Fatalf("cannot load AWS config: %v", err) + } + + dynamoClient := dynamodb.NewFromConfig(cfg, + dynamodb.WithEndpointResolver(dynamodb.EndpointResolverFromURL("http://localhost:8000"))) + + if _, err = dynamoClient.DeleteTable(ctx, &dynamodb.DeleteTableInput{ + TableName: aws.String(tableName), + }); err != nil { + log.Printf("warn: cannot delete table: %v", tableName) + } + + if _, err = dynamoClient.CreateTable(ctx, &dynamodb.CreateTableInput{ + TableName: aws.String(tableName), + KeySchema: []types.KeySchemaElement{ + {AttributeName: aws.String("pk"), KeyType: types.KeyTypeHash}, + {AttributeName: aws.String("sk"), KeyType: types.KeyTypeRange}, + }, + AttributeDefinitions: []types.AttributeDefinition{ + {AttributeName: aws.String("pk"), AttributeType: types.ScalarAttributeTypeS}, + {AttributeName: aws.String("sk"), AttributeType: types.ScalarAttributeTypeS}, + }, + ProvisionedThroughput: &types.ProvisionedThroughput{ + ReadCapacityUnits: aws.Int64(100), + WriteCapacityUnits: aws.Int64(100), + }, + }); err != nil { + log.Fatalf("warn: cannot create table: %v", tableName) + } + + dynamoProvider := dynamo.NewProvider(dynamoClient) + tableService := tables.NewService(dynamoProvider) + + for i := 0; i < totalItems; i++ { + key := uuid.New().String() + if err := tableService.Put(ctx, tableName, models.Item{ + "pk": &types.AttributeValueMemberS{Value: key}, + "sk": &types.AttributeValueMemberS{Value: key}, + "name": &types.AttributeValueMemberS{Value: gofakeit.Name()}, + "address": &types.AttributeValueMemberS{Value: gofakeit.Address().Address}, + "city": &types.AttributeValueMemberS{Value: gofakeit.Address().City}, + "phone": &types.AttributeValueMemberS{Value: gofakeit.Phone()}, + "web": &types.AttributeValueMemberS{Value: gofakeit.URL()}, + }); err != nil { + log.Fatalln(err) + } + } + + log.Printf("table '%v' created with %v items", tableName, totalItems) +}