issue-28: added default limit as a setting (#29)
This commit is contained in:
parent
93ec519127
commit
efdc7f9e25
|
@ -34,6 +34,7 @@ func main() {
|
||||||
var flagLocal = flag.String("local", "", "local endpoint")
|
var flagLocal = flag.String("local", "", "local endpoint")
|
||||||
var flagDebug = flag.String("debug", "", "file to log debug messages")
|
var flagDebug = flag.String("debug", "", "file to log debug messages")
|
||||||
var flagRO = flag.Bool("ro", false, "enable readonly mode")
|
var flagRO = flag.Bool("ro", false, "enable readonly mode")
|
||||||
|
var flagDefaultLimit = flag.Int("default-limit", 0, "default limit for queries and scans")
|
||||||
var flagWorkspace = flag.String("w", "", "workspace file")
|
var flagWorkspace = flag.String("w", "", "workspace file")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
@ -82,6 +83,11 @@ func main() {
|
||||||
cli.Fatalf("unable to set read-only mode: %v", err)
|
cli.Fatalf("unable to set read-only mode: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if *flagDefaultLimit > 0 {
|
||||||
|
if err := settingStore.SetDefaultLimit(*flagDefaultLimit); err != nil {
|
||||||
|
cli.Fatalf("unable to set default limit: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tableService := tables.NewService(dynamoProvider, settingStore)
|
tableService := tables.NewService(dynamoProvider, settingStore)
|
||||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||||
|
|
|
@ -16,4 +16,6 @@ type TableReadService interface {
|
||||||
type SettingsProvider interface {
|
type SettingsProvider interface {
|
||||||
IsReadOnly() (bool, error)
|
IsReadOnly() (bool, error)
|
||||||
SetReadOnly(ro bool) error
|
SetReadOnly(ro bool) error
|
||||||
|
DefaultLimit() (limit int)
|
||||||
|
SetDefaultLimit(limit int) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/lmika/audax/internal/common/ui/events"
|
"github.com/lmika/audax/internal/common/ui/events"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"log"
|
"log"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SettingsController struct {
|
type SettingsController struct {
|
||||||
|
@ -35,7 +37,21 @@ func (sc *SettingsController) SetSetting(name string, value string) tea.Msg {
|
||||||
Message: "In read-write mode",
|
Message: "In read-write mode",
|
||||||
Next: SettingsUpdated{},
|
Next: SettingsUpdated{},
|
||||||
}
|
}
|
||||||
|
case "default-limit":
|
||||||
|
newLimit, err := strconv.Atoi(value)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "bad value: %v", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := sc.settings.SetDefaultLimit(newLimit); err != nil {
|
||||||
|
return events.Error(err)
|
||||||
|
}
|
||||||
|
return events.WrappedStatusMsg{
|
||||||
|
Message: events.StatusMsg(fmt.Sprintf("Default query limit now %v", newLimit)),
|
||||||
|
Next: SettingsUpdated{},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return events.Error(errors.Errorf("unrecognised setting: %v", name))
|
return events.Error(errors.Errorf("unrecognised setting: %v", name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
|
|
||||||
func TestSettingsController_SetSetting(t *testing.T) {
|
func TestSettingsController_SetSetting(t *testing.T) {
|
||||||
t.Run("read-only setting", func(t *testing.T) {
|
t.Run("read-only setting", func(t *testing.T) {
|
||||||
srv := newService(t, false)
|
srv := newService(t, serviceConfig{})
|
||||||
|
|
||||||
msg := invokeCommand(t, srv.settingsController.SetSetting("ro", ""))
|
msg := invokeCommand(t, srv.settingsController.SetSetting("ro", ""))
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ func TestSettingsController_SetSetting(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("read-write setting", func(t *testing.T) {
|
t.Run("read-write setting", func(t *testing.T) {
|
||||||
srv := newService(t, true)
|
srv := newService(t, serviceConfig{isReadOnly: true})
|
||||||
|
|
||||||
msg := invokeCommand(t, srv.settingsController.SetSetting("rw", ""))
|
msg := invokeCommand(t, srv.settingsController.SetSetting("rw", ""))
|
||||||
|
|
||||||
|
@ -27,4 +27,13 @@ func TestSettingsController_SetSetting(t *testing.T) {
|
||||||
assert.IsType(t, events.WrappedStatusMsg{}, msg)
|
assert.IsType(t, events.WrappedStatusMsg{}, msg)
|
||||||
assert.IsType(t, controllers.SettingsUpdated{}, msg.(events.WrappedStatusMsg).Next)
|
assert.IsType(t, controllers.SettingsUpdated{}, msg.(events.WrappedStatusMsg).Next)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("set default limit", func(t *testing.T) {
|
||||||
|
srv := newService(t, serviceConfig{})
|
||||||
|
|
||||||
|
assert.Equal(t, 1000, srv.settingProvider.DefaultLimit())
|
||||||
|
invokeCommand(t, srv.settingsController.SetSetting("default-limit", "20"))
|
||||||
|
|
||||||
|
assert.Equal(t, 20, srv.settingProvider.DefaultLimit())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,6 @@ import (
|
||||||
"github.com/lmika/audax/internal/common/ui/events"
|
"github.com/lmika/audax/internal/common/ui/events"
|
||||||
"github.com/lmika/audax/internal/common/workspaces"
|
"github.com/lmika/audax/internal/common/workspaces"
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/controllers"
|
"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/workspacestore"
|
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/services/itemrenderer"
|
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/services/tables"
|
|
||||||
workspaces_service "github.com/lmika/audax/internal/dynamo-browse/services/workspaces"
|
|
||||||
"github.com/lmika/audax/test/testdynamo"
|
"github.com/lmika/audax/test/testdynamo"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"os"
|
"os"
|
||||||
|
@ -19,45 +14,28 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTableReadController_InitTable(t *testing.T) {
|
func TestTableReadController_InitTable(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, &mockedSetting{})
|
|
||||||
|
|
||||||
t.Run("should prompt for table if no table name provided", func(t *testing.T) {
|
t.Run("should prompt for table if no table name provided", func(t *testing.T) {
|
||||||
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "", false)
|
srv := newService(t, serviceConfig{})
|
||||||
|
|
||||||
event := readController.Init()
|
event := srv.readController.Init()
|
||||||
|
|
||||||
assert.IsType(t, controllers.PromptForTableMsg{}, event)
|
assert.IsType(t, controllers.PromptForTableMsg{}, event)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("should scan table if table name provided", func(t *testing.T) {
|
t.Run("should scan table if table name provided", func(t *testing.T) {
|
||||||
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "", false)
|
srv := newService(t, serviceConfig{})
|
||||||
|
|
||||||
event := readController.Init()
|
event := srv.readController.Init()
|
||||||
|
|
||||||
assert.IsType(t, controllers.PromptForTableMsg{}, event)
|
assert.IsType(t, controllers.PromptForTableMsg{}, event)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTableReadController_ListTables(t *testing.T) {
|
func TestTableReadController_ListTables(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, &mockedSetting{})
|
|
||||||
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "", false)
|
|
||||||
|
|
||||||
t.Run("returns a list of tables", func(t *testing.T) {
|
t.Run("returns a list of tables", func(t *testing.T) {
|
||||||
event := readController.ListTables().(controllers.PromptForTableMsg)
|
srv := newService(t, serviceConfig{})
|
||||||
|
|
||||||
|
event := srv.readController.ListTables().(controllers.PromptForTableMsg)
|
||||||
|
|
||||||
assert.Equal(t, []string{"alpha-table", "bravo-table"}, event.Tables)
|
assert.Equal(t, []string{"alpha-table", "bravo-table"}, event.Tables)
|
||||||
|
|
||||||
|
@ -71,59 +49,46 @@ func TestTableReadController_ListTables(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTableReadController_Rescan(t *testing.T) {
|
func TestTableReadController_Rescan(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, &mockedSetting{})
|
|
||||||
state := controllers.NewState()
|
|
||||||
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "bravo-table", false)
|
|
||||||
|
|
||||||
t.Run("should perform a rescan", func(t *testing.T) {
|
t.Run("should perform a rescan", func(t *testing.T) {
|
||||||
invokeCommand(t, readController.Init())
|
srv := newService(t, serviceConfig{tableName: "bravo-table"})
|
||||||
invokeCommand(t, readController.Rescan())
|
|
||||||
|
invokeCommand(t, srv.readController.Init())
|
||||||
|
invokeCommand(t, srv.readController.Rescan())
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("should prompt to rescan if any dirty rows", func(t *testing.T) {
|
t.Run("should prompt to rescan if any dirty rows", func(t *testing.T) {
|
||||||
invokeCommand(t, readController.Init())
|
srv := newService(t, serviceConfig{tableName: "bravo-table"})
|
||||||
|
|
||||||
state.ResultSet().SetDirty(0, true)
|
invokeCommand(t, srv.readController.Init())
|
||||||
|
|
||||||
invokeCommandWithPrompt(t, readController.Rescan(), "y")
|
srv.state.ResultSet().SetDirty(0, true)
|
||||||
|
|
||||||
assert.False(t, state.ResultSet().IsDirty(0))
|
invokeCommandWithPrompt(t, srv.readController.Rescan(), "y")
|
||||||
|
|
||||||
|
assert.False(t, srv.state.ResultSet().IsDirty(0))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("should not rescan if any dirty rows", func(t *testing.T) {
|
t.Run("should not rescan if any dirty rows", func(t *testing.T) {
|
||||||
invokeCommand(t, readController.Init())
|
srv := newService(t, serviceConfig{tableName: "bravo-table"})
|
||||||
|
|
||||||
state.ResultSet().SetDirty(0, true)
|
invokeCommand(t, srv.readController.Init())
|
||||||
|
|
||||||
invokeCommandWithPrompt(t, readController.Rescan(), "n")
|
srv.state.ResultSet().SetDirty(0, true)
|
||||||
|
|
||||||
assert.True(t, state.ResultSet().IsDirty(0))
|
invokeCommandWithPrompt(t, srv.readController.Rescan(), "n")
|
||||||
|
|
||||||
|
assert.True(t, srv.state.ResultSet().IsDirty(0))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTableReadController_ExportCSV(t *testing.T) {
|
func TestTableReadController_ExportCSV(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, &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) {
|
t.Run("should export result set to CSV file", func(t *testing.T) {
|
||||||
|
srv := newService(t, serviceConfig{tableName: "bravo-table"})
|
||||||
|
|
||||||
tempFile := tempFile(t)
|
tempFile := tempFile(t)
|
||||||
|
|
||||||
invokeCommand(t, readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
invokeCommand(t, readController.ExportCSV(tempFile))
|
invokeCommand(t, srv.readController.ExportCSV(tempFile))
|
||||||
|
|
||||||
bts, err := os.ReadFile(tempFile)
|
bts, err := os.ReadFile(tempFile)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -137,33 +102,26 @@ func TestTableReadController_ExportCSV(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("should return error if result set is not set", func(t *testing.T) {
|
t.Run("should return error if result set is not set", func(t *testing.T) {
|
||||||
tempFile := tempFile(t)
|
srv := newService(t, serviceConfig{tableName: "non-existant-table"})
|
||||||
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "non-existant-table", false)
|
|
||||||
|
|
||||||
invokeCommandExpectingError(t, readController.Init())
|
tempFile := tempFile(t)
|
||||||
invokeCommandExpectingError(t, readController.ExportCSV(tempFile))
|
|
||||||
|
invokeCommandExpectingError(t, srv.readController.Init())
|
||||||
|
invokeCommandExpectingError(t, srv.readController.ExportCSV(tempFile))
|
||||||
})
|
})
|
||||||
|
|
||||||
// Hidden items?
|
// Hidden items?
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTableReadController_Query(t *testing.T) {
|
func TestTableReadController_Query(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, &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) {
|
t.Run("should run scan with filter based on user query", func(t *testing.T) {
|
||||||
|
srv := newService(t, serviceConfig{tableName: "bravo-table"})
|
||||||
|
|
||||||
tempFile := tempFile(t)
|
tempFile := tempFile(t)
|
||||||
|
|
||||||
invokeCommand(t, readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
invokeCommandWithPrompts(t, readController.PromptForQuery(), `pk ^= "abc"`)
|
invokeCommandWithPrompts(t, srv.readController.PromptForQuery(), `pk ^= "abc"`)
|
||||||
invokeCommand(t, readController.ExportCSV(tempFile))
|
invokeCommand(t, srv.readController.ExportCSV(tempFile))
|
||||||
|
|
||||||
bts, err := os.ReadFile(tempFile)
|
bts, err := os.ReadFile(tempFile)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -175,11 +133,12 @@ func TestTableReadController_Query(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("should return error if result set is not set", func(t *testing.T) {
|
t.Run("should return error if result set is not set", func(t *testing.T) {
|
||||||
tempFile := tempFile(t)
|
srv := newService(t, serviceConfig{tableName: "non-existant-table"})
|
||||||
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "non-existant-table", false)
|
|
||||||
|
|
||||||
invokeCommandExpectingError(t, readController.Init())
|
tempFile := tempFile(t)
|
||||||
invokeCommandExpectingError(t, readController.ExportCSV(tempFile))
|
|
||||||
|
invokeCommandExpectingError(t, srv.readController.Init())
|
||||||
|
invokeCommandExpectingError(t, srv.readController.ExportCSV(tempFile))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/controllers"
|
"github.com/lmika/audax/internal/dynamo-browse/controllers"
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/models"
|
"github.com/lmika/audax/internal/dynamo-browse/models"
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/providers/dynamo"
|
"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/providers/workspacestore"
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/services/itemrenderer"
|
"github.com/lmika/audax/internal/dynamo-browse/services/itemrenderer"
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/services/tables"
|
"github.com/lmika/audax/internal/dynamo-browse/services/tables"
|
||||||
|
@ -17,7 +18,7 @@ import (
|
||||||
|
|
||||||
func TestTableWriteController_NewItem(t *testing.T) {
|
func TestTableWriteController_NewItem(t *testing.T) {
|
||||||
t.Run("should add an item with pk and sk set at the end of the result set", func(t *testing.T) {
|
t.Run("should add an item with pk and sk set at the end of the result set", func(t *testing.T) {
|
||||||
srv := newService(t, false)
|
srv := newService(t, serviceConfig{tableName: "alpha-table"})
|
||||||
|
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
assert.Len(t, srv.state.ResultSet().Items(), 3)
|
assert.Len(t, srv.state.ResultSet().Items(), 3)
|
||||||
|
@ -38,7 +39,7 @@ func TestTableWriteController_NewItem(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("should do nothing when in read-only mode", func(t *testing.T) {
|
t.Run("should do nothing when in read-only mode", func(t *testing.T) {
|
||||||
srv := newService(t, true)
|
srv := newService(t, serviceConfig{tableName: "alpha-table", isReadOnly: true})
|
||||||
|
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
assert.Len(t, srv.state.ResultSet().Items(), 3)
|
assert.Len(t, srv.state.ResultSet().Items(), 3)
|
||||||
|
@ -86,7 +87,7 @@ func TestTableWriteController_SetAttributeValue(t *testing.T) {
|
||||||
|
|
||||||
for _, scenario := range scenarios {
|
for _, scenario := range scenarios {
|
||||||
t.Run(fmt.Sprintf("should set value of field: %v", scenario.attrKey), func(t *testing.T) {
|
t.Run(fmt.Sprintf("should set value of field: %v", scenario.attrKey), func(t *testing.T) {
|
||||||
srv := newService(t, false)
|
srv := newService(t, serviceConfig{tableName: "alpha-table"})
|
||||||
|
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
invokeCommandWithPrompt(t, srv.writeController.SetAttributeValue(0, models.UnsetItemType, scenario.attrKey), scenario.attrValue)
|
invokeCommandWithPrompt(t, srv.writeController.SetAttributeValue(0, models.UnsetItemType, scenario.attrKey), scenario.attrValue)
|
||||||
|
@ -99,7 +100,7 @@ func TestTableWriteController_SetAttributeValue(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("should use type of selected item for marked fields if unspecified", func(t *testing.T) {
|
t.Run("should use type of selected item for marked fields if unspecified", func(t *testing.T) {
|
||||||
srv := newService(t, false)
|
srv := newService(t, serviceConfig{tableName: "alpha-table"})
|
||||||
|
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
invokeCommand(t, srv.writeController.ToggleMark(0))
|
invokeCommand(t, srv.writeController.ToggleMark(0))
|
||||||
|
@ -146,7 +147,7 @@ func TestTableWriteController_SetAttributeValue(t *testing.T) {
|
||||||
|
|
||||||
for _, scenario := range scenarios {
|
for _, scenario := range scenarios {
|
||||||
t.Run(fmt.Sprintf("should change the value of a field to type %v", scenario.attrType), func(t *testing.T) {
|
t.Run(fmt.Sprintf("should change the value of a field to type %v", scenario.attrType), func(t *testing.T) {
|
||||||
srv := newService(t, false)
|
srv := newService(t, serviceConfig{tableName: "alpha-table"})
|
||||||
|
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
before, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
before, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("alpha")
|
||||||
|
@ -165,7 +166,7 @@ func TestTableWriteController_SetAttributeValue(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run(fmt.Sprintf("should change value of nested field to type %v", scenario.attrType), func(t *testing.T) {
|
t.Run(fmt.Sprintf("should change value of nested field to type %v", scenario.attrType), func(t *testing.T) {
|
||||||
srv := newService(t, false)
|
srv := newService(t, serviceConfig{tableName: "alpha-table"})
|
||||||
|
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
|
|
||||||
|
@ -193,7 +194,7 @@ func TestTableWriteController_SetAttributeValue(t *testing.T) {
|
||||||
|
|
||||||
func TestTableWriteController_DeleteAttribute(t *testing.T) {
|
func TestTableWriteController_DeleteAttribute(t *testing.T) {
|
||||||
t.Run("should delete top level attribute", func(t *testing.T) {
|
t.Run("should delete top level attribute", func(t *testing.T) {
|
||||||
srv := newService(t, false)
|
srv := newService(t, serviceConfig{tableName: "alpha-table"})
|
||||||
|
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
before, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("age")
|
before, _ := srv.state.ResultSet().Items()[0].AttributeValueAsString("age")
|
||||||
|
@ -207,7 +208,7 @@ func TestTableWriteController_DeleteAttribute(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("should delete attribute of map", func(t *testing.T) {
|
t.Run("should delete attribute of map", func(t *testing.T) {
|
||||||
srv := newService(t, false)
|
srv := newService(t, serviceConfig{tableName: "alpha-table"})
|
||||||
|
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
|
|
||||||
|
@ -228,7 +229,7 @@ func TestTableWriteController_DeleteAttribute(t *testing.T) {
|
||||||
|
|
||||||
func TestTableWriteController_PutItem(t *testing.T) {
|
func TestTableWriteController_PutItem(t *testing.T) {
|
||||||
t.Run("should put the selected item if dirty", func(t *testing.T) {
|
t.Run("should put the selected item if dirty", func(t *testing.T) {
|
||||||
srv := newService(t, false)
|
srv := newService(t, serviceConfig{tableName: "alpha-table"})
|
||||||
|
|
||||||
// Read the table
|
// Read the table
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
|
@ -248,7 +249,7 @@ func TestTableWriteController_PutItem(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("should not put the selected item if user does not confirm", func(t *testing.T) {
|
t.Run("should not put the selected item if user does not confirm", func(t *testing.T) {
|
||||||
srv := newService(t, false)
|
srv := newService(t, serviceConfig{tableName: "alpha-table"})
|
||||||
|
|
||||||
// Read the table
|
// Read the table
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
|
@ -272,7 +273,7 @@ func TestTableWriteController_PutItem(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("should not put the selected item if not dirty", func(t *testing.T) {
|
t.Run("should not put the selected item if not dirty", func(t *testing.T) {
|
||||||
srv := newService(t, false)
|
srv := newService(t, serviceConfig{tableName: "alpha-table"})
|
||||||
|
|
||||||
// Read the table
|
// Read the table
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
|
@ -284,7 +285,7 @@ func TestTableWriteController_PutItem(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("should not put the selected item if in read-only mode", func(t *testing.T) {
|
t.Run("should not put the selected item if in read-only mode", func(t *testing.T) {
|
||||||
srv := newService(t, true)
|
srv := newService(t, serviceConfig{tableName: "alpha-table", isReadOnly: true})
|
||||||
|
|
||||||
// Read the table
|
// Read the table
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
|
@ -310,7 +311,7 @@ func TestTableWriteController_PutItem(t *testing.T) {
|
||||||
|
|
||||||
func TestTableWriteController_PutItems(t *testing.T) {
|
func TestTableWriteController_PutItems(t *testing.T) {
|
||||||
t.Run("should put all dirty items if none are marked", func(t *testing.T) {
|
t.Run("should put all dirty items if none are marked", func(t *testing.T) {
|
||||||
srv := newService(t, false)
|
srv := newService(t, serviceConfig{tableName: "alpha-table"})
|
||||||
|
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
|
|
||||||
|
@ -331,7 +332,7 @@ func TestTableWriteController_PutItems(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("only put marked items", func(t *testing.T) {
|
t.Run("only put marked items", func(t *testing.T) {
|
||||||
srv := newService(t, false)
|
srv := newService(t, serviceConfig{tableName: "alpha-table"})
|
||||||
|
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
|
|
||||||
|
@ -360,7 +361,7 @@ func TestTableWriteController_PutItems(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("do not put marked items which are not dirty", func(t *testing.T) {
|
t.Run("do not put marked items which are not dirty", func(t *testing.T) {
|
||||||
srv := newService(t, false)
|
srv := newService(t, serviceConfig{tableName: "alpha-table"})
|
||||||
|
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
|
|
||||||
|
@ -389,7 +390,7 @@ func TestTableWriteController_PutItems(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("do nothing if in read-only mode", func(t *testing.T) {
|
t.Run("do nothing if in read-only mode", func(t *testing.T) {
|
||||||
srv := newService(t, true)
|
srv := newService(t, serviceConfig{tableName: "alpha-table", isReadOnly: true})
|
||||||
|
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
|
|
||||||
|
@ -420,7 +421,7 @@ func TestTableWriteController_PutItems(t *testing.T) {
|
||||||
|
|
||||||
func TestTableWriteController_TouchItem(t *testing.T) {
|
func TestTableWriteController_TouchItem(t *testing.T) {
|
||||||
t.Run("should put the selected item if unmodified", func(t *testing.T) {
|
t.Run("should put the selected item if unmodified", func(t *testing.T) {
|
||||||
srv := newService(t, false)
|
srv := newService(t, serviceConfig{tableName: "alpha-table"})
|
||||||
|
|
||||||
// Read the table
|
// Read the table
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
|
@ -439,7 +440,7 @@ func TestTableWriteController_TouchItem(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("should not put the selected item if modified", func(t *testing.T) {
|
t.Run("should not put the selected item if modified", func(t *testing.T) {
|
||||||
srv := newService(t, false)
|
srv := newService(t, serviceConfig{tableName: "alpha-table"})
|
||||||
|
|
||||||
// Read the table
|
// Read the table
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
|
@ -453,7 +454,7 @@ func TestTableWriteController_TouchItem(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("should not put the selected item if in read-only mode", func(t *testing.T) {
|
t.Run("should not put the selected item if in read-only mode", func(t *testing.T) {
|
||||||
srv := newService(t, true)
|
srv := newService(t, serviceConfig{tableName: "alpha-table", isReadOnly: true})
|
||||||
|
|
||||||
// Read the table
|
// Read the table
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
|
@ -474,7 +475,7 @@ func TestTableWriteController_TouchItem(t *testing.T) {
|
||||||
|
|
||||||
func TestTableWriteController_NoisyTouchItem(t *testing.T) {
|
func TestTableWriteController_NoisyTouchItem(t *testing.T) {
|
||||||
t.Run("should delete and put the selected item if unmodified", func(t *testing.T) {
|
t.Run("should delete and put the selected item if unmodified", func(t *testing.T) {
|
||||||
srv := newService(t, false)
|
srv := newService(t, serviceConfig{tableName: "alpha-table"})
|
||||||
|
|
||||||
// Read the table
|
// Read the table
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
|
@ -493,7 +494,7 @@ func TestTableWriteController_NoisyTouchItem(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("should not put the selected item if modified", func(t *testing.T) {
|
t.Run("should not put the selected item if modified", func(t *testing.T) {
|
||||||
srv := newService(t, false)
|
srv := newService(t, serviceConfig{tableName: "alpha-table"})
|
||||||
|
|
||||||
// Read the table
|
// Read the table
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
|
@ -507,7 +508,7 @@ func TestTableWriteController_NoisyTouchItem(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("should not put the selected item if in read-only mode", func(t *testing.T) {
|
t.Run("should not put the selected item if in read-only mode", func(t *testing.T) {
|
||||||
srv := newService(t, true)
|
srv := newService(t, serviceConfig{tableName: "alpha-table", isReadOnly: true})
|
||||||
|
|
||||||
// Read the table
|
// Read the table
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
|
@ -522,7 +523,7 @@ func TestTableWriteController_NoisyTouchItem(t *testing.T) {
|
||||||
|
|
||||||
func TestTableWriteController_DeleteMarked(t *testing.T) {
|
func TestTableWriteController_DeleteMarked(t *testing.T) {
|
||||||
t.Run("should delete marked items", func(t *testing.T) {
|
t.Run("should delete marked items", func(t *testing.T) {
|
||||||
srv := newService(t, false)
|
srv := newService(t, serviceConfig{tableName: "alpha-table"})
|
||||||
|
|
||||||
// Read the table
|
// Read the table
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
|
@ -543,7 +544,7 @@ func TestTableWriteController_DeleteMarked(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("should not delete marked items if in read-only mode", func(t *testing.T) {
|
t.Run("should not delete marked items if in read-only mode", func(t *testing.T) {
|
||||||
srv := newService(t, true)
|
srv := newService(t, serviceConfig{tableName: "alpha-table", isReadOnly: true})
|
||||||
|
|
||||||
// Read the table
|
// Read the table
|
||||||
invokeCommand(t, srv.readController.Init())
|
invokeCommand(t, srv.readController.Init())
|
||||||
|
@ -566,44 +567,46 @@ func TestTableWriteController_DeleteMarked(t *testing.T) {
|
||||||
|
|
||||||
type services struct {
|
type services struct {
|
||||||
state *controllers.State
|
state *controllers.State
|
||||||
|
settingProvider controllers.SettingsProvider
|
||||||
readController *controllers.TableReadController
|
readController *controllers.TableReadController
|
||||||
writeController *controllers.TableWriteController
|
writeController *controllers.TableWriteController
|
||||||
settingsController *controllers.SettingsController
|
settingsController *controllers.SettingsController
|
||||||
}
|
}
|
||||||
|
|
||||||
func newService(t *testing.T, isReadOnly bool) *services {
|
type serviceConfig struct {
|
||||||
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
tableName string
|
||||||
|
isReadOnly bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newService(t *testing.T, cfg serviceConfig) *services {
|
||||||
|
ws := testWorkspace(t)
|
||||||
|
|
||||||
|
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(ws)
|
||||||
|
settingStore := settingstore.New(ws)
|
||||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||||
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||||
|
|
||||||
client := testdynamo.SetupTestTable(t, testData)
|
client := testdynamo.SetupTestTable(t, testData)
|
||||||
|
|
||||||
settingProvider := &mockedSetting{isReadOnly: isReadOnly}
|
|
||||||
provider := dynamo.NewProvider(client)
|
provider := dynamo.NewProvider(client)
|
||||||
service := tables.NewService(provider, settingProvider)
|
service := tables.NewService(provider, settingStore)
|
||||||
|
|
||||||
state := controllers.NewState()
|
state := controllers.NewState()
|
||||||
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
|
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, cfg.tableName, false)
|
||||||
writeController := controllers.NewTableWriteController(state, service, readController, settingProvider)
|
writeController := controllers.NewTableWriteController(state, service, readController, settingStore)
|
||||||
settingsController := controllers.NewSettingsController(settingProvider)
|
settingsController := controllers.NewSettingsController(settingStore)
|
||||||
|
|
||||||
|
if cfg.isReadOnly {
|
||||||
|
if err := settingStore.SetReadOnly(cfg.isReadOnly); err != nil {
|
||||||
|
t.Errorf("cannot set ro: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &services{
|
return &services{
|
||||||
state: state,
|
state: state,
|
||||||
|
settingProvider: settingStore,
|
||||||
readController: readController,
|
readController: readController,
|
||||||
writeController: writeController,
|
writeController: writeController,
|
||||||
settingsController: settingsController,
|
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
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,12 +3,17 @@ package settingstore
|
||||||
import (
|
import (
|
||||||
"github.com/asdine/storm"
|
"github.com/asdine/storm"
|
||||||
"github.com/lmika/audax/internal/common/workspaces"
|
"github.com/lmika/audax/internal/common/workspaces"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const settingBucket = "Settings"
|
const settingBucket = "Settings"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
keyTableReadOnly = "table_ro"
|
keyTableReadOnly = "ro"
|
||||||
|
keyTableDefaultLimit = "default_limit"
|
||||||
|
|
||||||
|
defaultsDefaultLimit = 1000
|
||||||
)
|
)
|
||||||
|
|
||||||
type SettingStore struct {
|
type SettingStore struct {
|
||||||
|
@ -22,10 +27,30 @@ func New(ws *workspaces.Workspace) *SettingStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SettingStore) IsReadOnly() (b bool, err error) {
|
func (c *SettingStore) IsReadOnly() (b bool, err error) {
|
||||||
err = c.ws.Get(settingBucket, keyTableReadOnly, &b)
|
if err := c.ws.Get(settingBucket, keyTableReadOnly, &b); err != nil {
|
||||||
|
if errors.Is(err, storm.ErrNotFound) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SettingStore) SetReadOnly(ro bool) error {
|
func (c *SettingStore) SetReadOnly(ro bool) error {
|
||||||
return c.ws.Set(settingBucket, keyTableReadOnly, ro)
|
return c.ws.Set(settingBucket, keyTableReadOnly, ro)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *SettingStore) DefaultLimit() (limit int) {
|
||||||
|
err := c.ws.Get(settingBucket, keyTableDefaultLimit, &limit)
|
||||||
|
if err != nil {
|
||||||
|
if !errors.Is(err, storm.ErrNotFound) {
|
||||||
|
log.Printf("warn: cannot get default limit from workspace, using default value: %v", err)
|
||||||
|
}
|
||||||
|
return defaultsDefaultLimit
|
||||||
|
}
|
||||||
|
return limit
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SettingStore) SetDefaultLimit(limit int) error {
|
||||||
|
return errors.Wrapf(c.ws.Set(settingBucket, keyTableDefaultLimit, &limit), "cannot set default limit to %v", limit)
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ type TableProvider interface {
|
||||||
PutItems(ctx context.Context, name string, items []models.Item) error
|
PutItems(ctx context.Context, name string, items []models.Item) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type ROProvider interface {
|
type ConfigProvider interface {
|
||||||
IsReadOnly() (bool, error)
|
IsReadOnly() (bool, error)
|
||||||
|
DefaultLimit() int
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,14 +12,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
provider TableProvider
|
provider TableProvider
|
||||||
roProvider ROProvider
|
configProvider ConfigProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(provider TableProvider, roProvider ROProvider) *Service {
|
func NewService(provider TableProvider, roProvider ConfigProvider) *Service {
|
||||||
return &Service{
|
return &Service{
|
||||||
provider: provider,
|
provider: provider,
|
||||||
roProvider: roProvider,
|
configProvider: roProvider,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,10 +32,10 @@ func (s *Service) Describe(ctx context.Context, table string) (*models.TableInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Scan(ctx context.Context, tableInfo *models.TableInfo) (*models.ResultSet, error) {
|
func (s *Service) Scan(ctx context.Context, tableInfo *models.TableInfo) (*models.ResultSet, error) {
|
||||||
return s.doScan(ctx, tableInfo, nil)
|
return s.doScan(ctx, tableInfo, nil, s.configProvider.DefaultLimit())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) doScan(ctx context.Context, tableInfo *models.TableInfo, expr models.Queryable) (*models.ResultSet, error) {
|
func (s *Service) doScan(ctx context.Context, tableInfo *models.TableInfo, expr models.Queryable, limit int) (*models.ResultSet, error) {
|
||||||
var (
|
var (
|
||||||
filterExpr *expression.Expression
|
filterExpr *expression.Expression
|
||||||
runAsQuery bool
|
runAsQuery bool
|
||||||
|
@ -54,10 +54,10 @@ func (s *Service) doScan(ctx context.Context, tableInfo *models.TableInfo, expr
|
||||||
var results []models.Item
|
var results []models.Item
|
||||||
if runAsQuery {
|
if runAsQuery {
|
||||||
log.Printf("executing query")
|
log.Printf("executing query")
|
||||||
results, err = s.provider.QueryItems(ctx, tableInfo.Name, filterExpr, 1000)
|
results, err = s.provider.QueryItems(ctx, tableInfo.Name, filterExpr, limit)
|
||||||
} else {
|
} else {
|
||||||
log.Printf("executing scan")
|
log.Printf("executing scan")
|
||||||
results, err = s.provider.ScanItems(ctx, tableInfo.Name, filterExpr, 1000)
|
results, err = s.provider.ScanItems(ctx, tableInfo.Name, filterExpr, limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -135,11 +135,11 @@ func (s *Service) Delete(ctx context.Context, tableInfo *models.TableInfo, items
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) ScanOrQuery(ctx context.Context, tableInfo *models.TableInfo, expr models.Queryable) (*models.ResultSet, error) {
|
func (s *Service) ScanOrQuery(ctx context.Context, tableInfo *models.TableInfo, expr models.Queryable) (*models.ResultSet, error) {
|
||||||
return s.doScan(ctx, tableInfo, expr)
|
return s.doScan(ctx, tableInfo, expr, s.configProvider.DefaultLimit())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) assertReadWrite() error {
|
func (s *Service) assertReadWrite() error {
|
||||||
b, err := s.roProvider.IsReadOnly()
|
b, err := s.configProvider.IsReadOnly()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
} else if b {
|
} else if b {
|
||||||
|
|
|
@ -19,7 +19,7 @@ func TestService_Describe(t *testing.T) {
|
||||||
t.Run("return details of the table", func(t *testing.T) {
|
t.Run("return details of the table", func(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
service := tables.NewService(provider, mockedReadOnlyProvider{readOnly: false})
|
service := tables.NewService(provider, mockedConfigProvider{readOnly: false})
|
||||||
ti, err := service.Describe(ctx, tableName)
|
ti, err := service.Describe(ctx, tableName)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
@ -40,17 +40,30 @@ func TestService_Scan(t *testing.T) {
|
||||||
t.Run("return all columns and fields in sorted order", func(t *testing.T) {
|
t.Run("return all columns and fields in sorted order", func(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
service := tables.NewService(provider, mockedReadOnlyProvider{readOnly: false})
|
service := tables.NewService(provider, mockedConfigProvider{readOnly: false})
|
||||||
ti, err := service.Describe(ctx, tableName)
|
ti, err := service.Describe(ctx, tableName)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
rs, err := service.Scan(ctx, ti)
|
rs, err := service.Scan(ctx, ti)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, rs.Items(), 3)
|
||||||
|
|
||||||
// Hash first, then range, then columns in alphabetic order
|
// Hash first, then range, then columns in alphabetic order
|
||||||
assert.Equal(t, rs.TableInfo, ti)
|
assert.Equal(t, rs.TableInfo, ti)
|
||||||
assert.Equal(t, rs.Columns(), []string{"pk", "sk", "alpha", "beta", "gamma"})
|
assert.Equal(t, rs.Columns(), []string{"pk", "sk", "alpha", "beta", "gamma"})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("should honour default limits", func(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
service := tables.NewService(provider, mockedConfigProvider{readOnly: false, defaultLimit: 2})
|
||||||
|
ti, err := service.Describe(ctx, tableName)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
rs, err := service.Scan(ctx, ti)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, rs.Items(), 2)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var testData = []testdynamo.TestData{
|
var testData = []testdynamo.TestData{
|
||||||
|
@ -78,10 +91,18 @@ var testData = []testdynamo.TestData{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
type mockedReadOnlyProvider struct {
|
type mockedConfigProvider struct {
|
||||||
readOnly bool
|
readOnly bool
|
||||||
|
defaultLimit int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m mockedReadOnlyProvider) IsReadOnly() (bool, error) {
|
func (m mockedConfigProvider) IsReadOnly() (bool, error) {
|
||||||
return m.readOnly, nil
|
return m.readOnly, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m mockedConfigProvider) DefaultLimit() int {
|
||||||
|
if m.defaultLimit == 0 {
|
||||||
|
return 1000
|
||||||
|
}
|
||||||
|
return m.defaultLimit
|
||||||
|
}
|
||||||
|
|
|
@ -106,6 +106,10 @@ func createTable(ctx context.Context, dynamoClient *dynamodb.Client, tableName s
|
||||||
|
|
||||||
type notROService struct{}
|
type notROService struct{}
|
||||||
|
|
||||||
|
func (n notROService) DefaultLimit() int {
|
||||||
|
return 1000
|
||||||
|
}
|
||||||
|
|
||||||
func (n notROService) IsReadOnly() (bool, error) {
|
func (n notROService) IsReadOnly() (bool, error) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue