From 18ffe85a562bc77e4f29bdc75812f316d1c68d01 Mon Sep 17 00:00:00 2001 From: Leon Mika Date: Sat, 17 May 2025 22:16:49 +1000 Subject: [PATCH] First attempt at a resultset pseudovar The resultset needs a table set, so rs:new will also assume the current table. --- go.mod | 2 +- go.sum | 2 ++ .../common/ui/commandctrl/cmdpacks/modrs.go | 34 ++++++++++++++++--- .../common/ui/commandctrl/cmdpacks/pvars.go | 31 +++++++++++++++++ .../common/ui/commandctrl/cmdpacks/stdcmds.go | 2 ++ internal/dynamo-browse/controllers/state.go | 8 +++++ .../dynamo-browse/controllers/tableread.go | 6 ++++ test/testdynamo/client.go | 8 ++++- 8 files changed, 87 insertions(+), 6 deletions(-) create mode 100644 internal/common/ui/commandctrl/cmdpacks/pvars.go diff --git a/go.mod b/go.mod index 3678e7c..51c142d 100644 --- a/go.mod +++ b/go.mod @@ -117,5 +117,5 @@ require ( golang.org/x/text v0.9.0 // indirect google.golang.org/appengine v1.6.7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - ucl.lmika.dev v0.0.0-20250517003439-109be33d1495 // indirect + ucl.lmika.dev v0.0.0-20250517115116-0f1ceba0902e // indirect ) diff --git a/go.sum b/go.sum index fdaef5d..1e50447 100644 --- a/go.sum +++ b/go.sum @@ -442,3 +442,5 @@ ucl.lmika.dev v0.0.0-20250515115457-27b6cc0b92e2 h1:cvguOoQ0HVgLKbHH17ZHvAUFht6H ucl.lmika.dev v0.0.0-20250515115457-27b6cc0b92e2/go.mod h1:/MMZKm6mOMtnY4I8TYEot4Pc8dKEy+/IAQo1VdpA5EY= ucl.lmika.dev v0.0.0-20250517003439-109be33d1495 h1:r46r+7T59Drm+in7TEWKCZfFYIM0ZyZ26QjHAbj8Lto= ucl.lmika.dev v0.0.0-20250517003439-109be33d1495/go.mod h1:/MMZKm6mOMtnY4I8TYEot4Pc8dKEy+/IAQo1VdpA5EY= +ucl.lmika.dev v0.0.0-20250517115116-0f1ceba0902e h1:CQ+qPqI5lYiiEM0tNAr4jS0iMz16bFqOui5mU3AHsCU= +ucl.lmika.dev v0.0.0-20250517115116-0f1ceba0902e/go.mod h1:/MMZKm6mOMtnY4I8TYEot4Pc8dKEy+/IAQo1VdpA5EY= diff --git a/internal/common/ui/commandctrl/cmdpacks/modrs.go b/internal/common/ui/commandctrl/cmdpacks/modrs.go index a748899..4af1513 100644 --- a/internal/common/ui/commandctrl/cmdpacks/modrs.go +++ b/internal/common/ui/commandctrl/cmdpacks/modrs.go @@ -8,6 +8,7 @@ import ( "github.com/lmika/dynamo-browse/internal/dynamo-browse/models/queryexpr" "github.com/lmika/dynamo-browse/internal/dynamo-browse/services/tables" "github.com/pkg/errors" + "time" "ucl.lmika.dev/repl" "ucl.lmika.dev/ucl" ) @@ -19,11 +20,36 @@ type rsModule struct { var rsNewDoc = repl.Doc{ Brief: "Creates a new, empty result set", + Usage: "[-table NAME]", + Detailed: ` + The result set assumes the details of the current table. If no table is specified, + the command will return an error. + `, } -func (rs *rsModule) rsNew(ctx context.Context, args ucl.CallArgs) (any, error) { - return &ResultSetProxy{ - RS: &models.ResultSet{}, +func (rs *rsModule) rsNew(ctx context.Context, args ucl.CallArgs) (_ any, err error) { + var tableInfo *models.TableInfo + if args.HasSwitch("table") { + var tblName string + if err := args.BindSwitch("table", &tblName); err != nil { + return nil, err + } + + tableInfo, err = rs.tableService.Describe(ctx, tblName) + if err != nil { + return nil, err + } + } else if currRs := rs.state.ResultSet(); currRs != nil && currRs.TableInfo != nil { + tableInfo = currRs.TableInfo + } else { + return nil, errors.New("no table specified") + } + + return ResultSetProxy{ + RS: &models.ResultSet{ + TableInfo: tableInfo, + Created: time.Now(), + }, }, nil } @@ -102,7 +128,7 @@ func (rs *rsModule) rsQuery(ctx context.Context, args ucl.CallArgs) (any, error) return nil, err } - return &ResultSetProxy{ + return ResultSetProxy{ RS: newResultSet, }, nil } diff --git a/internal/common/ui/commandctrl/cmdpacks/pvars.go b/internal/common/ui/commandctrl/cmdpacks/pvars.go new file mode 100644 index 0000000..5f5020e --- /dev/null +++ b/internal/common/ui/commandctrl/cmdpacks/pvars.go @@ -0,0 +1,31 @@ +package cmdpacks + +import ( + "context" + "github.com/lmika/dynamo-browse/internal/common/ui/commandctrl" + "github.com/lmika/dynamo-browse/internal/dynamo-browse/controllers" + "github.com/pkg/errors" + "log" +) + +type resultSetPVar struct { + state *controllers.State + readController *controllers.TableReadController +} + +func (rs resultSetPVar) Get(ctx context.Context) (any, error) { + return ResultSetProxy{rs.state.ResultSet()}, nil +} + +func (rs resultSetPVar) Set(ctx context.Context, value any) error { + rsVal, ok := value.(ResultSetProxy) + if !ok { + return errors.New("new value to @resultset is not a result set") + } + + log.Printf("type = %T", rsVal.RS) + + msg := rs.readController.SetResultSet(rsVal.RS) + commandctrl.PostMsg(ctx, msg) + return nil +} diff --git a/internal/common/ui/commandctrl/cmdpacks/stdcmds.go b/internal/common/ui/commandctrl/cmdpacks/stdcmds.go index 21756a3..4682926 100644 --- a/internal/common/ui/commandctrl/cmdpacks/stdcmds.go +++ b/internal/common/ui/commandctrl/cmdpacks/stdcmds.go @@ -384,4 +384,6 @@ func (sc StandardCommands) ConfigureUCL(ucl *ucl.Inst) { ucl.SetBuiltin("noisy-touch", sc.cmdNoisyTouch) ucl.SetBuiltin("rebind", sc.cmdRebind) // set-opt --> alias to opts:set + + ucl.SetPseudoVar("resultset", resultSetPVar{sc.State, sc.ReadController}) } diff --git a/internal/dynamo-browse/controllers/state.go b/internal/dynamo-browse/controllers/state.go index 6a886d2..8f7ea82 100644 --- a/internal/dynamo-browse/controllers/state.go +++ b/internal/dynamo-browse/controllers/state.go @@ -29,6 +29,14 @@ func (s *State) Filter() string { return s.filter } +func (s *State) SetResultSet(resultSet *models.ResultSet) { + s.mutex.Lock() + defer s.mutex.Unlock() + + s.resultSet = resultSet + s.filter = "" +} + func (s *State) withResultSet(rs func(*models.ResultSet)) { s.mutex.Lock() defer s.mutex.Unlock() diff --git a/internal/dynamo-browse/controllers/tableread.go b/internal/dynamo-browse/controllers/tableread.go index 6ef6e18..e7034a5 100644 --- a/internal/dynamo-browse/controllers/tableread.go +++ b/internal/dynamo-browse/controllers/tableread.go @@ -291,6 +291,12 @@ func (c *TableReadController) setResultSetAndFilter(resultSet *models.ResultSet, return c.state.buildNewResultSetMessage("") } +func (c *TableReadController) SetResultSet(resultSet *models.ResultSet) tea.Msg { + c.state.setResultSetAndFilter(resultSet, "") + c.eventBus.Fire(newResultSetEvent, resultSet, resultSetUpdateScript) + return c.state.buildNewResultSetMessage("") +} + func (c *TableReadController) Mark(op MarkOp, where string) tea.Msg { var ( whereExpr *queryexpr.QueryExpr diff --git a/test/testdynamo/client.go b/test/testdynamo/client.go index 68c9065..688ea25 100644 --- a/test/testdynamo/client.go +++ b/test/testdynamo/client.go @@ -2,6 +2,7 @@ package testdynamo import ( "context" + "os" "testing" "github.com/aws/aws-sdk-go-v2/aws" @@ -28,8 +29,13 @@ func SetupTestTable(t *testing.T, testData []TestData) *dynamodb.Client { config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider("abc", "123", ""))) assert.NoError(t, err) + testDynamoURL, ok := os.LookupEnv("TEST_DYNAMO_URL") + if !ok { + testDynamoURL = "http://localhost:4566" + } + dynamoClient := dynamodb.NewFromConfig(cfg, - dynamodb.WithEndpointResolver(dynamodb.EndpointResolverFromURL("http://localhost:4566"))) + dynamodb.WithEndpointResolver(dynamodb.EndpointResolverFromURL(testDynamoURL))) for _, table := range testData { tableInput := &dynamodb.CreateTableInput{