backstack: added saving of backstack to workspace

This commit is contained in:
Leon Mika 2022-08-11 22:23:39 +10:00
parent 96207821a2
commit 721d3abe5e
9 changed files with 214 additions and 11 deletions

View file

@ -11,9 +11,12 @@ import (
"github.com/lmika/audax/internal/common/ui/commandctrl"
"github.com/lmika/audax/internal/common/ui/logging"
"github.com/lmika/audax/internal/common/ui/osstyle"
"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/workspacestore"
"github.com/lmika/audax/internal/dynamo-browse/services/tables"
workspaces_service "github.com/lmika/audax/internal/dynamo-browse/services/workspaces"
"github.com/lmika/audax/internal/dynamo-browse/ui"
"github.com/lmika/gopkgs/cli"
"log"
@ -34,6 +37,16 @@ func main() {
cli.Fatalf("cannot load AWS config: %v", err)
}
wsManager := workspaces.New(workspaces.MetaInfo{
Command: "sqs-browse",
})
//ws, err := wsManager.CreateTemp()
ws, err := wsManager.Open("temp.workspace")
if err != nil {
cli.Fatalf("cannot create workspace: %v", ws)
}
defer ws.Close()
var dynamoClient *dynamodb.Client
if *flagLocal != "" {
host, port, err := net.SplitHostPort(*flagLocal)
@ -53,11 +66,13 @@ func main() {
}
dynamoProvider := dynamo.NewProvider(dynamoClient)
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(ws)
tableService := tables.NewService(dynamoProvider)
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
state := controllers.NewState()
tableReadController := controllers.NewTableReadController(state, tableService, *flagTable)
tableReadController := controllers.NewTableReadController(state, tableService, workspaceService, *flagTable)
tableWriteController := controllers.NewTableWriteController(state, tableService, tableReadController)
commandController := commandctrl.NewCommandController()

View file

@ -0,0 +1,37 @@
package workspaces
import (
"github.com/asdine/storm"
"github.com/pkg/errors"
"os"
)
type MetaInfo struct {
Command string
}
type Manager struct {
metainfo MetaInfo
}
func New(metaInfo MetaInfo) *Manager {
return &Manager{metainfo: metaInfo}
}
func (m *Manager) Open(filename string) (*Workspace, error) {
db, err := storm.Open(filename)
if err != nil {
return nil, errors.Wrapf(err, "cannot open workspace at %v", filename)
}
return &Workspace{db: db}, nil
}
func (m *Manager) CreateTemp() (*Workspace, error) {
workspaceFile, err := os.CreateTemp("", m.metainfo.Command+"*.workspace")
if err != nil {
return nil, errors.Wrapf(err, "cannot create workspace file")
}
workspaceFile.Close() // We just need the filename
return m.Open(workspaceFile.Name())
}

View file

@ -0,0 +1,19 @@
package workspaces
import (
"github.com/asdine/storm"
"log"
)
type Workspace struct {
db *storm.DB
}
func (ws *Workspace) DB() *storm.DB {
return ws.db
}
func (ws *Workspace) Close() {
log.Printf("close workspace")
ws.db.Close()
}

View file

@ -7,14 +7,17 @@ import (
"github.com/lmika/audax/internal/common/ui/events"
"github.com/lmika/audax/internal/dynamo-browse/models"
"github.com/lmika/audax/internal/dynamo-browse/models/queryexpr"
"github.com/lmika/audax/internal/dynamo-browse/services/workspaces"
"github.com/pkg/errors"
"log"
"os"
"sync"
)
type TableReadController struct {
tableService TableReadService
tableName string
tableService TableReadService
workspaceService *workspaces.Service
tableName string
// state
mutex *sync.Mutex
@ -23,12 +26,13 @@ type TableReadController struct {
//filter string
}
func NewTableReadController(state *State, tableService TableReadService, tableName string) *TableReadController {
func NewTableReadController(state *State, tableService TableReadService, workspaceService *workspaces.Service, tableName string) *TableReadController {
return &TableReadController{
state: state,
tableService: tableService,
tableName: tableName,
mutex: new(sync.Mutex),
state: state,
tableService: tableService,
workspaceService: workspaceService,
tableName: tableName,
mutex: new(sync.Mutex),
}
}
@ -99,6 +103,9 @@ func (c *TableReadController) PromptForQuery() tea.Cmd {
return events.Error(err)
}
if err := c.workspaceService.PushSnapshot(resultSet); err != nil {
log.Printf("cannot push snapshot: %v", err)
}
return c.setResultSetAndFilter(newResultSet, "")
})
},

View file

@ -3,9 +3,8 @@ package models
import "sort"
type ResultSet struct {
TableInfo *TableInfo
Query Queryable
//Columns []string
TableInfo *TableInfo
Query Queryable
items []Item
attributes []ItemAttribute

View file

@ -0,0 +1,19 @@
package serialisable
import (
"github.com/lmika/audax/internal/dynamo-browse/models"
"time"
)
type ResultSetSnapshot struct {
ID int64 `storm:"id,increment"`
BackLink int64 `storm:"index"`
Time time.Time
TableInfo *models.TableInfo
Query Query
Filter string
}
type Query struct {
Expression string
}

View file

@ -0,0 +1,55 @@
package workspacestore
import (
"github.com/asdine/storm"
"github.com/lmika/audax/internal/common/workspaces"
"github.com/lmika/audax/internal/dynamo-browse/models/serialisable"
"github.com/pkg/errors"
"log"
)
const resultSetSnapshotsBucket = "ResultSetSnapshots"
type ResultSetSnapshotStore struct {
ws storm.Node
}
func NewResultSetSnapshotStore(ws *workspaces.Workspace) *ResultSetSnapshotStore {
return &ResultSetSnapshotStore{
ws: ws.DB().From(resultSetSnapshotsBucket),
}
}
func (s *ResultSetSnapshotStore) Save(rs *serialisable.ResultSetSnapshot) error {
if err := s.ws.Save(rs); err != nil {
return errors.Wrap(err, "cannot save result set")
}
log.Printf("saved result set")
return nil
}
func (s *ResultSetSnapshotStore) SetAsHead(resultSetID int64) error {
if err := s.ws.Set("head", "id", resultSetID); err != nil {
return errors.Wrap(err, "cannot set as head")
}
log.Printf("saved result set head")
return nil
}
func (s *ResultSetSnapshotStore) Head() (*serialisable.ResultSetSnapshot, error) {
var headResultSetID int64
if err := s.ws.Get("head", "id", &headResultSetID); err != nil && !errors.Is(err, storm.ErrNotFound) {
return nil, errors.Wrap(err, "cannot get head")
}
var rss serialisable.ResultSetSnapshot
if err := s.ws.One("ID", headResultSetID, &rss); err != nil {
if errors.Is(err, storm.ErrNotFound) {
return nil, nil
} else {
return nil, errors.Wrap(err, "cannot get head")
}
}
return &rss, nil
}

View file

@ -0,0 +1,9 @@
package workspaces
import "github.com/lmika/audax/internal/dynamo-browse/models/serialisable"
type ResultSetSnapshotStore interface {
Save(rs *serialisable.ResultSetSnapshot) error
SetAsHead(resultSetId int64) error
Head() (*serialisable.ResultSetSnapshot, error)
}

View file

@ -0,0 +1,43 @@
package workspaces
import (
"github.com/lmika/audax/internal/dynamo-browse/models"
"github.com/lmika/audax/internal/dynamo-browse/models/serialisable"
"github.com/pkg/errors"
"time"
)
type Service struct {
store ResultSetSnapshotStore
}
func NewService(store ResultSetSnapshotStore) *Service {
return &Service{
store: store,
}
}
func (s *Service) PushSnapshot(rs *models.ResultSet) error {
newSnapshot := &serialisable.ResultSetSnapshot{
Time: time.Now(),
TableInfo: rs.TableInfo,
}
if q := rs.Query; q != nil {
newSnapshot.Query.Expression = q.String()
}
if head, err := s.store.Head(); head != nil {
newSnapshot.BackLink = head.ID
} else if err != nil {
return errors.Wrap(err, "cannot get head result set")
}
if err := s.store.Save(newSnapshot); err != nil {
return errors.Wrap(err, "cannot save snapshot")
}
if err := s.store.SetAsHead(newSnapshot.ID); err != nil {
return errors.Wrap(err, "cannot set new snapshot as head")
}
return nil
}