Issue 24: Added read-only mode (#27)
- Added settings to workspace, and added the read-only mode - Added the `-ro` field which will launch Dynamo-Browse in read-only mode - Added the `set ro` to enable read-only mode, and `set rw` to enable read-write mode
This commit is contained in:
parent
a1717572c5
commit
93ec519127
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/lmika/audax/internal/common/workspaces"
|
||||
"github.com/lmika/audax/internal/dynamo-browse/controllers"
|
||||
"github.com/lmika/audax/internal/dynamo-browse/providers/dynamo"
|
||||
"github.com/lmika/audax/internal/dynamo-browse/providers/settingstore"
|
||||
"github.com/lmika/audax/internal/dynamo-browse/providers/workspacestore"
|
||||
"github.com/lmika/audax/internal/dynamo-browse/services/itemrenderer"
|
||||
keybindings_service "github.com/lmika/audax/internal/dynamo-browse/services/keybindings"
|
||||
|
@ -32,6 +33,7 @@ func main() {
|
|||
var flagTable = flag.String("t", "", "dynamodb table name")
|
||||
var flagLocal = flag.String("local", "", "local endpoint")
|
||||
var flagDebug = flag.String("debug", "", "file to log debug messages")
|
||||
var flagRO = flag.Bool("ro", false, "enable readonly mode")
|
||||
var flagWorkspace = flag.String("w", "", "workspace file")
|
||||
flag.Parse()
|
||||
|
||||
|
@ -73,14 +75,22 @@ func main() {
|
|||
uiStyles := styles.DefaultStyles
|
||||
dynamoProvider := dynamo.NewProvider(dynamoClient)
|
||||
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(ws)
|
||||
settingStore := settingstore.New(ws)
|
||||
|
||||
tableService := tables.NewService(dynamoProvider)
|
||||
if *flagRO {
|
||||
if err := settingStore.SetReadOnly(*flagRO); err != nil {
|
||||
cli.Fatalf("unable to set read-only mode: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
tableService := tables.NewService(dynamoProvider, settingStore)
|
||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||
itemRendererService := itemrenderer.NewService(uiStyles.ItemView.FieldType, uiStyles.ItemView.MetaInfo)
|
||||
|
||||
state := controllers.NewState()
|
||||
tableReadController := controllers.NewTableReadController(state, tableService, workspaceService, itemRendererService, *flagTable, true)
|
||||
tableWriteController := controllers.NewTableWriteController(state, tableService, tableReadController)
|
||||
tableWriteController := controllers.NewTableWriteController(state, tableService, tableReadController, settingStore)
|
||||
settingsController := controllers.NewSettingsController(settingStore)
|
||||
keyBindings := keybindings.Default()
|
||||
|
||||
keyBindingService := keybindings_service.NewService(keyBindings)
|
||||
|
@ -91,6 +101,7 @@ func main() {
|
|||
model := ui.NewModel(
|
||||
tableReadController,
|
||||
tableWriteController,
|
||||
settingsController,
|
||||
itemRendererService,
|
||||
commandController,
|
||||
keyBindingController,
|
||||
|
|
|
@ -10,6 +10,11 @@ type ErrorMsg error
|
|||
// Message indicates that a message should be shown to the user
|
||||
type StatusMsg string
|
||||
|
||||
type WrappedStatusMsg struct {
|
||||
Message StatusMsg
|
||||
Next tea.Msg
|
||||
}
|
||||
|
||||
// ModeMessage indicates that the mode should be changed to the following
|
||||
type ModeMessage string
|
||||
|
||||
|
|
|
@ -10,6 +10,9 @@ type SetTableItemView struct {
|
|||
ViewIndex int
|
||||
}
|
||||
|
||||
type SettingsUpdated struct {
|
||||
}
|
||||
|
||||
type NewResultSet struct {
|
||||
ResultSet *models.ResultSet
|
||||
currentFilter string
|
||||
|
@ -44,10 +47,6 @@ func (rs NewResultSet) StatusMessage() string {
|
|||
}
|
||||
}
|
||||
|
||||
type SetReadWrite struct {
|
||||
NewValue bool
|
||||
}
|
||||
|
||||
type PromptForTableMsg struct {
|
||||
Tables []string
|
||||
OnSelected func(tableName string) tea.Msg
|
||||
|
|
|
@ -12,3 +12,8 @@ type TableReadService interface {
|
|||
Filter(resultSet *models.ResultSet, filter string) *models.ResultSet
|
||||
ScanOrQuery(ctx context.Context, tableInfo *models.TableInfo, query models.Queryable) (*models.ResultSet, error)
|
||||
}
|
||||
|
||||
type SettingsProvider interface {
|
||||
IsReadOnly() (bool, error)
|
||||
SetReadOnly(ro bool) error
|
||||
}
|
||||
|
|
49
internal/dynamo-browse/controllers/settings.go
Normal file
49
internal/dynamo-browse/controllers/settings.go
Normal file
|
@ -0,0 +1,49 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/lmika/audax/internal/common/ui/events"
|
||||
"github.com/pkg/errors"
|
||||
"log"
|
||||
)
|
||||
|
||||
type SettingsController struct {
|
||||
settings SettingsProvider
|
||||
}
|
||||
|
||||
func NewSettingsController(sp SettingsProvider) *SettingsController {
|
||||
return &SettingsController{
|
||||
settings: sp,
|
||||
}
|
||||
}
|
||||
|
||||
func (sc *SettingsController) SetSetting(name string, value string) tea.Msg {
|
||||
switch name {
|
||||
case "ro":
|
||||
if err := sc.settings.SetReadOnly(true); err != nil {
|
||||
return events.Error(err)
|
||||
}
|
||||
return events.WrappedStatusMsg{
|
||||
Message: "In read-only mode",
|
||||
Next: SettingsUpdated{},
|
||||
}
|
||||
case "rw":
|
||||
if err := sc.settings.SetReadOnly(false); err != nil {
|
||||
return events.Error(err)
|
||||
}
|
||||
return events.WrappedStatusMsg{
|
||||
Message: "In read-write mode",
|
||||
Next: SettingsUpdated{},
|
||||
}
|
||||
}
|
||||
return events.Error(errors.Errorf("unrecognised setting: %v", name))
|
||||
}
|
||||
|
||||
func (sc *SettingsController) IsReadOnly() bool {
|
||||
ro, err := sc.settings.IsReadOnly()
|
||||
if err != nil {
|
||||
log.Printf("warn: unable to determine if R/O is available: %v", err)
|
||||
return false
|
||||
}
|
||||
return ro
|
||||
}
|
30
internal/dynamo-browse/controllers/settings_test.go
Normal file
30
internal/dynamo-browse/controllers/settings_test.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
package controllers_test
|
||||
|
||||
import (
|
||||
"github.com/lmika/audax/internal/common/ui/events"
|
||||
"github.com/lmika/audax/internal/dynamo-browse/controllers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSettingsController_SetSetting(t *testing.T) {
|
||||
t.Run("read-only setting", func(t *testing.T) {
|
||||
srv := newService(t, false)
|
||||
|
||||
msg := invokeCommand(t, srv.settingsController.SetSetting("ro", ""))
|
||||
|
||||
assert.True(t, srv.settingsController.IsReadOnly())
|
||||
assert.IsType(t, events.WrappedStatusMsg{}, msg)
|
||||
assert.IsType(t, controllers.SettingsUpdated{}, msg.(events.WrappedStatusMsg).Next)
|
||||
})
|
||||
|
||||
t.Run("read-write setting", func(t *testing.T) {
|
||||
srv := newService(t, true)
|
||||
|
||||
msg := invokeCommand(t, srv.settingsController.SetSetting("rw", ""))
|
||||
|
||||
assert.False(t, srv.settingsController.IsReadOnly())
|
||||
assert.IsType(t, events.WrappedStatusMsg{}, msg)
|
||||
assert.IsType(t, controllers.SettingsUpdated{}, msg.(events.WrappedStatusMsg).Next)
|
||||
})
|
||||
}
|
|
@ -26,7 +26,7 @@ func TestTableReadController_InitTable(t *testing.T) {
|
|||
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||
|
||||
provider := dynamo.NewProvider(client)
|
||||
service := tables.NewService(provider)
|
||||
service := tables.NewService(provider, &mockedSetting{})
|
||||
|
||||
t.Run("should prompt for table if no table name provided", func(t *testing.T) {
|
||||
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "", false)
|
||||
|
@ -53,7 +53,7 @@ func TestTableReadController_ListTables(t *testing.T) {
|
|||
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||
|
||||
provider := dynamo.NewProvider(client)
|
||||
service := tables.NewService(provider)
|
||||
service := tables.NewService(provider, &mockedSetting{})
|
||||
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "", false)
|
||||
|
||||
t.Run("returns a list of tables", func(t *testing.T) {
|
||||
|
@ -78,7 +78,7 @@ func TestTableReadController_Rescan(t *testing.T) {
|
|||
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||
|
||||
provider := dynamo.NewProvider(client)
|
||||
service := tables.NewService(provider)
|
||||
service := tables.NewService(provider, &mockedSetting{})
|
||||
state := controllers.NewState()
|
||||
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "bravo-table", false)
|
||||
|
||||
|
@ -116,7 +116,7 @@ func TestTableReadController_ExportCSV(t *testing.T) {
|
|||
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||
|
||||
provider := dynamo.NewProvider(client)
|
||||
service := tables.NewService(provider)
|
||||
service := tables.NewService(provider, &mockedSetting{})
|
||||
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "bravo-table", false)
|
||||
|
||||
t.Run("should export result set to CSV file", func(t *testing.T) {
|
||||
|
@ -155,7 +155,7 @@ func TestTableReadController_Query(t *testing.T) {
|
|||
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||
|
||||
provider := dynamo.NewProvider(client)
|
||||
service := tables.NewService(provider)
|
||||
service := tables.NewService(provider, &mockedSetting{})
|
||||
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "bravo-table", false)
|
||||
|
||||
t.Run("should run scan with filter based on user query", func(t *testing.T) {
|
||||
|
|
|
@ -17,13 +17,15 @@ type TableWriteController struct {
|
|||
state *State
|
||||
tableService *tables.Service
|
||||
tableReadControllers *TableReadController
|
||||
settingProvider SettingsProvider
|
||||
}
|
||||
|
||||
func NewTableWriteController(state *State, tableService *tables.Service, tableReadControllers *TableReadController) *TableWriteController {
|
||||
func NewTableWriteController(state *State, tableService *tables.Service, tableReadControllers *TableReadController, settingProvider SettingsProvider) *TableWriteController {
|
||||
return &TableWriteController{
|
||||
state: state,
|
||||
tableService: tableService,
|
||||
tableReadControllers: tableReadControllers,
|
||||
settingProvider: settingProvider,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,6 +38,10 @@ func (twc *TableWriteController) ToggleMark(idx int) tea.Msg {
|
|||
}
|
||||
|
||||
func (twc *TableWriteController) NewItem() tea.Msg {
|
||||
if err := twc.assertReadWrite(); err != nil {
|
||||
return events.Error(err)
|
||||
}
|
||||
|
||||
// Work out which keys we need to prompt for
|
||||
rs := twc.state.ResultSet()
|
||||
|
||||
|
@ -226,6 +232,10 @@ func (twc *TableWriteController) DeleteAttribute(idx int, key string) tea.Msg {
|
|||
}
|
||||
|
||||
func (twc *TableWriteController) PutItem(idx int) tea.Msg {
|
||||
if err := twc.assertReadWrite(); err != nil {
|
||||
return events.Error(err)
|
||||
}
|
||||
|
||||
resultSet := twc.state.ResultSet()
|
||||
if !resultSet.IsDirty(idx) {
|
||||
return events.Error(errors.New("item is not dirty"))
|
||||
|
@ -247,6 +257,10 @@ func (twc *TableWriteController) PutItem(idx int) tea.Msg {
|
|||
}
|
||||
|
||||
func (twc *TableWriteController) PutItems() tea.Msg {
|
||||
if err := twc.assertReadWrite(); err != nil {
|
||||
return events.Error(err)
|
||||
}
|
||||
|
||||
var (
|
||||
markedItemCount int
|
||||
)
|
||||
|
@ -309,6 +323,10 @@ func (twc *TableWriteController) PutItems() tea.Msg {
|
|||
}
|
||||
|
||||
func (twc *TableWriteController) TouchItem(idx int) tea.Msg {
|
||||
if err := twc.assertReadWrite(); err != nil {
|
||||
return events.Error(err)
|
||||
}
|
||||
|
||||
resultSet := twc.state.ResultSet()
|
||||
if resultSet.IsDirty(idx) {
|
||||
return events.Error(errors.New("cannot touch dirty items"))
|
||||
|
@ -330,6 +348,10 @@ func (twc *TableWriteController) TouchItem(idx int) tea.Msg {
|
|||
}
|
||||
|
||||
func (twc *TableWriteController) NoisyTouchItem(idx int) tea.Msg {
|
||||
if err := twc.assertReadWrite(); err != nil {
|
||||
return events.Error(err)
|
||||
}
|
||||
|
||||
resultSet := twc.state.ResultSet()
|
||||
if resultSet.IsDirty(idx) {
|
||||
return events.Error(errors.New("cannot noisy touch dirty items"))
|
||||
|
@ -359,6 +381,10 @@ func (twc *TableWriteController) NoisyTouchItem(idx int) tea.Msg {
|
|||
}
|
||||
|
||||
func (twc *TableWriteController) DeleteMarked() tea.Msg {
|
||||
if err := twc.assertReadWrite(); err != nil {
|
||||
return events.Error(err)
|
||||
}
|
||||
|
||||
resultSet := twc.state.ResultSet()
|
||||
markedItems := resultSet.MarkedItems()
|
||||
|
||||
|
@ -385,6 +411,16 @@ func (twc *TableWriteController) DeleteMarked() tea.Msg {
|
|||
}
|
||||
}
|
||||
|
||||
func (twc *TableWriteController) assertReadWrite() error {
|
||||
b, err := twc.settingProvider.IsReadOnly()
|
||||
if err != nil {
|
||||
return err
|
||||
} else if b {
|
||||
return models.ErrReadOnly
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyToN(prefix string, n int, singular, plural, suffix string) string {
|
||||
if n == 1 {
|
||||
return fmt.Sprintf("%v%v %v%v", prefix, n, singular, suffix)
|
||||
|
|
|
@ -16,27 +16,16 @@ import (
|
|||
)
|
||||
|
||||
func TestTableWriteController_NewItem(t *testing.T) {
|
||||
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||
|
||||
t.Run("should add an item with pk and sk set at the end of the result set", func(t *testing.T) {
|
||||
client := testdynamo.SetupTestTable(t, testData)
|
||||
srv := newService(t, false)
|
||||
|
||||
provider := dynamo.NewProvider(client)
|
||||
service := tables.NewService(provider)
|
||||
|
||||
state := controllers.NewState()
|
||||
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
|
||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||
|
||||
invokeCommand(t, readController.Init())
|
||||
assert.Len(t, state.ResultSet().Items(), 3)
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
assert.Len(t, srv.state.ResultSet().Items(), 3)
|
||||
|
||||
// Prompt for keys
|
||||
invokeCommandWithPrompts(t, writeController.NewItem(), "pk-value", "sk-value")
|
||||
invokeCommandWithPrompts(t, srv.writeController.NewItem(), "pk-value", "sk-value")
|
||||
|
||||
newResultSet := state.ResultSet()
|
||||
newResultSet := srv.state.ResultSet()
|
||||
assert.Len(t, newResultSet.Items(), 4)
|
||||
assert.Len(t, newResultSet.Items()[3], 2)
|
||||
|
||||
|
@ -47,13 +36,25 @@ func TestTableWriteController_NewItem(t *testing.T) {
|
|||
assert.True(t, newResultSet.IsNew(3))
|
||||
assert.True(t, newResultSet.IsDirty(3))
|
||||
})
|
||||
|
||||
t.Run("should do nothing when in read-only mode", func(t *testing.T) {
|
||||
srv := newService(t, true)
|
||||
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
assert.Len(t, srv.state.ResultSet().Items(), 3)
|
||||
|
||||
// Prompt for keys
|
||||
invokeCommandExpectingError(t, srv.writeController.NewItem())
|
||||
|
||||
// Confirm no changes
|
||||
invokeCommand(t, srv.readController.Rescan())
|
||||
|
||||
newResultSet := srv.state.ResultSet()
|
||||
assert.Len(t, newResultSet.Items(), 3)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTableWriteController_SetAttributeValue(t *testing.T) {
|
||||
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||
|
||||
t.Run("should preserve the type of the field if unspecified", func(t *testing.T) {
|
||||
|
||||
scenarios := []struct {
|
||||
|
@ -85,51 +86,32 @@ func TestTableWriteController_SetAttributeValue(t *testing.T) {
|
|||
|
||||
for _, scenario := range scenarios {
|
||||
t.Run(fmt.Sprintf("should set value of field: %v", scenario.attrKey), func(t *testing.T) {
|
||||
client := testdynamo.SetupTestTable(t, testData)
|
||||
srv := newService(t, false)
|
||||
|
||||
provider := dynamo.NewProvider(client)
|
||||
service := tables.NewService(provider)
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
invokeCommandWithPrompt(t, srv.writeController.SetAttributeValue(0, models.UnsetItemType, scenario.attrKey), scenario.attrValue)
|
||||
|
||||
state := controllers.NewState()
|
||||
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
|
||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||
|
||||
invokeCommand(t, readController.Init())
|
||||
invokeCommandWithPrompt(t, writeController.SetAttributeValue(0, models.UnsetItemType, scenario.attrKey), scenario.attrValue)
|
||||
|
||||
after, _ := state.ResultSet().Items()[0][scenario.attrKey]
|
||||
after, _ := srv.state.ResultSet().Items()[0][scenario.attrKey]
|
||||
assert.Equal(t, scenario.expected, after)
|
||||
assert.True(t, state.ResultSet().IsDirty(0))
|
||||
assert.True(t, srv.state.ResultSet().IsDirty(0))
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("should use type of selected item for marked fields if unspecified", func(t *testing.T) {
|
||||
client := testdynamo.SetupTestTable(t, testData)
|
||||
srv := newService(t, false)
|
||||
|
||||
provider := dynamo.NewProvider(client)
|
||||
service := tables.NewService(provider)
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
invokeCommand(t, srv.writeController.ToggleMark(0))
|
||||
invokeCommandWithPrompt(t, srv.writeController.SetAttributeValue(1, models.UnsetItemType, "alpha"), "a brand new value")
|
||||
|
||||
state := controllers.NewState()
|
||||
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
|
||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||
|
||||
invokeCommand(t, readController.Init())
|
||||
invokeCommand(t, writeController.ToggleMark(0))
|
||||
invokeCommandWithPrompt(t, writeController.SetAttributeValue(1, models.UnsetItemType, "alpha"), "a brand new value")
|
||||
|
||||
after1 := state.ResultSet().Items()[0]["alpha"].(*types.AttributeValueMemberS).Value
|
||||
after1 := srv.state.ResultSet().Items()[0]["alpha"].(*types.AttributeValueMemberS).Value
|
||||
assert.Equal(t, "a brand new value", after1)
|
||||
assert.True(t, state.ResultSet().IsDirty(0))
|
||||
assert.False(t, state.ResultSet().IsDirty(1))
|
||||
assert.True(t, srv.state.ResultSet().IsDirty(0))
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(1))
|
||||
})
|
||||
|
||||
t.Run("should change the value to a particular field if already present", func(t *testing.T) {
|
||||
client := testdynamo.SetupTestTable(t, testData)
|
||||
|
||||
provider := dynamo.NewProvider(client)
|
||||
service := tables.NewService(provider)
|
||||
|
||||
scenarios := []struct {
|
||||
attrType models.ItemType
|
||||
attrValue string
|
||||
|
@ -164,97 +146,80 @@ func TestTableWriteController_SetAttributeValue(t *testing.T) {
|
|||
|
||||
for _, scenario := range scenarios {
|
||||
t.Run(fmt.Sprintf("should change the value of a field to type %v", scenario.attrType), func(t *testing.T) {
|
||||
state := controllers.NewState()
|
||||
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
|
||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||
srv := newService(t, false)
|
||||
|
||||
invokeCommand(t, readController.Init())
|
||||
before, _ := state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
before, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "This is some value", before)
|
||||
assert.False(t, state.ResultSet().IsDirty(0))
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
|
||||
if scenario.attrValue == "" {
|
||||
invokeCommand(t, writeController.SetAttributeValue(0, scenario.attrType, "alpha"))
|
||||
invokeCommand(t, srv.writeController.SetAttributeValue(0, scenario.attrType, "alpha"))
|
||||
} else {
|
||||
invokeCommandWithPrompt(t, writeController.SetAttributeValue(0, scenario.attrType, "alpha"), scenario.attrValue)
|
||||
invokeCommandWithPrompt(t, srv.writeController.SetAttributeValue(0, scenario.attrType, "alpha"), scenario.attrValue)
|
||||
}
|
||||
|
||||
after, _ := state.ResultSet().Items()[0]["alpha"]
|
||||
after, _ := srv.state.ResultSet().Items()[0]["alpha"]
|
||||
assert.Equal(t, scenario.expected, after)
|
||||
assert.True(t, state.ResultSet().IsDirty(0))
|
||||
assert.True(t, srv.state.ResultSet().IsDirty(0))
|
||||
})
|
||||
|
||||
t.Run(fmt.Sprintf("should change value of nested field to type %v", scenario.attrType), func(t *testing.T) {
|
||||
state := controllers.NewState()
|
||||
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
|
||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||
srv := newService(t, false)
|
||||
|
||||
invokeCommand(t, readController.Init())
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
|
||||
beforeAddress := state.ResultSet().Items()[0]["address"].(*types.AttributeValueMemberM)
|
||||
beforeAddress := srv.state.ResultSet().Items()[0]["address"].(*types.AttributeValueMemberM)
|
||||
beforeStreet := beforeAddress.Value["street"].(*types.AttributeValueMemberS).Value
|
||||
|
||||
assert.Equal(t, "Fake st.", beforeStreet)
|
||||
assert.False(t, state.ResultSet().IsDirty(0))
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
|
||||
if scenario.attrValue == "" {
|
||||
invokeCommand(t, writeController.SetAttributeValue(0, scenario.attrType, "address.street"))
|
||||
invokeCommand(t, srv.writeController.SetAttributeValue(0, scenario.attrType, "address.street"))
|
||||
} else {
|
||||
invokeCommandWithPrompt(t, writeController.SetAttributeValue(0, scenario.attrType, "address.street"), scenario.attrValue)
|
||||
invokeCommandWithPrompt(t, srv.writeController.SetAttributeValue(0, scenario.attrType, "address.street"), scenario.attrValue)
|
||||
}
|
||||
|
||||
afterAddress := state.ResultSet().Items()[0]["address"].(*types.AttributeValueMemberM)
|
||||
afterAddress := srv.state.ResultSet().Items()[0]["address"].(*types.AttributeValueMemberM)
|
||||
after := afterAddress.Value["street"]
|
||||
|
||||
assert.Equal(t, scenario.expected, after)
|
||||
assert.True(t, state.ResultSet().IsDirty(0))
|
||||
assert.True(t, srv.state.ResultSet().IsDirty(0))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestTableWriteController_DeleteAttribute(t *testing.T) {
|
||||
client := testdynamo.SetupTestTable(t, testData)
|
||||
|
||||
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||
|
||||
provider := dynamo.NewProvider(client)
|
||||
service := tables.NewService(provider)
|
||||
|
||||
t.Run("should delete top level attribute", func(t *testing.T) {
|
||||
state := controllers.NewState()
|
||||
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
|
||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||
srv := newService(t, false)
|
||||
|
||||
invokeCommand(t, readController.Init())
|
||||
before, _ := state.ResultSet().Items()[0].AttributeValueAsString("age")
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
before, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("age")
|
||||
assert.Equal(t, "23", before)
|
||||
assert.False(t, state.ResultSet().IsDirty(0))
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
|
||||
invokeCommand(t, writeController.DeleteAttribute(0, "age"))
|
||||
invokeCommand(t, srv.writeController.DeleteAttribute(0, "age"))
|
||||
|
||||
_, hasAge := state.ResultSet().Items()[0]["age"]
|
||||
_, hasAge := srv.state.ResultSet().Items()[0]["age"]
|
||||
assert.False(t, hasAge)
|
||||
})
|
||||
|
||||
t.Run("should delete attribute of map", func(t *testing.T) {
|
||||
state := controllers.NewState()
|
||||
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
|
||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||
srv := newService(t, false)
|
||||
|
||||
invokeCommand(t, readController.Init())
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
|
||||
beforeAddress := state.ResultSet().Items()[0]["address"].(*types.AttributeValueMemberM)
|
||||
beforeAddress := srv.state.ResultSet().Items()[0]["address"].(*types.AttributeValueMemberM)
|
||||
beforeStreet := beforeAddress.Value["no"].(*types.AttributeValueMemberN).Value
|
||||
|
||||
assert.Equal(t, "123", beforeStreet)
|
||||
assert.False(t, state.ResultSet().IsDirty(0))
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
|
||||
invokeCommand(t, writeController.DeleteAttribute(0, "address.no"))
|
||||
invokeCommand(t, srv.writeController.DeleteAttribute(0, "address.no"))
|
||||
|
||||
afterAddress := state.ResultSet().Items()[0]["address"].(*types.AttributeValueMemberM)
|
||||
afterAddress := srv.state.ResultSet().Items()[0]["address"].(*types.AttributeValueMemberM)
|
||||
_, hasStreet := afterAddress.Value["no"]
|
||||
|
||||
assert.False(t, hasStreet)
|
||||
|
@ -262,296 +227,383 @@ func TestTableWriteController_DeleteAttribute(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestTableWriteController_PutItem(t *testing.T) {
|
||||
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||
|
||||
t.Run("should put the selected item if dirty", func(t *testing.T) {
|
||||
client := testdynamo.SetupTestTable(t, testData)
|
||||
|
||||
provider := dynamo.NewProvider(client)
|
||||
service := tables.NewService(provider)
|
||||
|
||||
state := controllers.NewState()
|
||||
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
|
||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||
srv := newService(t, false)
|
||||
|
||||
// Read the table
|
||||
invokeCommand(t, readController.Init())
|
||||
before, _ := state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
before, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "This is some value", before)
|
||||
assert.False(t, state.ResultSet().IsDirty(0))
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
|
||||
// Modify the item and put it
|
||||
invokeCommandWithPrompt(t, writeController.SetAttributeValue(0, models.StringItemType, "alpha"), "a new value")
|
||||
invokeCommandWithPrompt(t, writeController.PutItem(0), "y")
|
||||
invokeCommandWithPrompt(t, srv.writeController.SetAttributeValue(0, models.StringItemType, "alpha"), "a new value")
|
||||
invokeCommandWithPrompt(t, srv.writeController.PutItem(0), "y")
|
||||
|
||||
// Rescan the table
|
||||
invokeCommand(t, readController.Rescan())
|
||||
after, _ := state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
invokeCommand(t, srv.readController.Rescan())
|
||||
after, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "a new value", after)
|
||||
assert.False(t, state.ResultSet().IsDirty(0))
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
})
|
||||
|
||||
t.Run("should not put the selected item if user does not confirm", func(t *testing.T) {
|
||||
client := testdynamo.SetupTestTable(t, testData)
|
||||
|
||||
provider := dynamo.NewProvider(client)
|
||||
service := tables.NewService(provider)
|
||||
|
||||
state := controllers.NewState()
|
||||
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
|
||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||
srv := newService(t, false)
|
||||
|
||||
// Read the table
|
||||
invokeCommand(t, readController.Init())
|
||||
before, _ := state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
before, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "This is some value", before)
|
||||
assert.False(t, state.ResultSet().IsDirty(0))
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
|
||||
// Modify the item but do not put it
|
||||
invokeCommandWithPrompt(t, writeController.SetAttributeValue(0, models.StringItemType, "alpha"), "a new value")
|
||||
invokeCommandWithPrompt(t, writeController.PutItem(0), "n")
|
||||
invokeCommandWithPrompt(t, srv.writeController.SetAttributeValue(0, models.StringItemType, "alpha"), "a new value")
|
||||
invokeCommandWithPrompt(t, srv.writeController.PutItem(0), "n")
|
||||
|
||||
current, _ := state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
current, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "a new value", current)
|
||||
assert.True(t, state.ResultSet().IsDirty(0))
|
||||
assert.True(t, srv.state.ResultSet().IsDirty(0))
|
||||
|
||||
// Rescan the table to confirm item is not modified
|
||||
invokeCommandWithPrompt(t, readController.Rescan(), "y")
|
||||
after, _ := state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
invokeCommandWithPrompt(t, srv.readController.Rescan(), "y")
|
||||
after, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "This is some value", after)
|
||||
assert.False(t, state.ResultSet().IsDirty(0))
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
})
|
||||
|
||||
t.Run("should not put the selected item if not dirty", func(t *testing.T) {
|
||||
client := testdynamo.SetupTestTable(t, testData)
|
||||
|
||||
provider := dynamo.NewProvider(client)
|
||||
service := tables.NewService(provider)
|
||||
|
||||
state := controllers.NewState()
|
||||
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
|
||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||
srv := newService(t, false)
|
||||
|
||||
// Read the table
|
||||
invokeCommand(t, readController.Init())
|
||||
before, _ := state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
before, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "This is some value", before)
|
||||
assert.False(t, state.ResultSet().IsDirty(0))
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
|
||||
invokeCommandExpectingError(t, writeController.PutItem(0))
|
||||
invokeCommandExpectingError(t, srv.writeController.PutItem(0))
|
||||
})
|
||||
|
||||
t.Run("should not put the selected item if in read-only mode", func(t *testing.T) {
|
||||
srv := newService(t, true)
|
||||
|
||||
// Read the table
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
before, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "This is some value", before)
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
|
||||
// Modify the item but do not put it
|
||||
invokeCommandWithPrompt(t, srv.writeController.SetAttributeValue(0, models.StringItemType, "alpha"), "a new value")
|
||||
invokeCommandExpectingError(t, srv.writeController.PutItem(0))
|
||||
|
||||
current, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "a new value", current)
|
||||
assert.True(t, srv.state.ResultSet().IsDirty(0))
|
||||
|
||||
// Rescan the table to confirm item is not modified
|
||||
invokeCommandWithPrompt(t, srv.readController.Rescan(), "y")
|
||||
after, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "This is some value", after)
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
})
|
||||
}
|
||||
|
||||
func TestTableWriteController_PutItems(t *testing.T) {
|
||||
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||
|
||||
t.Run("should put all dirty items if none are marked", func(t *testing.T) {
|
||||
client := testdynamo.SetupTestTable(t, testData)
|
||||
srv := newService(t, false)
|
||||
|
||||
provider := dynamo.NewProvider(client)
|
||||
service := tables.NewService(provider)
|
||||
|
||||
state := controllers.NewState()
|
||||
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
|
||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||
|
||||
invokeCommand(t, readController.Init())
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
|
||||
// Modify the item and put it
|
||||
invokeCommandWithPrompt(t, writeController.SetAttributeValue(0, models.StringItemType, "alpha"), "a new value")
|
||||
invokeCommandWithPrompt(t, writeController.SetAttributeValue(2, models.StringItemType, "alpha"), "another new value")
|
||||
invokeCommandWithPrompt(t, srv.writeController.SetAttributeValue(0, models.StringItemType, "alpha"), "a new value")
|
||||
invokeCommandWithPrompt(t, srv.writeController.SetAttributeValue(2, models.StringItemType, "alpha"), "another new value")
|
||||
|
||||
invokeCommandWithPrompt(t, writeController.PutItems(), "y")
|
||||
invokeCommandWithPrompt(t, srv.writeController.PutItems(), "y")
|
||||
|
||||
// Rescan the table
|
||||
invokeCommand(t, readController.Rescan())
|
||||
invokeCommand(t, srv.readController.Rescan())
|
||||
|
||||
assert.Equal(t, "a new value", state.ResultSet().Items()[0]["alpha"].(*types.AttributeValueMemberS).Value)
|
||||
assert.Equal(t, "another new value", state.ResultSet().Items()[2]["alpha"].(*types.AttributeValueMemberS).Value)
|
||||
assert.Equal(t, "a new value", srv.state.ResultSet().Items()[0]["alpha"].(*types.AttributeValueMemberS).Value)
|
||||
assert.Equal(t, "another new value", srv.state.ResultSet().Items()[2]["alpha"].(*types.AttributeValueMemberS).Value)
|
||||
|
||||
assert.False(t, state.ResultSet().IsDirty(0))
|
||||
assert.False(t, state.ResultSet().IsDirty(2))
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(2))
|
||||
})
|
||||
|
||||
t.Run("only put marked items", func(t *testing.T) {
|
||||
client := testdynamo.SetupTestTable(t, testData)
|
||||
srv := newService(t, false)
|
||||
|
||||
provider := dynamo.NewProvider(client)
|
||||
service := tables.NewService(provider)
|
||||
|
||||
state := controllers.NewState()
|
||||
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
|
||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||
|
||||
invokeCommand(t, readController.Init())
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
|
||||
// Modify the item and put it
|
||||
invokeCommandWithPrompt(t, writeController.SetAttributeValue(0, models.StringItemType, "alpha"), "a new value")
|
||||
invokeCommandWithPrompt(t, writeController.SetAttributeValue(2, models.StringItemType, "alpha"), "another new value")
|
||||
invokeCommand(t, writeController.ToggleMark(0))
|
||||
invokeCommandWithPrompt(t, srv.writeController.SetAttributeValue(0, models.StringItemType, "alpha"), "a new value")
|
||||
invokeCommandWithPrompt(t, srv.writeController.SetAttributeValue(2, models.StringItemType, "alpha"), "another new value")
|
||||
invokeCommand(t, srv.writeController.ToggleMark(0))
|
||||
|
||||
invokeCommandWithPrompt(t, writeController.PutItems(), "y")
|
||||
invokeCommandWithPrompt(t, srv.writeController.PutItems(), "y")
|
||||
|
||||
// Verify dirty items are unchanged
|
||||
assert.Equal(t, "a new value", state.ResultSet().Items()[0]["alpha"].(*types.AttributeValueMemberS).Value)
|
||||
assert.Equal(t, "another new value", state.ResultSet().Items()[2]["alpha"].(*types.AttributeValueMemberS).Value)
|
||||
assert.Equal(t, "a new value", srv.state.ResultSet().Items()[0]["alpha"].(*types.AttributeValueMemberS).Value)
|
||||
assert.Equal(t, "another new value", srv.state.ResultSet().Items()[2]["alpha"].(*types.AttributeValueMemberS).Value)
|
||||
|
||||
assert.False(t, state.ResultSet().IsDirty(0))
|
||||
assert.True(t, state.ResultSet().IsDirty(2))
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
assert.True(t, srv.state.ResultSet().IsDirty(2))
|
||||
|
||||
// Rescan the table and verify dirty items were not written
|
||||
invokeCommandWithPrompt(t, readController.Rescan(), "y")
|
||||
invokeCommandWithPrompt(t, srv.readController.Rescan(), "y")
|
||||
|
||||
assert.Equal(t, "a new value", state.ResultSet().Items()[0]["alpha"].(*types.AttributeValueMemberS).Value)
|
||||
assert.Nil(t, state.ResultSet().Items()[2]["alpha"])
|
||||
assert.Equal(t, "a new value", srv.state.ResultSet().Items()[0]["alpha"].(*types.AttributeValueMemberS).Value)
|
||||
assert.Nil(t, srv.state.ResultSet().Items()[2]["alpha"])
|
||||
|
||||
assert.False(t, state.ResultSet().IsDirty(0))
|
||||
assert.False(t, state.ResultSet().IsDirty(2))
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(2))
|
||||
})
|
||||
|
||||
t.Run("do not put marked items which are not diry", func(t *testing.T) {
|
||||
client := testdynamo.SetupTestTable(t, testData)
|
||||
t.Run("do not put marked items which are not dirty", func(t *testing.T) {
|
||||
srv := newService(t, false)
|
||||
|
||||
provider := dynamo.NewProvider(client)
|
||||
service := tables.NewService(provider)
|
||||
|
||||
state := controllers.NewState()
|
||||
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
|
||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||
|
||||
invokeCommand(t, readController.Init())
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
|
||||
// Modify the item and put it
|
||||
invokeCommandWithPrompt(t, writeController.SetAttributeValue(0, models.StringItemType, "alpha"), "a new value")
|
||||
invokeCommandWithPrompt(t, writeController.SetAttributeValue(2, models.StringItemType, "alpha"), "another new value")
|
||||
invokeCommand(t, writeController.ToggleMark(1))
|
||||
invokeCommandWithPrompt(t, srv.writeController.SetAttributeValue(0, models.StringItemType, "alpha"), "a new value")
|
||||
invokeCommandWithPrompt(t, srv.writeController.SetAttributeValue(2, models.StringItemType, "alpha"), "another new value")
|
||||
invokeCommand(t, srv.writeController.ToggleMark(1))
|
||||
|
||||
invokeCommand(t, writeController.PutItems())
|
||||
invokeCommand(t, srv.writeController.PutItems())
|
||||
|
||||
// Verify dirty items are unchanged
|
||||
assert.Equal(t, "a new value", state.ResultSet().Items()[0]["alpha"].(*types.AttributeValueMemberS).Value)
|
||||
assert.Equal(t, "another new value", state.ResultSet().Items()[2]["alpha"].(*types.AttributeValueMemberS).Value)
|
||||
assert.Equal(t, "a new value", srv.state.ResultSet().Items()[0]["alpha"].(*types.AttributeValueMemberS).Value)
|
||||
assert.Equal(t, "another new value", srv.state.ResultSet().Items()[2]["alpha"].(*types.AttributeValueMemberS).Value)
|
||||
|
||||
assert.True(t, state.ResultSet().IsDirty(0))
|
||||
assert.True(t, state.ResultSet().IsDirty(2))
|
||||
assert.True(t, srv.state.ResultSet().IsDirty(0))
|
||||
assert.True(t, srv.state.ResultSet().IsDirty(2))
|
||||
|
||||
// Rescan the table and verify dirty items were not written
|
||||
invokeCommandWithPrompt(t, readController.Rescan(), "y")
|
||||
invokeCommandWithPrompt(t, srv.readController.Rescan(), "y")
|
||||
|
||||
assert.Equal(t, "This is some value", state.ResultSet().Items()[0]["alpha"].(*types.AttributeValueMemberS).Value)
|
||||
assert.Nil(t, state.ResultSet().Items()[2]["alpha"])
|
||||
assert.Equal(t, "This is some value", srv.state.ResultSet().Items()[0]["alpha"].(*types.AttributeValueMemberS).Value)
|
||||
assert.Nil(t, srv.state.ResultSet().Items()[2]["alpha"])
|
||||
|
||||
assert.False(t, state.ResultSet().IsDirty(0))
|
||||
assert.False(t, state.ResultSet().IsDirty(2))
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(2))
|
||||
})
|
||||
|
||||
t.Run("do nothing if in read-only mode", func(t *testing.T) {
|
||||
srv := newService(t, true)
|
||||
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
|
||||
// Modify the item and put it
|
||||
invokeCommandWithPrompt(t, srv.writeController.SetAttributeValue(0, models.StringItemType, "alpha"), "a new value")
|
||||
invokeCommandWithPrompt(t, srv.writeController.SetAttributeValue(2, models.StringItemType, "alpha"), "another new value")
|
||||
invokeCommand(t, srv.writeController.ToggleMark(0))
|
||||
|
||||
invokeCommandExpectingError(t, srv.writeController.PutItems())
|
||||
|
||||
// Verify dirty items are unchanged
|
||||
assert.Equal(t, "a new value", srv.state.ResultSet().Items()[0]["alpha"].(*types.AttributeValueMemberS).Value)
|
||||
assert.Equal(t, "another new value", srv.state.ResultSet().Items()[2]["alpha"].(*types.AttributeValueMemberS).Value)
|
||||
|
||||
assert.True(t, srv.state.ResultSet().IsDirty(0))
|
||||
assert.True(t, srv.state.ResultSet().IsDirty(2))
|
||||
|
||||
// Rescan the table and verify dirty items were not written
|
||||
invokeCommandWithPrompt(t, srv.readController.Rescan(), "y")
|
||||
|
||||
assert.Equal(t, "This is some value", srv.state.ResultSet().Items()[0]["alpha"].(*types.AttributeValueMemberS).Value)
|
||||
assert.Nil(t, srv.state.ResultSet().Items()[2]["alpha"])
|
||||
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(2))
|
||||
})
|
||||
}
|
||||
|
||||
func TestTableWriteController_TouchItem(t *testing.T) {
|
||||
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||
|
||||
t.Run("should put the selected item if unmodified", func(t *testing.T) {
|
||||
client := testdynamo.SetupTestTable(t, testData)
|
||||
|
||||
provider := dynamo.NewProvider(client)
|
||||
service := tables.NewService(provider)
|
||||
|
||||
state := controllers.NewState()
|
||||
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
|
||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||
srv := newService(t, false)
|
||||
|
||||
// Read the table
|
||||
invokeCommand(t, readController.Init())
|
||||
before, _ := state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
before, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "This is some value", before)
|
||||
assert.False(t, state.ResultSet().IsDirty(0))
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
|
||||
// Modify the item and put it
|
||||
invokeCommandWithPrompt(t, writeController.TouchItem(0), "y")
|
||||
invokeCommandWithPrompt(t, srv.writeController.TouchItem(0), "y")
|
||||
|
||||
// Rescan the table
|
||||
invokeCommand(t, readController.Rescan())
|
||||
after, _ := state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
invokeCommand(t, srv.readController.Rescan())
|
||||
after, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "This is some value", after)
|
||||
assert.False(t, state.ResultSet().IsDirty(0))
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
})
|
||||
|
||||
t.Run("should not put the selected item if modified", func(t *testing.T) {
|
||||
client := testdynamo.SetupTestTable(t, testData)
|
||||
|
||||
provider := dynamo.NewProvider(client)
|
||||
service := tables.NewService(provider)
|
||||
|
||||
state := controllers.NewState()
|
||||
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
|
||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||
srv := newService(t, false)
|
||||
|
||||
// Read the table
|
||||
invokeCommand(t, readController.Init())
|
||||
before, _ := state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
before, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "This is some value", before)
|
||||
assert.False(t, state.ResultSet().IsDirty(0))
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
|
||||
// Modify the item and put it
|
||||
invokeCommandWithPrompt(t, writeController.SetAttributeValue(0, models.StringItemType, "alpha"), "a new value")
|
||||
invokeCommandExpectingError(t, writeController.TouchItem(0))
|
||||
invokeCommandWithPrompt(t, srv.writeController.SetAttributeValue(0, models.StringItemType, "alpha"), "a new value")
|
||||
invokeCommandExpectingError(t, srv.writeController.TouchItem(0))
|
||||
})
|
||||
|
||||
t.Run("should not put the selected item if in read-only mode", func(t *testing.T) {
|
||||
srv := newService(t, true)
|
||||
|
||||
// Read the table
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
before, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "This is some value", before)
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
|
||||
// Modify the item and put it
|
||||
invokeCommandExpectingError(t, srv.writeController.TouchItem(0))
|
||||
|
||||
// Rescan the table
|
||||
invokeCommand(t, srv.readController.Rescan())
|
||||
after, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "This is some value", after)
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
})
|
||||
}
|
||||
|
||||
func TestTableWriteController_NoisyTouchItem(t *testing.T) {
|
||||
t.Run("should delete and put the selected item if unmodified", func(t *testing.T) {
|
||||
srv := newService(t, false)
|
||||
|
||||
// Read the table
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
before, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "This is some value", before)
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
|
||||
// Modify the item and put it
|
||||
invokeCommandWithPrompt(t, srv.writeController.NoisyTouchItem(0), "y")
|
||||
|
||||
// Rescan the table
|
||||
invokeCommand(t, srv.readController.Rescan())
|
||||
after, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "This is some value", after)
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
})
|
||||
|
||||
t.Run("should not put the selected item if modified", func(t *testing.T) {
|
||||
srv := newService(t, false)
|
||||
|
||||
// Read the table
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
before, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "This is some value", before)
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
|
||||
// Modify the item and put it
|
||||
invokeCommandWithPrompt(t, srv.writeController.SetAttributeValue(0, models.StringItemType, "alpha"), "a new value")
|
||||
invokeCommandExpectingError(t, srv.writeController.NoisyTouchItem(0))
|
||||
})
|
||||
|
||||
t.Run("should not put the selected item if in read-only mode", func(t *testing.T) {
|
||||
srv := newService(t, true)
|
||||
|
||||
// Read the table
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
before, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "This is some value", before)
|
||||
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||
|
||||
// Modify the item and put it
|
||||
invokeCommandExpectingError(t, srv.writeController.NoisyTouchItem(0))
|
||||
})
|
||||
}
|
||||
|
||||
func TestTableWriteController_DeleteMarked(t *testing.T) {
|
||||
t.Run("should delete marked items", func(t *testing.T) {
|
||||
srv := newService(t, false)
|
||||
|
||||
// Read the table
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
assert.Len(t, srv.state.ResultSet().Items(), 3)
|
||||
|
||||
// Mark some items
|
||||
invokeCommand(t, srv.writeController.ToggleMark(0))
|
||||
invokeCommand(t, srv.writeController.ToggleMark(2))
|
||||
|
||||
// Delete it
|
||||
invokeCommandWithPrompt(t, srv.writeController.DeleteMarked(), "y")
|
||||
|
||||
// Rescan and confirm marked items are deleted
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
assert.Len(t, srv.state.ResultSet().Items(), 1)
|
||||
after, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "This is another some value", after)
|
||||
})
|
||||
|
||||
t.Run("should not delete marked items if in read-only mode", func(t *testing.T) {
|
||||
srv := newService(t, true)
|
||||
|
||||
// Read the table
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
assert.Len(t, srv.state.ResultSet().Items(), 3)
|
||||
|
||||
// Mark some items
|
||||
invokeCommand(t, srv.writeController.ToggleMark(0))
|
||||
invokeCommand(t, srv.writeController.ToggleMark(2))
|
||||
|
||||
// Delete it
|
||||
invokeCommandExpectingError(t, srv.writeController.DeleteMarked())
|
||||
|
||||
// Rescan and confirm marked items are not deleted
|
||||
invokeCommand(t, srv.readController.Init())
|
||||
assert.Len(t, srv.state.ResultSet().Items(), 3)
|
||||
after, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "This is some value", after)
|
||||
})
|
||||
}
|
||||
|
||||
type services struct {
|
||||
state *controllers.State
|
||||
readController *controllers.TableReadController
|
||||
writeController *controllers.TableWriteController
|
||||
settingsController *controllers.SettingsController
|
||||
}
|
||||
|
||||
func newService(t *testing.T, isReadOnly bool) *services {
|
||||
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||
|
||||
t.Run("should delete and put the selected item if unmodified", func(t *testing.T) {
|
||||
client := testdynamo.SetupTestTable(t, testData)
|
||||
|
||||
settingProvider := &mockedSetting{isReadOnly: isReadOnly}
|
||||
provider := dynamo.NewProvider(client)
|
||||
service := tables.NewService(provider)
|
||||
service := tables.NewService(provider, settingProvider)
|
||||
|
||||
state := controllers.NewState()
|
||||
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
|
||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||
writeController := controllers.NewTableWriteController(state, service, readController, settingProvider)
|
||||
settingsController := controllers.NewSettingsController(settingProvider)
|
||||
|
||||
// Read the table
|
||||
invokeCommand(t, readController.Init())
|
||||
before, _ := state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "This is some value", before)
|
||||
assert.False(t, state.ResultSet().IsDirty(0))
|
||||
|
||||
// Modify the item and put it
|
||||
invokeCommandWithPrompt(t, writeController.NoisyTouchItem(0), "y")
|
||||
|
||||
// Rescan the table
|
||||
invokeCommand(t, readController.Rescan())
|
||||
after, _ := state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "This is some value", after)
|
||||
assert.False(t, state.ResultSet().IsDirty(0))
|
||||
})
|
||||
|
||||
t.Run("should not put the selected item if modified", func(t *testing.T) {
|
||||
client := testdynamo.SetupTestTable(t, testData)
|
||||
|
||||
provider := dynamo.NewProvider(client)
|
||||
service := tables.NewService(provider)
|
||||
|
||||
state := controllers.NewState()
|
||||
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
|
||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||
|
||||
// Read the table
|
||||
invokeCommand(t, readController.Init())
|
||||
before, _ := state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||
assert.Equal(t, "This is some value", before)
|
||||
assert.False(t, state.ResultSet().IsDirty(0))
|
||||
|
||||
// Modify the item and put it
|
||||
invokeCommandWithPrompt(t, writeController.SetAttributeValue(0, models.StringItemType, "alpha"), "a new value")
|
||||
invokeCommandExpectingError(t, writeController.NoisyTouchItem(0))
|
||||
})
|
||||
return &services{
|
||||
state: state,
|
||||
readController: readController,
|
||||
writeController: writeController,
|
||||
settingsController: settingsController,
|
||||
}
|
||||
}
|
||||
|
||||
type mockedSetting struct {
|
||||
isReadOnly bool
|
||||
}
|
||||
|
||||
func (ms *mockedSetting) SetReadOnly(ro bool) error {
|
||||
ms.isReadOnly = ro
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ms *mockedSetting) IsReadOnly() (bool, error) {
|
||||
return ms.isReadOnly, nil
|
||||
}
|
||||
|
|
5
internal/dynamo-browse/models/errors.go
Normal file
5
internal/dynamo-browse/models/errors.go
Normal file
|
@ -0,0 +1,5 @@
|
|||
package models
|
||||
|
||||
import "github.com/pkg/errors"
|
||||
|
||||
var ErrReadOnly = errors.New("in read-only mode")
|
|
@ -0,0 +1,31 @@
|
|||
package settingstore
|
||||
|
||||
import (
|
||||
"github.com/asdine/storm"
|
||||
"github.com/lmika/audax/internal/common/workspaces"
|
||||
)
|
||||
|
||||
const settingBucket = "Settings"
|
||||
|
||||
const (
|
||||
keyTableReadOnly = "table_ro"
|
||||
)
|
||||
|
||||
type SettingStore struct {
|
||||
ws storm.Node
|
||||
}
|
||||
|
||||
func New(ws *workspaces.Workspace) *SettingStore {
|
||||
return &SettingStore{
|
||||
ws: ws.DB(),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *SettingStore) IsReadOnly() (b bool, err error) {
|
||||
err = c.ws.Get(settingBucket, keyTableReadOnly, &b)
|
||||
return b, err
|
||||
}
|
||||
|
||||
func (c *SettingStore) SetReadOnly(ro bool) error {
|
||||
return c.ws.Set(settingBucket, keyTableReadOnly, ro)
|
||||
}
|
|
@ -17,3 +17,7 @@ type TableProvider interface {
|
|||
PutItem(ctx context.Context, name string, item models.Item) error
|
||||
PutItems(ctx context.Context, name string, items []models.Item) error
|
||||
}
|
||||
|
||||
type ROProvider interface {
|
||||
IsReadOnly() (bool, error)
|
||||
}
|
||||
|
|
|
@ -13,11 +13,13 @@ import (
|
|||
|
||||
type Service struct {
|
||||
provider TableProvider
|
||||
roProvider ROProvider
|
||||
}
|
||||
|
||||
func NewService(provider TableProvider) *Service {
|
||||
func NewService(provider TableProvider, roProvider ROProvider) *Service {
|
||||
return &Service{
|
||||
provider: provider,
|
||||
roProvider: roProvider,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,10 +77,18 @@ func (s *Service) doScan(ctx context.Context, tableInfo *models.TableInfo, expr
|
|||
}
|
||||
|
||||
func (s *Service) Put(ctx context.Context, tableInfo *models.TableInfo, item models.Item) error {
|
||||
if err := s.assertReadWrite(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.provider.PutItem(ctx, tableInfo.Name, item)
|
||||
}
|
||||
|
||||
func (s *Service) PutItemAt(ctx context.Context, resultSet *models.ResultSet, index int) error {
|
||||
if err := s.assertReadWrite(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
item := resultSet.Items()[index]
|
||||
if err := s.provider.PutItem(ctx, resultSet.TableInfo.Name, item); err != nil {
|
||||
return err
|
||||
|
@ -90,6 +100,10 @@ func (s *Service) PutItemAt(ctx context.Context, resultSet *models.ResultSet, in
|
|||
}
|
||||
|
||||
func (s *Service) PutSelectedItems(ctx context.Context, resultSet *models.ResultSet, markedItems []models.ItemIndex) error {
|
||||
if err := s.assertReadWrite(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(markedItems) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
@ -108,6 +122,10 @@ func (s *Service) PutSelectedItems(ctx context.Context, resultSet *models.Result
|
|||
}
|
||||
|
||||
func (s *Service) Delete(ctx context.Context, tableInfo *models.TableInfo, items []models.Item) error {
|
||||
if err := s.assertReadWrite(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, item := range items {
|
||||
if err := s.provider.DeleteItem(ctx, tableInfo.Name, item.KeyValue(tableInfo)); err != nil {
|
||||
return errors.Wrapf(err, "cannot delete item")
|
||||
|
@ -120,6 +138,16 @@ func (s *Service) ScanOrQuery(ctx context.Context, tableInfo *models.TableInfo,
|
|||
return s.doScan(ctx, tableInfo, expr)
|
||||
}
|
||||
|
||||
func (s *Service) assertReadWrite() error {
|
||||
b, err := s.roProvider.IsReadOnly()
|
||||
if err != nil {
|
||||
return err
|
||||
} else if b {
|
||||
return models.ErrReadOnly
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: move into a new service
|
||||
func (s *Service) Filter(resultSet *models.ResultSet, filter string) *models.ResultSet {
|
||||
for i, item := range resultSet.Items() {
|
||||
|
|
|
@ -19,7 +19,7 @@ func TestService_Describe(t *testing.T) {
|
|||
t.Run("return details of the table", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
service := tables.NewService(provider)
|
||||
service := tables.NewService(provider, mockedReadOnlyProvider{readOnly: false})
|
||||
ti, err := service.Describe(ctx, tableName)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
@ -40,7 +40,7 @@ func TestService_Scan(t *testing.T) {
|
|||
t.Run("return all columns and fields in sorted order", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
service := tables.NewService(provider)
|
||||
service := tables.NewService(provider, mockedReadOnlyProvider{readOnly: false})
|
||||
ti, err := service.Describe(ctx, tableName)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
@ -77,3 +77,11 @@ var testData = []testdynamo.TestData{
|
|||
},
|
||||
},
|
||||
}
|
||||
|
||||
type mockedReadOnlyProvider struct {
|
||||
readOnly bool
|
||||
}
|
||||
|
||||
func (m mockedReadOnlyProvider) IsReadOnly() (bool, error) {
|
||||
return m.readOnly, nil
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ const (
|
|||
type Model struct {
|
||||
tableReadController *controllers.TableReadController
|
||||
tableWriteController *controllers.TableWriteController
|
||||
settingsController *controllers.SettingsController
|
||||
commandController *commandctrl.CommandController
|
||||
itemEdit *dynamoitemedit.Model
|
||||
statusAndPrompt *statusandprompt.StatusAndPrompt
|
||||
|
@ -56,6 +57,7 @@ type Model struct {
|
|||
func NewModel(
|
||||
rc *controllers.TableReadController,
|
||||
wc *controllers.TableWriteController,
|
||||
settingsController *controllers.SettingsController,
|
||||
itemRendererService *itemrenderer.Service,
|
||||
cc *commandctrl.CommandController,
|
||||
keyBindingController *controllers.KeyBindingController,
|
||||
|
@ -63,7 +65,7 @@ func NewModel(
|
|||
) Model {
|
||||
uiStyles := styles.DefaultStyles
|
||||
|
||||
dtv := dynamotableview.New(defaultKeyMap.TableView, uiStyles)
|
||||
dtv := dynamotableview.New(defaultKeyMap.TableView, settingsController, uiStyles)
|
||||
div := dynamoitemview.New(itemRendererService, uiStyles)
|
||||
mainView := layout.NewVBox(layout.LastChildFixedAt(14), dtv, div)
|
||||
|
||||
|
@ -141,6 +143,15 @@ func NewModel(
|
|||
}
|
||||
return events.StatusMsg(s.String())
|
||||
},
|
||||
"set": func(ctx commandctrl.ExecContext, args []string) tea.Msg {
|
||||
switch len(args) {
|
||||
case 1:
|
||||
return settingsController.SetSetting(args[0], "")
|
||||
case 2:
|
||||
return settingsController.SetSetting(args[0], args[1])
|
||||
}
|
||||
return events.Error(errors.New("expected: settingName [value]"))
|
||||
},
|
||||
"rebind": func(ctx commandctrl.ExecContext, args []string) tea.Msg {
|
||||
if len(args) != 2 {
|
||||
return events.Error(errors.New("expected: bindingName newKey"))
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/layout"
|
||||
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/styles"
|
||||
table "github.com/lmika/go-bubble-table"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -21,29 +22,38 @@ var (
|
|||
Background(lipgloss.Color("#4479ff"))
|
||||
)
|
||||
|
||||
type Setting interface {
|
||||
IsReadOnly() bool
|
||||
}
|
||||
|
||||
type Model struct {
|
||||
frameTitle frame.FrameTitle
|
||||
table table.Model
|
||||
w, h int
|
||||
keyBinding *keybindings.TableKeyBinding
|
||||
setting Setting
|
||||
|
||||
// model state
|
||||
isReadOnly bool
|
||||
colOffset int
|
||||
rows []table.Row
|
||||
resultSet *models.ResultSet
|
||||
}
|
||||
|
||||
func New(keyBinding *keybindings.TableKeyBinding, uiStyles styles.Styles) *Model {
|
||||
func New(keyBinding *keybindings.TableKeyBinding, setting Setting, uiStyles styles.Styles) *Model {
|
||||
tbl := table.New(table.SimpleColumns([]string{"pk", "sk"}), 100, 100)
|
||||
rows := make([]table.Row, 0)
|
||||
tbl.SetRows(rows)
|
||||
|
||||
frameTitle := frame.NewFrameTitle("No table", true, uiStyles.Frames)
|
||||
isReadOnly := setting.IsReadOnly()
|
||||
|
||||
return &Model{
|
||||
isReadOnly: isReadOnly,
|
||||
frameTitle: frameTitle,
|
||||
table: tbl,
|
||||
keyBinding: keyBinding,
|
||||
setting: setting,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,6 +67,9 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
m.resultSet = msg.ResultSet
|
||||
m.updateTable()
|
||||
return m, m.postSelectedItemChanged
|
||||
case controllers.SettingsUpdated:
|
||||
m.updateTableHeading()
|
||||
return m, nil
|
||||
case tea.KeyMsg:
|
||||
switch {
|
||||
// Table nav
|
||||
|
@ -113,10 +126,19 @@ func (m *Model) Resize(w, h int) layout.ResizingModel {
|
|||
return m
|
||||
}
|
||||
|
||||
func (m *Model) updateTable() {
|
||||
m.colOffset = 0
|
||||
func (m *Model) updateTableHeading() {
|
||||
tableName := new(strings.Builder)
|
||||
tableName.WriteString("Table: " + m.resultSet.TableInfo.Name)
|
||||
if m.setting.IsReadOnly() {
|
||||
tableName.WriteString(" [RO]")
|
||||
}
|
||||
|
||||
m.frameTitle.SetTitle("Table: " + m.resultSet.TableInfo.Name)
|
||||
m.frameTitle.SetTitle(tableName.String())
|
||||
}
|
||||
|
||||
func (m *Model) updateTable() {
|
||||
m.updateTableHeading()
|
||||
m.colOffset = 0
|
||||
m.rebuildTable()
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/lmika/audax/internal/common/sliceutils"
|
||||
"github.com/lmika/audax/internal/common/ui/events"
|
||||
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/layout"
|
||||
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/utils"
|
||||
"log"
|
||||
)
|
||||
|
||||
|
@ -36,11 +37,16 @@ func (s *StatusAndPrompt) Init() tea.Cmd {
|
|||
}
|
||||
|
||||
func (s *StatusAndPrompt) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
var cc utils.CmdCollector
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case events.ErrorMsg:
|
||||
s.statusMessage = "Error: " + msg.Error()
|
||||
case events.StatusMsg:
|
||||
s.statusMessage = string(msg)
|
||||
case events.WrappedStatusMsg:
|
||||
s.statusMessage = string(msg.Message)
|
||||
cc.Add(func() tea.Msg { return msg.Next })
|
||||
case events.ModeMessage:
|
||||
s.modeLine = string(msg)
|
||||
case events.MessageWithStatus:
|
||||
|
@ -86,9 +92,9 @@ func (s *StatusAndPrompt) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
}
|
||||
}
|
||||
|
||||
newModel, cmd := s.model.Update(msg)
|
||||
newModel := cc.Collect(s.model.Update(msg))
|
||||
s.model = newModel.(layout.ResizingModel)
|
||||
return s, cmd
|
||||
return s, cc.Cmd()
|
||||
}
|
||||
|
||||
func (s *StatusAndPrompt) InPrompt() bool {
|
||||
|
|
|
@ -49,7 +49,7 @@ func main() {
|
|||
}
|
||||
|
||||
dynamoProvider := dynamo.NewProvider(dynamoClient)
|
||||
tableService := tables.NewService(dynamoProvider)
|
||||
tableService := tables.NewService(dynamoProvider, notROService{})
|
||||
|
||||
_, _ = tableService, tableInfo
|
||||
|
||||
|
@ -103,3 +103,9 @@ func createTable(ctx context.Context, dynamoClient *dynamodb.Client, tableName s
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type notROService struct{}
|
||||
|
||||
func (n notROService) IsReadOnly() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue