@@ -8,11 +8,99 @@ import {GaxiosPromise} from "googleapis-common";
88export class GoogleSheetConnectorService {
99
1010 private readonly _jwtClient : JWT ;
11+ private _loadedSpreadsheet : sheets_v4 . Schema$Spreadsheet ;
12+ private loadedSheet : sheets_v4 . Schema$Sheet ;
1113 constructor ( private _authService : GoogleAuthService ) {
1214
1315 this . _jwtClient = this . _authService . getClient ( ) ;
1416 }
1517
18+ getLoadedSheet ( ) : sheets_v4 . Schema$Sheet {
19+ return this . loadedSheet ;
20+ }
21+
22+ async loadSheet ( spreadsheetId : string , index : number ) : Promise < sheets_v4 . Schema$Sheet > {
23+ if ( ! this . _loadedSpreadsheet || this . _loadedSpreadsheet . spreadsheetId !== spreadsheetId ) {
24+ await this . loadSpreadSheet ( spreadsheetId ) ;
25+ }
26+
27+ this . loadedSheet = await this . getSheetByLoadedSpreadSheetIndex ( index ) ;
28+ return this . loadedSheet ;
29+ }
30+
31+ getLoadedSpreadSheet ( ) : sheets_v4 . Schema$Spreadsheet {
32+ return this . _loadedSpreadsheet ;
33+ }
34+
35+ async loadSpreadSheet ( spreadsheetId : string ) : Promise < sheets_v4 . Schema$Spreadsheet > {
36+ const sheets = this . getGoogleSheetConnect ( )
37+ const res = await sheets . spreadsheets . get ( {
38+ spreadsheetId : spreadsheetId ,
39+ includeGridData : true ,
40+ } ) ;
41+
42+ this . _loadedSpreadsheet = res . data ;
43+
44+ return res . data ;
45+ }
46+
47+ /**
48+ * Read a range of cells from a spreadsheet
49+ *
50+ * @param range
51+ *
52+ * @returns {Promise<any> }
53+ */
54+ async readRangeFromLoadedSheet ( range : string ) : Promise < any [ ] [ ] > {
55+ return this . readRangeFromLoadedSpreadSheet ( this . getLoadedSheet ( ) . properties . title , range ) ;
56+ }
57+
58+ /**
59+ * Read a range of cells from a spreadsheet
60+ *
61+ * @param sheet
62+ * @param range
63+ *
64+ * @returns {Promise<any> }
65+ */
66+ async readRangeFromLoadedSpreadSheet ( sheet , range : string ) : Promise < any [ ] [ ] > {
67+
68+ const spreadsheet = this . getLoadedSpreadSheet ( ) ;
69+ const sheetIndex = spreadsheet . sheets . findIndex ( ( s ) => s . properties . title === sheet ) ;
70+ const sheetData = spreadsheet . sheets [ sheetIndex ] . data [ 0 ] . rowData ;
71+ const rangeData = range . split ( '!' ) [ 1 ] ;
72+ return this . getRangeData ( sheetData , rangeData ) ;
73+ }
74+
75+ private getCharNumber ( char : string ) : number {
76+ let result = 0 ;
77+ for ( let i = 0 ; i < char . length ; i ++ ) {
78+ result = result * 26 + char . charCodeAt ( i ) - 64 ;
79+ }
80+ return result ;
81+ }
82+
83+ private getRangeCell ( range : string ) : { row : number , column : number } {
84+ const row = parseInt ( range . match ( / \d + / ) [ 0 ] ) - 1 ;
85+ const column = this . getCharNumber ( range . match ( / [ A - Z ] + / ) [ 0 ] ) - 1 ;
86+ return { row, column} ;
87+ }
88+ private getRangeData ( sheetData : sheets_v4 . Schema$RowData [ ] , range : string ) : any [ ] [ ] {
89+ const rangeData = range . split ( ':' ) ;
90+ const start = this . getRangeCell ( rangeData [ 0 ] ) ;
91+ const end = this . getRangeCell ( rangeData [ 1 ] ) ;
92+ const data = [ ] ;
93+ for ( let i = start . row ; i <= end . row ; i ++ ) {
94+ const row = [ ] ;
95+ for ( let j = start . column ; j <= end . column ; j ++ ) {
96+ const value = sheetData [ i ] . values [ j ] . formattedValue ;
97+ row . push ( value ) ;
98+ }
99+ data . push ( row ) ;
100+ }
101+ return data ;
102+ }
103+
16104 /**
17105 * Read a range of cells from a spreadsheet
18106 *
@@ -131,6 +219,13 @@ export class GoogleSheetConnectorService{
131219 } ) ;
132220 }
133221
222+ private async getSheetByLoadedSpreadSheetIndex ( index : number ) : Promise < sheets_v4 . Schema$Sheet > {
223+ return this . _loadedSpreadsheet . sheets [ index ] ;
224+ }
225+
226+ private async getSheetBySpreadSheetIndex ( spreedsheatId : string , index : number ) : Promise < sheets_v4 . Schema$Sheet > {
227+ return this . readAllSheet ( spreedsheatId ) . then ( ( sheets ) => sheets [ index ] ) ;
228+ }
134229 /**
135230 * Create a new spreadsheet
136231 *
@@ -152,6 +247,145 @@ export class GoogleSheetConnectorService{
152247 return res . data . spreadsheetId ;
153248 }
154249
250+ private async getSheetMergeMetadata (
251+ sheet : sheets_v4 . Schema$Sheet ,
252+ ) {
253+ // Find all rows groups locations from merged cells
254+ return sheet . merges . map ( ( merge ) => ( {
255+ sheetId : merge . sheetId ,
256+ start : merge . startRowIndex ,
257+ end : merge . endRowIndex ,
258+ } ) ) ;
259+ }
260+
261+ /**
262+ * Insert empty dimension
263+ *
264+ * @param spreadsheetId
265+ * @param sheetId
266+ * @param dimension
267+ * @param startIndex
268+ * @param endIndex
269+ */
270+ private async insertDimension (
271+ spreadsheetId : string ,
272+ sheetId : number ,
273+ dimension : string ,
274+ startIndex : number ,
275+ endIndex : number ,
276+ ) {
277+ // Initialize request parameters.
278+ const request : sheets_v4 . Schema$Request = {
279+ insertDimension : {
280+ range : {
281+ sheetId,
282+ dimension,
283+ startIndex,
284+ endIndex,
285+ } ,
286+ inheritFromBefore : false ,
287+ } ,
288+ } ;
289+
290+ // Update spreadsheet.
291+ return this . getGoogleSheetConnect ( )
292+ . spreadsheets . batchUpdate ( {
293+ spreadsheetId : spreadsheetId ,
294+ requestBody : {
295+ requests : [ request ] ,
296+ } ,
297+ } ) ;
298+ }
299+
300+ /**
301+ * Insert empty row
302+ *
303+ * @param spreadsheetId,
304+ * @param sheetId
305+ * @param startIndex
306+ * @param endIndex
307+ */
308+ private async insertRow (
309+ spreadsheetId : string ,
310+ sheetId : number ,
311+ startIndex : number ,
312+ endIndex : number ,
313+ ) {
314+ return this . insertDimension ( spreadsheetId , sheetId , 'ROWS' , startIndex , endIndex ) ;
315+ }
316+
317+ /**
318+ * Merge cells in sheet
319+ *
320+ * @param spreadsheetId
321+ * @param sheetId
322+ * @param startRowIndex
323+ * @param endRowIndex
324+ * @param startColumnIndex
325+ * @param endColumnIndex
326+ */
327+ private async mergeCells (
328+ spreadsheetId : string ,
329+ sheetId : number ,
330+ startRowIndex : number ,
331+ endRowIndex : number ,
332+ startColumnIndex : number ,
333+ endColumnIndex : number ,
334+ ) {
335+ // Initialize request parameters.
336+ const request : sheets_v4 . Schema$Request = {
337+ mergeCells : {
338+ range : {
339+ sheetId : sheetId ,
340+ startRowIndex : startRowIndex ,
341+ endRowIndex : endRowIndex ,
342+ startColumnIndex : startColumnIndex ,
343+ endColumnIndex : endColumnIndex ,
344+ } ,
345+ } ,
346+ } ;
347+
348+ return await this . getGoogleSheetConnect ( )
349+ . spreadsheets . batchUpdate ( {
350+ spreadsheetId : spreadsheetId ,
351+ requestBody : {
352+ requests : [ request ] ,
353+ } ,
354+ } ) ;
355+ }
356+
357+ async appendRow ( spreedsheatId , sheet , rows ) {
358+ // Initialize request parameters
359+ const request = {
360+ spreadsheetId : spreedsheatId ,
361+ range : `${ sheet . properties . title } ` ,
362+ resource : {
363+ values : rows ,
364+ } ,
365+ valueInputOption : 'USER_ENTERED' ,
366+ insertDataOption : 'INSERT_ROWS' ,
367+ } ;
368+
369+ return await this . getGoogleSheetConnect ( ) . spreadsheets . values . append ( request ) ;
370+ }
371+
372+ /**
373+ * Get column value from a spreadsheet
374+ * @param spreedsheatId
375+ * @param sheet
376+ * @param columnKey
377+ * @private
378+ */
379+ private async getColumnValues ( spreedsheatId , sheet , columnKey : string ) : Promise < string [ ] > {
380+ const values = await this . getGoogleSheetConnect ( )
381+ . spreadsheets . values . batchGet ( {
382+ spreadsheetId : spreedsheatId ,
383+ ranges : [ `${ sheet . properties . title } !${ columnKey } ` ] ,
384+ } ) ;
385+
386+ return values . data . valueRanges [ 0 ] . values . map ( ( value : string [ ] ) => value [ 0 ] ) ;
387+ }
388+
155389 /**
156390 * Get Google Sheet Connection
157391 *
0 commit comments