- Fixed the 'M' bind to mark all/none items, rather than toggle - Fixed panic which was raised when reqesting @item with an index beyond the length of resultset - Added changing the table when calling @table with a table or string name
This commit is contained in:
parent
85a4f0b5e9
commit
c8b65f6b0a
12 changed files with 380 additions and 15 deletions
|
|
@ -154,6 +154,40 @@ func TestModRS_Query(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestModRS_Filter(t *testing.T) {
|
||||
tests := []struct {
|
||||
descr string
|
||||
cmd string
|
||||
}{
|
||||
{
|
||||
descr: "returns filtered items 1",
|
||||
cmd: `
|
||||
rs = rs:scan -table service-test-data
|
||||
rs = rs:filter $rs 'pk="abc"'
|
||||
assert (len $rs) "expected len == 2"
|
||||
assert (eq $rs.First.pk "abc") "expected First.pk == abc"
|
||||
`,
|
||||
},
|
||||
//{
|
||||
// descr: "returns filtered items 2",
|
||||
// cmd: `
|
||||
// rs = rs:scan -table service-test-data
|
||||
// rs = rs:filter $rs 'pk="bbb"'
|
||||
// assert (len $rs) "expected len == 1"
|
||||
// assert (eq $rs.First.pk "bbb") "expected First.pk == bbb"
|
||||
// `,
|
||||
//},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.descr, func(t *testing.T) {
|
||||
svc := newService(t)
|
||||
|
||||
_, err := svc.CommandController.ExecuteAndWait(t.Context(), tt.cmd)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestModRS_First(t *testing.T) {
|
||||
tests := []struct {
|
||||
descr string
|
||||
|
|
|
|||
|
|
@ -174,6 +174,31 @@ func (tp resultSetItemsProxy) Index(k int) ucl.Object {
|
|||
return itemProxy{resultSet: tp.resultSet, idx: k, item: tp.resultSet.Items()[k]}
|
||||
}
|
||||
|
||||
type resultSetMarkedItemsProxy struct {
|
||||
resultSet *models.ResultSet
|
||||
}
|
||||
|
||||
func (ip resultSetMarkedItemsProxy) String() string {
|
||||
return fmt.Sprintf("MarkedItems(%v)", len(ip.resultSet.MarkedItems()))
|
||||
}
|
||||
|
||||
func (ip resultSetMarkedItemsProxy) Truthy() bool {
|
||||
return len(ip.resultSet.MarkedItems()) > 0
|
||||
}
|
||||
|
||||
func (tp resultSetMarkedItemsProxy) Len() int {
|
||||
return len(tp.resultSet.MarkedItems())
|
||||
}
|
||||
|
||||
func (tp resultSetMarkedItemsProxy) Index(k int) ucl.Object {
|
||||
markedItems := tp.resultSet.MarkedItems()
|
||||
if k >= len(markedItems) {
|
||||
return nil
|
||||
}
|
||||
actualItem := tp.resultSet.Items()[markedItems[k].Index]
|
||||
return itemProxy{resultSet: tp.resultSet, idx: markedItems[k].Index, item: actualItem}
|
||||
}
|
||||
|
||||
type itemProxy struct {
|
||||
resultSet *models.ResultSet
|
||||
idx int
|
||||
|
|
|
|||
|
|
@ -2,20 +2,53 @@ package cmdpacks
|
|||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"lmika.dev/cmd/dynamo-browse/internal/common/ui/commandctrl"
|
||||
"lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/controllers"
|
||||
"lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/models"
|
||||
"github.com/pkg/errors"
|
||||
"lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/services/tables"
|
||||
)
|
||||
|
||||
type tablePVar struct {
|
||||
state *controllers.State
|
||||
state *controllers.State
|
||||
tableService *tables.Service
|
||||
readController *controllers.TableReadController
|
||||
}
|
||||
|
||||
func (rs tablePVar) Get(ctx context.Context) (any, error) {
|
||||
return newTableProxy(rs.state.ResultSet().TableInfo), nil
|
||||
}
|
||||
|
||||
func (rs tablePVar) Set(ctx context.Context, value any) error {
|
||||
scanNewTable := func(name string) error {
|
||||
tableInfo, err := rs.tableService.Describe(ctx, name)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "cannot describe %v", name)
|
||||
}
|
||||
|
||||
resultSet, err := rs.tableService.Scan(ctx, tableInfo)
|
||||
if resultSet != nil {
|
||||
resultSet = rs.tableService.Filter(resultSet, rs.state.Filter())
|
||||
}
|
||||
|
||||
msg := rs.readController.SetResultSet(resultSet)
|
||||
commandctrl.PostMsg(ctx, msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
tblVal, ok := value.(SimpleProxy[*models.TableInfo])
|
||||
if ok {
|
||||
return scanNewTable(tblVal.value.Name)
|
||||
}
|
||||
|
||||
strVal, ok := value.(string)
|
||||
if ok {
|
||||
return scanNewTable(strVal)
|
||||
}
|
||||
return errors.New("new value to @table is not a table name")
|
||||
}
|
||||
|
||||
type resultSetPVar struct {
|
||||
state *controllers.State
|
||||
readController *controllers.TableReadController
|
||||
|
|
@ -36,6 +69,15 @@ func (rs resultSetPVar) Set(ctx context.Context, value any) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
type markedSetPVar struct {
|
||||
state *controllers.State
|
||||
readController *controllers.TableReadController
|
||||
}
|
||||
|
||||
func (rs markedSetPVar) Get(ctx context.Context) (any, error) {
|
||||
return resultSetMarkedItemsProxy{rs.state.ResultSet()}, nil
|
||||
}
|
||||
|
||||
type itemPVar struct {
|
||||
state *controllers.State
|
||||
}
|
||||
|
|
@ -43,9 +85,14 @@ type itemPVar struct {
|
|||
func (rs itemPVar) Get(ctx context.Context) (any, error) {
|
||||
selItem, ok := commandctrl.SelectedItemIndex(ctx)
|
||||
if !ok {
|
||||
return nil, errors.New("no item selected")
|
||||
return nil, nil
|
||||
}
|
||||
return itemProxy{rs.state.ResultSet(), selItem, rs.state.ResultSet().Items()[selItem]}, nil
|
||||
rset := rs.state.ResultSet()
|
||||
if selItem < 0 || selItem >= len(rs.state.ResultSet().Items()) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return itemProxy{rset, selItem, rset.Items()[selItem]}, nil
|
||||
}
|
||||
|
||||
func (rs itemPVar) Set(ctx context.Context, value any) error {
|
||||
|
|
|
|||
32
internal/common/ui/commandctrl/cmdpacks/pvars_test.go
Normal file
32
internal/common/ui/commandctrl/cmdpacks/pvars_test.go
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
package cmdpacks_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPVars(t *testing.T) {
|
||||
tests := []struct {
|
||||
descr string
|
||||
cmd string
|
||||
}{
|
||||
{
|
||||
descr: "returns item on empty result set",
|
||||
cmd: `
|
||||
ui:query '"a"="1"' -table service-test-data
|
||||
@item
|
||||
`,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.descr, func(t *testing.T) {
|
||||
svc := newService(t)
|
||||
|
||||
ctx := t.Context()
|
||||
|
||||
_, err := svc.CommandController.ExecuteAndWait(ctx, tt.cmd)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package cmdpacks
|
|||
|
||||
import (
|
||||
"context"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/pkg/errors"
|
||||
"lmika.dev/cmd/dynamo-browse/internal/common/ui/commandctrl"
|
||||
|
|
@ -426,8 +427,9 @@ func (sc StandardCommands) ConfigureUCL(ucl *ucl.Inst) {
|
|||
ucl.SetBuiltin("q", sc.cmdQuit)
|
||||
|
||||
ucl.SetPseudoVar("resultset", resultSetPVar{sc.State, sc.ReadController})
|
||||
ucl.SetPseudoVar("table", tablePVar{sc.State})
|
||||
ucl.SetPseudoVar("table", tablePVar{sc.State, sc.TableService, sc.ReadController})
|
||||
ucl.SetPseudoVar("item", itemPVar{sc.State})
|
||||
ucl.SetPseudoVar("marked", markedSetPVar{sc.State, sc.ReadController})
|
||||
}
|
||||
|
||||
func (sc StandardCommands) RunPrelude(ctx context.Context, ucl *ucl.Inst) error {
|
||||
|
|
@ -438,4 +440,13 @@ func (sc StandardCommands) RunPrelude(ctx context.Context, ucl *ucl.Inst) error
|
|||
const uclPrelude = `
|
||||
ui:command unmark { mark none }
|
||||
ui:command set-opt { |n k| opt:set $n $k }
|
||||
|
||||
ui:bind "view.toggle-marked-items" "M" {
|
||||
markedCount = len @marked
|
||||
if (eq $markedCount (len @resultset)) {
|
||||
mark none
|
||||
} else {
|
||||
mark all
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue