From 1d78ecf2a3b6b09a30fd821d8db3e62fd9d853e4 Mon Sep 17 00:00:00 2001 From: Daniel Messias Date: Mon, 31 Oct 2022 14:13:56 +0000 Subject: [PATCH] LF client small tidyup --- data/lakeformation.go | 73 ++++++++++++++----------- ui/components/table/table.go | 11 +--- ui/pages/glue/glue.go | 2 +- ui/pages/iam/iam.go | 2 +- ui/pages/iam/role.go | 2 +- ui/pages/iam/user.go | 2 +- ui/pages/lakeformation/database.go | 35 ++++++++---- ui/pages/lakeformation/lakeformation.go | 6 +- ui/pages/lakeformation/spec.go | 4 +- ui/pages/lakeformation/table.go | 45 +++++++++++---- ui/pages/lambda/lambda.go | 2 +- ui/pages/rds/rds.go | 2 +- ui/pages/s3/bucket.go | 2 +- ui/pages/s3/s3.go | 4 +- 14 files changed, 116 insertions(+), 76 deletions(-) diff --git a/data/lakeformation.go b/data/lakeformation.go index 678bdcf..208d538 100644 --- a/data/lakeformation.go +++ b/data/lakeformation.go @@ -12,7 +12,6 @@ import ( "github.com/aws/aws-sdk-go-v2/service/lakeformation" lftypes "github.com/aws/aws-sdk-go-v2/service/lakeformation/types" "github.com/danielcmessias/sawsy/ui/components/table" - "github.com/danielcmessias/sawsy/utils" ) type LakeFormationClient struct { @@ -190,79 +189,89 @@ func (c *LakeFormationClient) GetDataLakeLocations(nextToken *string) ([]table.R return rows, output.NextToken, nil } -func (c *LakeFormationClient) GetDatabase(databaseName string) ([][]table.Row, error) { +func (c *LakeFormationClient) GetDatabaseDetails(databaseName string) ([]table.Row, error) { input := glue.GetDatabaseInput{ Name: aws.String(databaseName), } output, err := c.glue.GetDatabase(c.ctx, &input) if err != nil { - log.Fatalf("unable to get database: %v", err) + log.Fatalf("unable to get LF database: %v", err) } - var detailRows []table.Row - detailRows = append(detailRows, []string{"Name", utils.UseStr(output.Database.Name)}) - detailRows = append(detailRows, []string{"Location", utils.UseStr(output.Database.LocationUri)}) - detailRows = append(detailRows, []string{"Description", utils.UseStr(output.Database.Description)}) + rows := []table.Row{ + {"Name", aws.ToString(output.Database.Name)}, + {"Location", aws.ToString(output.Database.LocationUri)}, + {"Description", aws.ToString(output.Database.Description)}, + } + + return rows, nil +} - lfTagInput := lakeformation.GetResourceLFTagsInput{ +func (c *LakeFormationClient) GetDatabaseTags(databaseName string) ([]table.Row, error) { + input := lakeformation.GetResourceLFTagsInput{ Resource: &lftypes.Resource{ Database: &lftypes.DatabaseResource{ Name: aws.String(databaseName), }, }, - ShowAssignedLFTags: utils.BoolPtr(true), + ShowAssignedLFTags: aws.Bool(true), } - lfTagsOutput, err := c.lf.GetResourceLFTags(c.ctx, &lfTagInput) + output, err := c.lf.GetResourceLFTags(c.ctx, &input) if err != nil { - log.Fatalf("unable to get database: %v", err) + log.Fatalf("unable to get LF database tags: %v", err) } - var lfTagRows []table.Row - for _, t := range lfTagsOutput.LFTagOnDatabase { - lfTagRows = append(lfTagRows, []string{utils.UseStr(t.TagKey), strings.Join(t.TagValues, ",")}) + var rows []table.Row + for _, t := range output.LFTagOnDatabase { + rows = append(rows, []string{aws.ToString(t.TagKey), strings.Join(t.TagValues, ",")}) } - return [][]table.Row{detailRows, lfTagRows}, nil + return rows, nil } -func (c *LakeFormationClient) GetTable(tableName string, databaseName string) ([][]table.Row, error) { +func (c *LakeFormationClient) GetTableDetailsAndSchema(tableName string, databaseName string) ([]table.Row, []table.Row, error) { input := glue.GetTableInput{ DatabaseName: aws.String(databaseName), Name: aws.String(tableName), } output, err := c.glue.GetTable(c.ctx, &input) if err != nil { - log.Fatalf("unable to get table: %v", err) + log.Fatalf("unable to get LF table: %v", err) } - var detailRows []table.Row - detailRows = append(detailRows, []string{"Table Name", utils.UseStr(output.Table.Name)}) - detailRows = append(detailRows, []string{"Database Name", utils.UseStr(output.Table.DatabaseName)}) - detailRows = append(detailRows, []string{"Location", utils.UseStr(output.Table.StorageDescriptor.Location)}) - detailRows = append(detailRows, []string{"Description", utils.UseStr(output.Table.Description)}) - detailRows = append(detailRows, []string{"Last Updated", output.Table.UpdateTime.String()}) + detailsRows := []table.Row{ + {"Table Name", aws.ToString(output.Table.Name)}, + {"Database Name", aws.ToString(output.Table.DatabaseName)}, + {"Location", aws.ToString(output.Table.StorageDescriptor.Location)}, + {"Description", aws.ToString(output.Table.Description)}, + {"Last Updated", formatTime(output.Table.UpdateTime)}, + } var schemaRows []table.Row for i, c := range output.Table.StorageDescriptor.Columns { - schemaRows = append(schemaRows, []string{strconv.Itoa(i + 1), utils.UseStr(c.Name), utils.UseStr(c.Type)}) + schemaRows = append(schemaRows, []string{strconv.Itoa(i + 1), aws.ToString(c.Name), aws.ToString(c.Type)}) } - lfTagInput := lakeformation.GetResourceLFTagsInput{ + return detailsRows, schemaRows, nil +} + +func (c *LakeFormationClient) GetTableTags(tableName string, databaseName string) ([]table.Row, error) { + input := lakeformation.GetResourceLFTagsInput{ Resource: &lftypes.Resource{ Table: &lftypes.TableResource{ DatabaseName: aws.String(databaseName), Name: aws.String(tableName), }, }, - ShowAssignedLFTags: utils.BoolPtr(true), + ShowAssignedLFTags: aws.Bool(true), } - lfTagsOutput, err := c.lf.GetResourceLFTags(c.ctx, &lfTagInput) + output, err := c.lf.GetResourceLFTags(c.ctx, &input) if err != nil { - log.Fatalf("unable to get database: %v", err) + log.Fatalf("unable to get LF table tags: %v", err) } - var lfTagRows []table.Row - for _, t := range lfTagsOutput.LFTagsOnTable { - lfTagRows = append(lfTagRows, []string{utils.UseStr(t.TagKey), strings.Join(t.TagValues, ",")}) + var rows []table.Row + for _, t := range output.LFTagsOnTable { + rows = append(rows, []string{aws.ToString(t.TagKey), strings.Join(t.TagValues, ",")}) } - return [][]table.Row{detailRows, schemaRows, lfTagRows}, nil + return rows, nil } diff --git a/ui/components/table/table.go b/ui/components/table/table.go index 73b271a..732540c 100644 --- a/ui/components/table/table.go +++ b/ui/components/table/table.go @@ -165,13 +165,8 @@ func (m *Model) GetCurrentRow() Row { return m.filteredRows[m.rowsViewport.GetCurrItem()] } -func (m *Model) GetMarshalledRow() map[string]string { - row := m.GetCurrentRow() - rowMap := make(map[string]string) - for i, col := range m.Columns { - rowMap[col.Title] = row[i] - } - return rowMap +func (m *Model) GetCurrentRowMarshalled() map[string]string { + return m.MarhsalRow(m.GetCurrentRow()) } func (m *Model) MarhsalRow(row Row) map[string]string { @@ -182,7 +177,7 @@ func (m *Model) MarhsalRow(row Row) map[string]string { return rowMap } -func (m *Model) UnmarhsalRow(row map[string]string) Row { +func (m *Model) UnmarshalRow(row map[string]string) Row { rowArr := make(Row, len(m.Columns)) for i, col := range m.Columns { rowArr[i] = row[col.Title] diff --git a/ui/pages/glue/glue.go b/ui/pages/glue/glue.go index b456c8e..1746fed 100644 --- a/ui/pages/glue/glue.go +++ b/ui/pages/glue/glue.go @@ -64,7 +64,7 @@ func (m *GluePageModel) Inspect(client data.Client) tea.Cmd { if !ok { log.Fatal("This pane is not a table") } - row := table.GetMarshalledRow() + row := table.GetCurrentRowMarshalled() var nextPage string var pageContext interface{} diff --git a/ui/pages/iam/iam.go b/ui/pages/iam/iam.go index d9b990b..71ad90d 100644 --- a/ui/pages/iam/iam.go +++ b/ui/pages/iam/iam.go @@ -63,7 +63,7 @@ func (m *IAMPageModel) Inspect(client data.Client) tea.Cmd { log.Fatal("This pane is not a table") } - row := table.GetMarshalledRow() + row := table.GetCurrentRowMarshalled() switch m.GetCurrentPaneId() { case m.GetPaneId("Users"): diff --git a/ui/pages/iam/role.go b/ui/pages/iam/role.go index 36f1010..d0ada6f 100644 --- a/ui/pages/iam/role.go +++ b/ui/pages/iam/role.go @@ -82,7 +82,7 @@ func (m *RolePageModel) Inspect(client data.Client) tea.Cmd { log.Fatal("This pane is not a table") } - row := table.GetMarshalledRow() + row := table.GetCurrentRowMarshalled() switch m.GetCurrentPaneId() { case m.GetPaneId("Policies"): return func() tea.Msg { diff --git a/ui/pages/iam/user.go b/ui/pages/iam/user.go index 1b9fd8e..de5ffb1 100644 --- a/ui/pages/iam/user.go +++ b/ui/pages/iam/user.go @@ -69,7 +69,7 @@ func (m *UserPageModel) Inspect(client data.Client) tea.Cmd { switch m.GetCurrentPaneId() { case m.GetPaneId("Policies"): - row := table.GetMarshalledRow() + row := table.GetCurrentRowMarshalled() return func() tea.Msg { return page.ChangePageMsg{ NewPage: "iam/policy", diff --git a/ui/pages/lakeformation/database.go b/ui/pages/lakeformation/database.go index 839fef0..00d56fa 100644 --- a/ui/pages/lakeformation/database.go +++ b/ui/pages/lakeformation/database.go @@ -22,19 +22,32 @@ func NewDatabasePage(ctx *context.ProgramContext) *DatabasePageModel { } func (m *DatabasePageModel) FetchData(client data.Client) tea.Cmd { + return tea.Batch( + m.fetchDatabaseDetails(client), + m.fetchDatabaseTags(client), + ) +} + +func (m *DatabasePageModel) fetchDatabaseDetails(client data.Client) tea.Cmd { return func() tea.Msg { - output, _ := client.LakeFormation.GetDatabase(m.Context.(DatabasePageContext).DatabaseName) - var msgs []page.NewRowsMsg - for i, rows := range output { - msgs = append(msgs, page.NewRowsMsg{ - Page: m.Spec.Name, - PaneId: i, - Rows: rows, - Overwrite: true, - }) + rows, _ := client.LakeFormation.GetDatabaseDetails(m.Context.(DatabasePageContext).DatabaseName) + msg := page.NewRowsMsg{ + Page: m.Spec.Name, + PaneId: m.GetPaneId("Details"), + Rows: rows, } - return page.BatchedNewRowsMsg{ - Msgs: msgs, + return msg + } +} + +func (m *DatabasePageModel) fetchDatabaseTags(client data.Client) tea.Cmd { + return func() tea.Msg { + rows, _ := client.LakeFormation.GetDatabaseTags(m.Context.(DatabasePageContext).DatabaseName) + msg := page.NewRowsMsg{ + Page: m.Spec.Name, + PaneId: m.GetPaneId("LF-Tags"), + Rows: rows, } + return msg } } diff --git a/ui/pages/lakeformation/lakeformation.go b/ui/pages/lakeformation/lakeformation.go index cd15923..af3449c 100644 --- a/ui/pages/lakeformation/lakeformation.go +++ b/ui/pages/lakeformation/lakeformation.go @@ -111,18 +111,18 @@ func (m *LakeFormationPageModel) Inspect(client data.Client) tea.Cmd { log.Fatal("This pane is not a table") } - row := table.GetMarshalledRow() + row := table.GetCurrentRowMarshalled() var nextPage string var pageContext interface{} switch m.Tabs.CurrentTabId { case m.GetPaneId("Databases"): - nextPage = "lakeformation/databases" + nextPage = "lakeformation/database" pageContext = DatabasePageContext{ DatabaseName: row["Database"], } case m.GetPaneId("Tables"): - nextPage = "lakeformation/tables" + nextPage = "lakeformation/table" pageContext = TablePageContext{ TableName: row["Table"], DatabaseName: row["Database"], diff --git a/ui/pages/lakeformation/spec.go b/ui/pages/lakeformation/spec.go index 7f61936..4e48ac3 100644 --- a/ui/pages/lakeformation/spec.go +++ b/ui/pages/lakeformation/spec.go @@ -125,7 +125,7 @@ var lakeFormationPageSpec = page.PageSpec{ } var databasePageSpec = page.PageSpec{ - Name: "lakeformation/databases", + Name: "lakeformation/database", PaneSpecs: []pane.PaneSpec{ table.TableSpec{ BaseSpec: pane.BaseSpec{ @@ -159,7 +159,7 @@ var databasePageSpec = page.PageSpec{ } var tablePageSpec = page.PageSpec{ - Name: "lakeformation/tables", + Name: "lakeformation/table", PaneSpecs: []pane.PaneSpec{ table.TableSpec{ BaseSpec: pane.BaseSpec{ diff --git a/ui/pages/lakeformation/table.go b/ui/pages/lakeformation/table.go index 821edf1..c9f5b09 100644 --- a/ui/pages/lakeformation/table.go +++ b/ui/pages/lakeformation/table.go @@ -23,20 +23,43 @@ func NewTablePage(ctx *context.ProgramContext) *TablePageModel { } func (m *TablePageModel) FetchData(client data.Client) tea.Cmd { - context := m.Context.(TablePageContext) + return tea.Batch( + m.fetchTableDetailsAndSchema(client), + m.fetchTableTags(client), + ) +} + +func (m *TablePageModel) fetchTableDetailsAndSchema(client data.Client) tea.Cmd { return func() tea.Msg { - output, _ := client.LakeFormation.GetTable(context.TableName, context.DatabaseName) - var msgs []page.NewRowsMsg - for i, rows := range output { - msgs = append(msgs, page.NewRowsMsg{ - Page: m.Spec.Name, - PaneId: i, - Rows: rows, - Overwrite: true, - }) + ctx := m.Context.(TablePageContext) + detailsRows, schemaRows, _ := client.LakeFormation.GetTableDetailsAndSchema(ctx.TableName, ctx.DatabaseName) + + detailsRowsMsg := page.NewRowsMsg{ + Page: m.Spec.Name, + PaneId: m.GetPaneId("Details"), + Rows: detailsRows, } + schemaRowsMsg := page.NewRowsMsg{ + Page: m.Spec.Name, + PaneId: m.GetPaneId("Schema"), + Rows: schemaRows, + } + return page.BatchedNewRowsMsg{ - Msgs: msgs, + Msgs: []page.NewRowsMsg{detailsRowsMsg, schemaRowsMsg}, + } + } +} + +func (m *TablePageModel) fetchTableTags(client data.Client) tea.Cmd { + return func() tea.Msg { + ctx := m.Context.(TablePageContext) + rows, _ := client.LakeFormation.GetTableTags(ctx.TableName, ctx.DatabaseName) + msg := page.NewRowsMsg{ + Page: m.Spec.Name, + PaneId: m.GetPaneId("LF-Tags"), + Rows: rows, } + return msg } } diff --git a/ui/pages/lambda/lambda.go b/ui/pages/lambda/lambda.go index 77be43f..aed8fbd 100644 --- a/ui/pages/lambda/lambda.go +++ b/ui/pages/lambda/lambda.go @@ -46,7 +46,7 @@ func (m *LambdaPageModel) Inspect(client data.Client) tea.Cmd { if !ok { log.Fatal("This pane is not a table") } - row := table.GetMarshalledRow() + row := table.GetCurrentRowMarshalled() var nextPage string var pageContext interface{} diff --git a/ui/pages/rds/rds.go b/ui/pages/rds/rds.go index de1cbb4..92adab2 100644 --- a/ui/pages/rds/rds.go +++ b/ui/pages/rds/rds.go @@ -47,7 +47,7 @@ func (m *RDSPageModel) Inspect(client data.Client) tea.Cmd { log.Fatal("This pane is not a table") } - row := table.GetMarshalledRow() + row := table.GetCurrentRowMarshalled() var nextPage string var pageContext interface{} diff --git a/ui/pages/s3/bucket.go b/ui/pages/s3/bucket.go index 56a9aa5..efa1435 100644 --- a/ui/pages/s3/bucket.go +++ b/ui/pages/s3/bucket.go @@ -117,7 +117,7 @@ func (m *BucketPageModel) Inspect(client data.Client) tea.Cmd { } context := m.Context.(BucketPageContext) - key := table.GetMarshalledRow()["Key"] + key := table.GetCurrentRowMarshalled()["Key"] sanitizedPrefix := context.Prefix + key sanitizedPrefix = strings.Replace(sanitizedPrefix, fmt.Sprintf("%s ", icons.FILE), "", 1) sanitizedPrefix = strings.Replace(sanitizedPrefix, fmt.Sprintf("%s ", icons.FOLDER), "", 1) diff --git a/ui/pages/s3/s3.go b/ui/pages/s3/s3.go index c654a7d..643a6f0 100644 --- a/ui/pages/s3/s3.go +++ b/ui/pages/s3/s3.go @@ -63,7 +63,7 @@ func (m *S3PageModel) fetchBucketRegion(client data.Client, row table.Row) tea.C return page.UpdateRowMsg{ Page: m.Spec.Name, PaneId: m.GetPaneId("Buckets"), - Row: table.UnmarhsalRow(marshalledRow), + Row: table.UnmarshalRow(marshalledRow), PrimaryKeyIndex: 0, } } @@ -79,7 +79,7 @@ func (m *S3PageModel) Inspect(client data.Client) tea.Cmd { log.Fatal("This pane is not a table") } - row := table.GetMarshalledRow() + row := table.GetCurrentRowMarshalled() // If the region hasn't been found yet, we need to wait. // An alternative idea might be to just fetch the region in GetObjects if it's missing at that