From f82436dc8d81adc3ed3453396cf662f0c6c08de1 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Sun, 20 Oct 2019 21:21:55 +0200 Subject: [PATCH] :sparkles: Make it possible to define how values should be interpreted --- .../nodes/GoogleSheets/GoogleSheet.ts | 35 ++--- .../nodes/GoogleSheets/GoogleSheets.node.ts | 120 +++++++++++++++++- 2 files changed, 134 insertions(+), 21 deletions(-) diff --git a/packages/nodes-base/nodes/GoogleSheets/GoogleSheet.ts b/packages/nodes-base/nodes/GoogleSheets/GoogleSheet.ts index 1f61b58884..2d9c7c7ec5 100644 --- a/packages/nodes-base/nodes/GoogleSheets/GoogleSheet.ts +++ b/packages/nodes-base/nodes/GoogleSheets/GoogleSheet.ts @@ -23,6 +23,10 @@ export interface ILookupValues { lookupValue: string; } +export type ValueInputOption = 'RAW' | 'USER_ENTERED'; + +export type ValueRenderOption = 'FORMATTED_VALUE' | 'FORMULA' | 'UNFORMATTED_VALUE'; + export class GoogleSheet { id: string; credentials: IGoogleAuthCredentials; @@ -43,7 +47,7 @@ export class GoogleSheet { /** * Returns the cell values */ - async getData(range: string): Promise { + async getData(range: string, valueRenderMode: ValueRenderOption): Promise { const client = await this.getAuthenticationClient(); const response = await Sheets.spreadsheets.values.get( @@ -51,7 +55,7 @@ export class GoogleSheet { auth: client, spreadsheetId: this.id, range, - valueRenderOption: 'UNFORMATTED_VALUE', + valueRenderOption: valueRenderMode, } ); @@ -62,7 +66,7 @@ export class GoogleSheet { /** * Sets the cell values */ - async batchUpdate(updateData: ISheetUpdateData[]) { + async batchUpdate(updateData: ISheetUpdateData[], valueInputMode: ValueInputOption) { const client = await this.getAuthenticationClient(); const response = await Sheets.spreadsheets.values.batchUpdate( @@ -70,10 +74,9 @@ export class GoogleSheet { // @ts-ignore auth: client, spreadsheetId: this.id, - valueInputOption: 'RAW', + valueInputOption: valueInputMode, resource: { data: updateData, - valueInputOption: "USER_ENTERED", }, } ); @@ -85,7 +88,7 @@ export class GoogleSheet { /** * Sets the cell values */ - async setData(range: string, data: string[][]) { + async setData(range: string, data: string[][], valueInputMode: ValueInputOption) { const client = await this.getAuthenticationClient(); const response = await Sheets.spreadsheets.values.update( @@ -94,7 +97,7 @@ export class GoogleSheet { auth: client, spreadsheetId: this.id, range, - valueInputOption: 'RAW', + valueInputOption: valueInputMode, resource: { values: data } @@ -108,7 +111,7 @@ export class GoogleSheet { /** * Appends the cell values */ - async appendData(range: string, data: string[][]) { + async appendData(range: string, data: string[][], valueInputMode: ValueInputOption) { const client = await this.getAuthenticationClient(); const response = await Sheets.spreadsheets.values.append( @@ -117,7 +120,7 @@ export class GoogleSheet { auth: client, spreadsheetId: this.id, range, - valueInputOption: 'RAW', + valueInputOption: valueInputMode, resource: { values: data } @@ -196,9 +199,9 @@ export class GoogleSheet { } - async appendSheetData(inputData: IDataObject[], range: string, keyRowIndex: number): Promise { + async appendSheetData(inputData: IDataObject[], range: string, keyRowIndex: number, valueInputMode: ValueInputOption): Promise { const data = await this.convertStructuredDataToArray(inputData, range, keyRowIndex); - return this.appendData(range, data); + return this.appendData(range, data, valueInputMode); } @@ -213,7 +216,7 @@ export class GoogleSheet { * @returns {Promise} * @memberof GoogleSheet */ - async updateSheetData(inputData: IDataObject[], indexKey: string, range: string, keyRowIndex: number, dataStartRowIndex: number): Promise { + async updateSheetData(inputData: IDataObject[], indexKey: string, range: string, keyRowIndex: number, dataStartRowIndex: number, valueInputMode: ValueInputOption, valueRenderMode: ValueRenderOption): Promise { // Get current data in Google Sheet let rangeStart: string, rangeEnd: string; let sheet: string | undefined = undefined; @@ -224,7 +227,7 @@ export class GoogleSheet { const keyRowRange = `${sheet ? sheet + '!' : ''}${rangeStart}${dataStartRowIndex}:${rangeEnd}${dataStartRowIndex}`; - const sheetDatakeyRow = await this.getData(keyRowRange); + const sheetDatakeyRow = await this.getData(keyRowRange, valueRenderMode); if (sheetDatakeyRow === undefined) { throw new Error('Could not retrieve the key row!'); @@ -242,7 +245,7 @@ export class GoogleSheet { let keyColumnRange = String.fromCharCode(characterCode); keyColumnRange = `${sheet ? sheet + '!' : ''}${keyColumnRange}:${keyColumnRange}`; - const sheetDataKeyColumn = await this.getData(keyColumnRange); + const sheetDataKeyColumn = await this.getData(keyColumnRange, valueRenderMode); if (sheetDataKeyColumn === undefined) { throw new Error('Could not retrieve the key column!'); @@ -312,7 +315,7 @@ export class GoogleSheet { } } - return this.batchUpdate(updateData); + return this.batchUpdate(updateData, valueInputMode); } @@ -386,7 +389,7 @@ export class GoogleSheet { getRange = `${sheet}!${getRange}`; } - const keyColumnData = await this.getData(getRange); + const keyColumnData = await this.getData(getRange, 'UNFORMATTED_VALUE'); if (keyColumnData === undefined) { throw new Error('Could not retrieve the column data!'); diff --git a/packages/nodes-base/nodes/GoogleSheets/GoogleSheets.node.ts b/packages/nodes-base/nodes/GoogleSheets/GoogleSheets.node.ts index fe08e0fb86..1ce289cfa2 100644 --- a/packages/nodes-base/nodes/GoogleSheets/GoogleSheets.node.ts +++ b/packages/nodes-base/nodes/GoogleSheets/GoogleSheets.node.ts @@ -11,6 +11,8 @@ import { IGoogleAuthCredentials, ILookupValues, ISheetUpdateData, + ValueInputOption, + ValueRenderOption, } from './GoogleSheet'; @@ -258,6 +260,110 @@ export class GoogleSheets implements INodeType { description: 'The name of the key to identify which
data should be updated in the sheet.', }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add Option', + default: {}, + options: [ + { + displayName: 'Value Input Mode', + name: 'valueInputMode', + type: 'options', + displayOptions: { + show: { + '/operation': [ + 'append', + 'update', + ], + }, + }, + options: [ + { + name: 'RAW', + value: 'RAW', + description: 'The values will not be parsed and will be stored as-is.', + }, + { + name: 'User Entered', + value: 'USER_ENTERED', + description: 'The values will be parsed as if the user typed them into the UI. Numbers will stay as numbers, but strings may be converted to numbers, dates, etc. following the same rules that are applied when entering text into a cell via the Google Sheets UI.' + }, + ], + default: 'RAW', + description: 'Determines how data should be interpreted.', + }, + { + displayName: 'Value Render Mode', + name: 'valueRenderMode', + type: 'options', + displayOptions: { + show: { + '/operation': [ + 'lookup', + 'read', + ], + }, + }, + options: [ + { + name: 'Formatted Value', + value: 'FORMATTED_VALUE', + description: 'Values will be calculated & formatted in the reply according to the cell\'s formatting.Formatting is based on the spreadsheet\'s locale, not the requesting user\'s locale.For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return "$1.23".', + }, + { + name: 'Formula', + value: 'FORMULA', + description: ' Values will not be calculated. The reply will include the formulas. For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return "=A1".', + }, + { + name: 'Unformatted Value', + value: 'UNFORMATTED_VALUE', + description: 'Values will be calculated, but not formatted in the reply. For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return the number 1.23.' + }, + ], + default: 'UNFORMATTED_VALUE', + description: 'Determines how values should be rendered in the output.', + }, + { + displayName: 'Value Render Mode', + name: 'valueRenderMode', + type: 'options', + displayOptions: { + show: { + '/operation': [ + 'update', + ], + '/rawData': [ + false + ], + }, + }, + options: [ + { + name: 'Formatted Value', + value: 'FORMATTED_VALUE', + description: 'Values will be calculated & formatted in the reply according to the cell\'s formatting.Formatting is based on the spreadsheet\'s locale, not the requesting user\'s locale.For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return "$1.23".', + }, + { + name: 'Formula', + value: 'FORMULA', + description: ' Values will not be calculated. The reply will include the formulas. For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return "=A1".', + }, + { + name: 'Unformatted Value', + value: 'UNFORMATTED_VALUE', + description: 'Values will be calculated, but not formatted in the reply. For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return the number 1.23.' + }, + ], + default: 'UNFORMATTED_VALUE', + description: 'Determines how values should be rendered in the output.', + }, + + ], + } + ], }; @@ -281,6 +387,10 @@ export class GoogleSheets implements INodeType { const operation = this.getNodeParameter('operation', 0) as string; + const options = this.getNodeParameter('options', 0, {}) as IDataObject; + + const valueInputMode = (options.valueInputMode || 'RAW') as ValueInputOption; + const valueRenderMode = (options.valueRenderMode || 'FORMATTED_VALUE') as ValueRenderOption; if (operation === 'append') { // ---------------------------------- @@ -296,7 +406,7 @@ export class GoogleSheets implements INodeType { }); // Convert data into array format - const data = await sheet.appendSheetData(setData, range, keyRow); + const data = await sheet.appendSheetData(setData, range, keyRow, valueInputMode); // TODO: Should add this data somewhere // TODO: Should have something like add metadata which does not get passed through @@ -307,7 +417,7 @@ export class GoogleSheets implements INodeType { // lookup // ---------------------------------- - const sheetData = await sheet.getData(range); + const sheetData = await sheet.getData(range, valueRenderMode); if (sheetData === undefined) { return []; @@ -336,7 +446,7 @@ export class GoogleSheets implements INodeType { const rawData = this.getNodeParameter('rawData', 0) as boolean; - const sheetData = await sheet.getData(range); + const sheetData = await sheet.getData(range, valueRenderMode); let returnData: IDataObject[]; if (!sheetData) { @@ -376,7 +486,7 @@ export class GoogleSheets implements INodeType { }); } - const data = await sheet.batchUpdate(updateData); + const data = await sheet.batchUpdate(updateData, valueInputMode); } else { const keyName = this.getNodeParameter('key', 0) as string; const keyRow = this.getNodeParameter('keyRow', 0) as number; @@ -387,7 +497,7 @@ export class GoogleSheets implements INodeType { setData.push(item.json); }); - const data = await sheet.updateSheetData(setData, keyName, range, keyRow, dataStartRow); + const data = await sheet.updateSheetData(setData, keyName, range, keyRow, dataStartRow, valueInputMode, valueRenderMode); } // TODO: Should add this data somewhere // TODO: Should have something like add metadata which does not get passed through