Skip to content

Commit

Permalink
feat: expand methods and allow stored sheet feature
Browse files Browse the repository at this point in the history
  • Loading branch information
johnkhansrc committed Dec 31, 2022
1 parent fb9318e commit 67ddc66
Show file tree
Hide file tree
Showing 2 changed files with 235 additions and 1 deletion.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nest-google-sheet-connector",
"version": "1.1.3",
"version": "2.0.0",
"description": "A Google Sheet integration for NestJs",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
234 changes: 234 additions & 0 deletions src/google-sheet-connector.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,99 @@ import {GaxiosPromise} from "googleapis-common";
export class GoogleSheetConnectorService{

private readonly _jwtClient: JWT;
private _loadedSpreadsheet: sheets_v4.Schema$Spreadsheet;
private loadedSheet: sheets_v4.Schema$Sheet;
constructor(private _authService: GoogleAuthService) {

this._jwtClient = this._authService.getClient();
}

getLoadedSheet(): sheets_v4.Schema$Sheet {
return this.loadedSheet;
}

async loadSheet(spreadsheetId: string, index: number): Promise<sheets_v4.Schema$Sheet> {
if (!this._loadedSpreadsheet || this._loadedSpreadsheet.spreadsheetId !== spreadsheetId) {
await this.loadSpreadSheet(spreadsheetId);
}

this.loadedSheet = await this.getSheetByLoadedSpreadSheetIndex(index);
return this.loadedSheet;
}

getLoadedSpreadSheet(): sheets_v4.Schema$Spreadsheet {
return this._loadedSpreadsheet;
}

async loadSpreadSheet(spreadsheetId: string): Promise<sheets_v4.Schema$Spreadsheet> {
const sheets = this.getGoogleSheetConnect()
const res = await sheets.spreadsheets.get({
spreadsheetId: spreadsheetId,
includeGridData: true,
});

this._loadedSpreadsheet = res.data;

return res.data;
}

/**
* Read a range of cells from a spreadsheet
*
* @param range
*
* @returns {Promise<any>}
*/
async readRangeFromLoadedSheet(range: string): Promise<any[][]> {
return this.readRangeFromLoadedSpreadSheet(this.getLoadedSheet().properties.title, range);
}

/**
* Read a range of cells from a spreadsheet
*
* @param sheet
* @param range
*
* @returns {Promise<any>}
*/
async readRangeFromLoadedSpreadSheet(sheet, range: string): Promise<any[][]> {

const spreadsheet = this.getLoadedSpreadSheet();
const sheetIndex = spreadsheet.sheets.findIndex((s) => s.properties.title === sheet);
const sheetData = spreadsheet.sheets[sheetIndex].data[0].rowData;
const rangeData = range.split('!')[1];
return this.getRangeData(sheetData, rangeData);
}

private getCharNumber(char: string): number {
let result = 0;
for (let i = 0; i < char.length; i++) {
result = result * 26 + char.charCodeAt(i) - 64;
}
return result;
}

private getRangeCell(range: string): { row: number, column: number } {
const row = parseInt(range.match(/\d+/)[0]) - 1;
const column = this.getCharNumber(range.match(/[A-Z]+/)[0]) - 1;
return {row, column};
}
private getRangeData(sheetData: sheets_v4.Schema$RowData[], range: string): any[][] {
const rangeData = range.split(':');
const start = this.getRangeCell(rangeData[0]);
const end = this.getRangeCell(rangeData[1]);
const data = [];
for (let i = start.row; i <= end.row; i++) {
const row = [];
for (let j = start.column; j <= end.column; j++) {
const value = sheetData[i].values[j].formattedValue;
row.push(value);
}
data.push(row);
}
return data;
}

/**
* Read a range of cells from a spreadsheet
*
Expand Down Expand Up @@ -131,6 +219,13 @@ export class GoogleSheetConnectorService{
});
}

private async getSheetByLoadedSpreadSheetIndex(index: number): Promise<sheets_v4.Schema$Sheet> {
return this._loadedSpreadsheet.sheets[index];
}

private async getSheetBySpreadSheetIndex(spreedsheatId: string, index: number): Promise<sheets_v4.Schema$Sheet> {
return this.readAllSheet(spreedsheatId).then((sheets) => sheets[index]);
}
/**
* Create a new spreadsheet
*
Expand All @@ -152,6 +247,145 @@ export class GoogleSheetConnectorService{
return res.data.spreadsheetId;
}

private async getSheetMergeMetadata(
sheet: sheets_v4.Schema$Sheet,
) {
// Find all rows groups locations from merged cells
return sheet.merges.map((merge) => ({
sheetId: merge.sheetId,
start: merge.startRowIndex,
end: merge.endRowIndex,
}));
}

/**
* Insert empty dimension
*
* @param spreadsheetId
* @param sheetId
* @param dimension
* @param startIndex
* @param endIndex
*/
private async insertDimension(
spreadsheetId: string,
sheetId: number,
dimension: string,
startIndex: number,
endIndex: number,
) {
// Initialize request parameters.
const request: sheets_v4.Schema$Request = {
insertDimension: {
range: {
sheetId,
dimension,
startIndex,
endIndex,
},
inheritFromBefore: false,
},
};

// Update spreadsheet.
return this.getGoogleSheetConnect()
.spreadsheets.batchUpdate({
spreadsheetId: spreadsheetId,
requestBody: {
requests: [request],
},
});
}

/**
* Insert empty row
*
* @param spreadsheetId,
* @param sheetId
* @param startIndex
* @param endIndex
*/
private async insertRow(
spreadsheetId: string,
sheetId: number,
startIndex: number,
endIndex: number,
) {
return this.insertDimension(spreadsheetId, sheetId, 'ROWS', startIndex, endIndex);
}

/**
* Merge cells in sheet
*
* @param spreadsheetId
* @param sheetId
* @param startRowIndex
* @param endRowIndex
* @param startColumnIndex
* @param endColumnIndex
*/
private async mergeCells(
spreadsheetId: string,
sheetId: number,
startRowIndex: number,
endRowIndex: number,
startColumnIndex: number,
endColumnIndex: number,
) {
// Initialize request parameters.
const request: sheets_v4.Schema$Request = {
mergeCells: {
range: {
sheetId: sheetId,
startRowIndex: startRowIndex,
endRowIndex: endRowIndex,
startColumnIndex: startColumnIndex,
endColumnIndex: endColumnIndex,
},
},
};

return await this.getGoogleSheetConnect()
.spreadsheets.batchUpdate({
spreadsheetId: spreadsheetId,
requestBody: {
requests: [request],
},
});
}

async appendRow(spreedsheatId, sheet, rows) {
// Initialize request parameters
const request = {
spreadsheetId: spreedsheatId,
range: `${sheet.properties.title}`,
resource: {
values: rows,
},
valueInputOption: 'USER_ENTERED',
insertDataOption: 'INSERT_ROWS',
};

return await this.getGoogleSheetConnect().spreadsheets.values.append(request);
}

/**
* Get column value from a spreadsheet
* @param spreedsheatId
* @param sheet
* @param columnKey
* @private
*/
private async getColumnValues(spreedsheatId, sheet, columnKey: string): Promise<string[]> {
const values = await this.getGoogleSheetConnect()
.spreadsheets.values.batchGet({
spreadsheetId: spreedsheatId,
ranges: [`${sheet.properties.title}!${columnKey}`],
});

return values.data.valueRanges[0].values.map((value: string[]) => value[0]);
}

/**
* Get Google Sheet Connection
*
Expand Down

0 comments on commit 67ddc66

Please sign in to comment.