Skip to content

Commit 67ddc66

Browse files
committed
feat: expand methods and allow stored sheet feature
1 parent fb9318e commit 67ddc66

File tree

2 files changed

+235
-1
lines changed

2 files changed

+235
-1
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nest-google-sheet-connector",
3-
"version": "1.1.3",
3+
"version": "2.0.0",
44
"description": "A Google Sheet integration for NestJs",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

src/google-sheet-connector.service.ts

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,99 @@ import {GaxiosPromise} from "googleapis-common";
88
export 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

Comments
 (0)