-
Notifications
You must be signed in to change notification settings - Fork 0
/
gsheet.go
147 lines (120 loc) · 3.52 KB
/
gsheet.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package gsheets
import (
"context"
"fmt"
"golang.org/x/oauth2/google"
"google.golang.org/api/option"
"google.golang.org/api/sheets/v4"
)
var scopes = []string{
"https://www.googleapis.com/auth/drive",
"https://www.googleapis.com/auth/drive.file",
"https://www.googleapis.com/auth/drive.readonly",
"https://www.googleapis.com/auth/spreadsheets",
"https://www.googleapis.com/auth/spreadsheets.readonly",
}
type SheetValueAppender interface {
AppendValues(spreadsheetId string, sheetId int64, data [][]string) error
}
type SheetService interface {
SheetValueAppender
GetFirstSheet(spreadsheetId string) (*Sheet, error)
}
type sheetsService struct {
service *sheets.Service
}
type SpreadSheet struct {
Id string
}
type Sheet struct {
Id int64
Title string
Index int64
}
func NewDefaultService() (SheetService, error) {
ctx := context.Background()
credentials, err := google.FindDefaultCredentials(ctx, scopes...)
if err != nil {
return nil, err
}
service, err := sheets.NewService(context.Background(), option.WithCredentials(credentials))
if err != nil {
return nil, err
}
return &sheetsService{service: service}, nil
}
func NewService(service *sheets.Service) (SheetService, error) {
return &sheetsService{service: service}, nil
}
func (s *sheetsService) AppendValues(spreadsheetId string, sheetId int64, data [][]string) error {
sheetName, err := s.getSheetName(spreadsheetId, sheetId)
if err != nil {
return fmt.Errorf("unable to append data, spreadsheet='%s' sheetId='%d': %w", spreadsheetId, sheetId, err)
}
_range := fmt.Sprintf("'%s'!A:A", sheetName)
values := toValues(data)
valueRange := &sheets.ValueRange{
MajorDimension: "ROWS",
Values: values,
}
_, err = s.service.Spreadsheets.Values.Append(spreadsheetId, _range, valueRange).
ValueInputOption("RAW").
InsertDataOption("INSERT_ROWS").
Do()
if err != nil {
return fmt.Errorf("unable to append data, spreadsheet='%s' sheetId='%d': %w", spreadsheetId, sheetId, err)
}
return nil
}
func (s *sheetsService) GetFirstSheet(spreadsheetId string) (*Sheet, error) {
return s.getSheetByIndex(spreadsheetId, 0)
}
func (s *sheetsService) getSheetByIndex(spreadsheetId string, index int64) (*Sheet, error) {
sheets, err := s.getSheets(spreadsheetId)
if err != nil {
return nil, fmt.Errorf("cannot read spreadsheet: %w", err)
}
for _, sheet := range sheets {
if sheet.Index == index {
return sheet, nil
}
}
return nil, fmt.Errorf("cannot find sheet with index 0")
}
func (s *sheetsService) getSheets(spreadsheetId string) ([]*Sheet, error) {
resp, err := s.service.Spreadsheets.Get(spreadsheetId).Do()
if err != nil {
return nil, fmt.Errorf("cannot read spreadsheet: %w", err)
}
sheets := make([]*Sheet, 0, len(resp.Sheets))
for _, sheet := range resp.Sheets {
sheets = append(sheets, &Sheet{
Id: sheet.Properties.SheetId,
Title: sheet.Properties.Title,
Index: sheet.Properties.Index,
})
}
return sheets, nil
}
func (s *sheetsService) getSheetName(spreadsheetId string, sheetId int64) (string, error) {
allSheets, err := s.getSheets(spreadsheetId)
if err != nil {
return "", err
}
for _, sheet := range allSheets {
if sheet.Id == sheetId {
return sheet.Title, nil
}
}
return "", fmt.Errorf("sheet does not exist, spreadsheet='%s' sheetId='%d'", spreadsheetId, sheetId)
}
func toValues(data [][]string) [][]interface{} {
values := make([][]interface{}, len(data))
for i, row := range data {
values[i] = make([]interface{}, len(row))
for j, cell := range row {
values[i][j] = cell
}
}
return values
}