sqs-browse: added notion of workspaces in sqs-browse

Also added a tool to generate test tables
This commit is contained in:
Leon Mika 2022-03-24 15:44:57 +11:00
parent cecdbafabb
commit 30dbc4eefe
16 changed files with 239 additions and 60 deletions

View file

@ -10,8 +10,8 @@ import (
"github.com/lmika/awstools/internal/common/ui/dispatcher" "github.com/lmika/awstools/internal/common/ui/dispatcher"
"github.com/lmika/awstools/internal/sqs-browse/controllers" "github.com/lmika/awstools/internal/sqs-browse/controllers"
"github.com/lmika/awstools/internal/sqs-browse/models" "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" 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/messages"
"github.com/lmika/awstools/internal/sqs-browse/services/pollmessage" "github.com/lmika/awstools/internal/sqs-browse/services/pollmessage"
"github.com/lmika/awstools/internal/sqs-browse/ui" "github.com/lmika/awstools/internal/sqs-browse/ui"
@ -35,7 +35,18 @@ func main() {
bus := events.New() 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) sqsProvider := sqsprovider.NewProvider(sqsClient)
messageService := messages.NewService(sqsProvider) messageService := messages.NewService(sqsProvider)
@ -59,6 +70,8 @@ func main() {
} }
defer f.Close() defer f.Close()
log.Printf("workspace file: %v", workspaceFile.Name())
go func() { go func() {
if err := pollService.Poll(context.Background()); err != nil { if err := pollService.Poll(context.Background()); err != nil {
log.Printf("cannot start poller: %v", err) log.Printf("cannot start poller: %v", err)

4
go.mod
View file

@ -21,6 +21,7 @@ require (
require ( require (
github.com/alecthomas/participle/v2 v2.0.0-alpha7 // indirect 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/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/feature/ec2/imds v1.10.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.6 // 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/sso v1.9.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.14.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/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/containerd/console v1.0.3 // indirect
github.com/davecgh/go-spew v1.1.1 // 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/jmespath/go-jmespath v0.4.0 // indirect
github.com/juju/ansiterm v0.0.0-20210929141451-8b71cc96ebdc // indirect github.com/juju/ansiterm v0.0.0-20210929141451-8b71cc96ebdc // indirect
github.com/lmika/shellwords v0.0.0-20140714114018-ce258dd729fe // 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/muesli/termenv v0.11.1-0.20220212125758-44cd13922739 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.2.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/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect

9
go.sum
View file

@ -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 h1:cK4vjj0VSgb3lN1nuKA5F7dw+1s1pWBe5bx7nNCnN+c=
github.com/alecthomas/participle/v2 v2.0.0-alpha7/go.mod h1:NumScqsC42o9x+dGj8/YqsIfhrIQjFEOFovxotbBirA= 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/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 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/aws/aws-sdk-go-v2 v1.13.0 h1:1XIXAfxsEmbhbj5ry3D3vX+6ZcUYvIqSm4CWWEuGZCA= 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.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 h1:IQ+lPZVkSM3FRtyaDox41R8YS6iwPMYIreejOgPW49g=
github.com/aws/smithy-go v1.11.1/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM= 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 h1:mXpaaBlrHGH4K8v5PvM8YqBFT9jlysS1YOycU2u3gEQ=
github.com/calyptia/go-bubble-table v0.1.0/go.mod h1:2nnweuFos+eEIIbgweXvZuX+ROOatsMwB3NHnX/vTC4= 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= 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.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.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/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 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= 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= 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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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-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-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-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-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

View file

@ -11,7 +11,7 @@ import (
func TestCommandController_Prompt(t *testing.T) { func TestCommandController_Prompt(t *testing.T) {
t.Run("prompt user for a command", func(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()) ctx, uiCtx := testuictx.New(context.Background())
err := cmd.Prompt().Execute(ctx) err := cmd.Prompt().Execute(ctx)

View file

@ -55,7 +55,7 @@ func TestTableWriteController_Delete(t *testing.T) {
ctx = controllers.ContextWithState(ctx, controllers.State{ ctx = controllers.ContextWithState(ctx, controllers.State{
ResultSet: resultSet, ResultSet: resultSet,
SelectedItem: resultSet.Items[1], SelectedItem: resultSet.Items[1],
InReadWriteMode: false, InReadWriteMode: true,
}) })
op := twc.Delete() op := twc.Delete()
@ -91,7 +91,7 @@ func TestTableWriteController_Delete(t *testing.T) {
ctx = controllers.ContextWithState(ctx, controllers.State{ ctx = controllers.ContextWithState(ctx, controllers.State{
ResultSet: resultSet, ResultSet: resultSet,
SelectedItem: resultSet.Items[1], SelectedItem: resultSet.Items[1],
InReadWriteMode: false, InReadWriteMode: true,
}) })
op := twc.Delete() op := twc.Delete()

View file

@ -2,9 +2,7 @@ package modexpr
import ( import (
"github.com/alecthomas/participle/v2" "github.com/alecthomas/participle/v2"
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
"github.com/pkg/errors" "github.com/pkg/errors"
"strconv"
) )
type astExpr struct { type astExpr struct {
@ -12,19 +10,17 @@ type astExpr struct {
} }
type astAttribute struct { type astAttribute struct {
Name string `parser:"@Ident '='"` Names *astKeyList `parser:"@@ '='"`
Value string `parser:"@String"` Value *astLiteralValue `parser:"@@"`
} }
func (a astAttribute) dynamoValue() (types.AttributeValue, error) { type astKeyList struct {
// TODO: should be based on type Names []string `parser:"@Ident ('/' @Ident)*"`
s, err := strconv.Unquote(a.Value)
if err != nil {
return nil, errors.Wrap(err, "cannot unquote string")
}
return &types.AttributeValueMemberS{Value: s}, nil
} }
type astLiteralValue struct {
String string `parser:"@String"`
}
var parser = participle.MustBuild(&astExpr{}) var parser = participle.MustBuild(&astExpr{})

View file

@ -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
}

View file

@ -7,15 +7,14 @@ type ModExpr struct {
} }
func (me *ModExpr) Patch(item models.Item) (models.Item, error) { 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 { newItem := item.Clone()
var err error for _, mod := range mods {
name := attribute.Name mod.Apply(newItem)
newItem[name], err = attribute.dynamoValue()
if err != nil {
return nil, err
}
} }
return newItem, nil return newItem, nil

View file

@ -36,4 +36,20 @@ func TestModExpr_Patch(t *testing.T) {
assert.Equal(t, "new value", newItem["alpha"].(*types.AttributeValueMemberS).Value) assert.Equal(t, "new value", newItem["alpha"].(*types.AttributeValueMemberS).Value)
assert.Equal(t, "another new value", newItem["beta"].(*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)
})
} }

View file

@ -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
}

View file

@ -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
}

View file

@ -155,10 +155,14 @@ func (m uiModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// Tea events // Tea events
case tea.WindowSizeMsg: case tea.WindowSizeMsg:
fixedViewsHeight := lipgloss.Height(m.headerView()) + lipgloss.Height(m.splitterView()) + lipgloss.Height(m.footerView()) 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 { 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.viewport.SetContent("(no message selected)")
m.ready = true m.ready = true
} else { } else {

View file

@ -3,9 +3,9 @@ package models
import "time" import "time"
type Message struct { type Message struct {
ID uint64 ID uint64 `storm:"id,increment"`
ExtID string ExtID string `storm:"unique"`
Queue string Queue string `storm:"index"`
Received time.Time Received time.Time
Data string Data string
} }

View file

@ -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),
}
}

View file

@ -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)
}

View file

@ -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)
}