Skip to content

Commit

Permalink
feat: fixed interface
Browse files Browse the repository at this point in the history
  • Loading branch information
deejiw committed Oct 3, 2023
1 parent d99bd2e commit 9c05c32
Show file tree
Hide file tree
Showing 6 changed files with 397 additions and 0 deletions.
51 changes: 51 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# General
.DS_Store
.AppleDouble
.LSOverride

# Icon must end with two \r
Icon

# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db

# Dump file
*.stackdump

# Folder config file
[Dd]esktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp

# Windows shortcuts
*.lnk
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ require (
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
github.com/googleapis/gax-go/v2 v2.7.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ github.com/google/pprof v0.0.0-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE
github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k=
github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
Expand Down
4 changes: 4 additions & 0 deletions module.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/dop251/goja"
"go.k6.io/k6/js/common"
"go.k6.io/k6/js/modules"
"google.golang.org/api/sheets/v4"
)

func init() {
Expand All @@ -30,6 +31,9 @@ type (
// vu modules.VU
keyByte []byte
scope []string

// Client
sheet *sheets.Service
}

GcpConfig struct {
Expand Down
212 changes: 212 additions & 0 deletions sheet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
package gcp

import (
"context"
"fmt"
"log"
"strconv"
"strings"

"google.golang.org/api/option"
"google.golang.org/api/sheets/v4"
)

// Direct interface from https://pkg.go.dev/google.golang.org/api/sheets/v4#SpreadsheetsValuesService.

// This function retrieves data from a Google Sheet.
// Parameters:
// - spreadsheetId: the ID of the Google Sheet.
// - sheetName: the name of the sheet to retrieve data from.
// - cellRange: the range of cells to retrieve data from.
// Returns:
// - [][]interface{}: a 2D slice of interface{} values representing the retrieved data.
// - error: an error if one occurred, otherwise nil.
func (g *Gcp) SpreadsheetGet(spreadsheetId string, sheetName string, cellRange string) ([][]interface{}, error) {
g.sheetClient()

res, err := g.sheet.Spreadsheets.Values.Get(spreadsheetId, fmt.Sprintf("%s!%s", sheetName, cellRange)).Do()
if err != nil || res.HTTPStatusCode != 200 {
log.Fatalf("unable to get data from range %s in sheet %s <%v>.", cellRange, sheetName, err)
}

if len(res.Values) == 0 {
fmt.Printf("No data found in range %s on sheet %s.", cellRange, sheetName)
return nil, nil
}

return res.Values, nil
}

// Appends a row of data to a Google Sheet.
// Parameters:
// - spreadsheetId: the ID of the Google Sheet.
// - sheetName: the name of the sheet to append data to.
// - valueRange: a slice of interface{} values representing the data to append.
// Returns:
// - string: an empty string.
// - error: an error if one occurred, otherwise nil.
func (g *Gcp) SpreadsheetAppend(spreadsheetId string, sheetName string, valueRange []interface{}) (string, error) {
ctx := context.Background()
g.sheetClient()

row := &sheets.ValueRange{
Values: [][]interface{}{valueRange},
}

res, err := g.sheet.Spreadsheets.Values.Append(spreadsheetId, sheetName, row).ValueInputOption("RAW").InsertDataOption("INSERT_ROWS").Context(ctx).Do()
if err != nil || res.HTTPStatusCode != 200 {
log.Fatalf("unable to append data into sheet %s <%v>.", sheetName, err)
}

return "", nil
}

// Updates a range of cells in a Google Sheet.
// Parameters:
// - spreadsheetId: the ID of the Google Sheet.
// - sheetName: the name of the sheet to update data in.
// - cellRange: the range of cells to update data in.
// - valueRange: a slice of interface{} values representing the data to update.
// Returns:
// - string: an empty string.
// - error: an error if one occurred, otherwise nil.
func (g *Gcp) SpreadsheetUpdate(spreadsheetId string, sheetName string, cellRange string, valueRange []interface{}) (string, error) {
ctx := context.Background()
g.sheetClient()

row := &sheets.ValueRange{
Values: [][]interface{}{valueRange},
}

res, err := g.sheet.Spreadsheets.Values.Update(spreadsheetId, fmt.Sprintf("%s!%s", sheetName, cellRange), row).ValueInputOption("RAW").Context(ctx).Do()
if err != nil || res.HTTPStatusCode != 200 {
log.Fatalf("unable to update data into sheet %s range %s <%v>.", sheetName, cellRange, err)
}

return "", nil
}

// Similar to https://pkg.go.dev/google.golang.org/api/sheets/v4#SpreadsheetsService.GetByDataFilter
// Get a row from a Google Sheet based on filters.
// Parameters:
// - spreadsheetId: the ID of the Google Sheet.
// - sheetName: the name of the sheet to search data in.
// - filters: a map of column names to values to search for in the specified column.
// Returns:
// - map[string]interface{}: a map of the row data if a match is found.
// - error: an error if one occurred, otherwise nil.
func (g *Gcp) SpreadsheetGetRowByFilters(spreadsheetId string, sheetName string, filters map[string]string) (map[string]interface{}, error) {
cellRange, headers := g.findCellRangeAndHeaders(spreadsheetId, sheetName)
rows, _ := g.SpreadsheetGet(spreadsheetId, sheetName, cellRange)

// Find matching rows based on the filters
for _, row := range rows {
match := true
for key, value := range filters {
headerIndex := findHeaderIndex(headers, key)
if headerIndex == -1 || headerIndex >= len(row) || strings.TrimSpace(row[headerIndex].(string)) != value {
match = false
break
}
}
if match {
return mergeKV(headers, row), nil
}
}

fmt.Printf("No row matches filters %v", filters)
return nil, nil
}

// This function appends a row of data to a Google Sheet with a unique ID.
// Parameters:
// - spreadsheetId: the ID of the Google Sheet.
// - sheetName: the name of the sheet to append data to.
// - values: a slice of interface{} values representing the data to append.
// Returns:
// - string: the unique ID of the appended row.
// - error: an error if one occurred, otherwise nil.
func (g *Gcp) SpreadsheetAppendWithUniqueId(spreadsheetId string, sheetName string, values map[string]interface{}) (int64, error) {
ctx := context.Background()
g.sheetClient()

_, headers := g.findCellRangeAndHeaders(spreadsheetId, sheetName)
rows, _ := g.SpreadsheetGet(spreadsheetId, sheetName, "A:A")
id := getUniqueId(rows)
values["id"] = id

row := &sheets.ValueRange{
Values: [][]interface{}{sortValuesByHeaders(headers, values)},
}

res, err := g.sheet.Spreadsheets.Values.Append(spreadsheetId, sheetName, row).ValueInputOption("RAW").Context(ctx).Do()
if err != nil || res.HTTPStatusCode != 200 {
log.Fatalf("unable to append data into sheet %s <%v>.", sheetName, err)
}

return id, nil
}

func (g *Gcp) SpreadsheetGetUniqueIdByFiltersAndAppendIfNotExist(spreadsheetId string, sheetName string, filters map[string]string, values map[string]interface{}) (int64, error) {
var id int64
ctx := context.Background()
g.sheetClient()

_, headers := g.findCellRangeAndHeaders(spreadsheetId, sheetName)

rowByFilters, _ := g.SpreadsheetGetRowByFilters(spreadsheetId, sheetName, filters)
rows, _ := g.SpreadsheetGet(spreadsheetId, sheetName, "A:A")

if rowByFilters == nil {
id = getUniqueId(rows)
} else {
i, err := strconv.ParseInt(rowByFilters["id"].(string), 0, 64)
if err != nil {
log.Fatalf("unable to parse string to int64 for %s <%v>.", rowByFilters["id"].(string), err)
}
return i, nil
}

values["id"] = id

row := &sheets.ValueRange{
Values: [][]interface{}{sortValuesByHeaders(headers, values)},
}

res, err := g.sheet.Spreadsheets.Values.Append(spreadsheetId, sheetName, row).ValueInputOption("RAW").Context(ctx).Do()
if err != nil || res.HTTPStatusCode != 200 {
log.Fatalf("unable to append data into sheet %s <%v>.", sheetName, err)
}

return id, nil
}

// This function initializes the Google Sheets client.
func (g *Gcp) sheetClient() {
if g.sheet == nil {
ctx := context.Background()
jwt, err := getJwtConfig(g.keyByte, g.scope)
if err != nil {
log.Fatalf("could not get JWT config with scope %s <%v>.", g.scope, err)
}

c, err := sheets.NewService(ctx, option.WithTokenSource(jwt.TokenSource(ctx)))

if err != nil {
log.Fatalf("could not initialize Sheets client <%v>.", err)
}

g.sheet = c
}
}

// This function returns the cell range of the first row of a Google Sheet.
// Parameters:
// - spreadsheetId: the ID of the Google Sheet.
// - sheetName: the name of the sheet to retrieve data from.
// Returns:
// - string: the cell range of the first row.
func (g *Gcp) findCellRangeAndHeaders(spreadsheetId string, sheetName string) (string, []interface{}) {
rows, _ := g.SpreadsheetGet(spreadsheetId, sheetName, "1:1")
return fmt.Sprintf("A:%s", columnIndexToLetter(len(rows[0])-1)), rows[0]
}
Loading

0 comments on commit 9c05c32

Please sign in to comment.