diff --git a/packages/nodes-base/nodes/Google/GoogleSheet.ts b/packages/nodes-base/nodes/Google/GoogleSheet.ts
index d2eb887b9..9a30c683a 100644
--- a/packages/nodes-base/nodes/Google/GoogleSheet.ts
+++ b/packages/nodes-base/nodes/Google/GoogleSheet.ts
@@ -1,5 +1,5 @@
import { IDataObject } from 'n8n-workflow';
-import { google } from 'googleapis';
+import { google, sheets_v4 } from 'googleapis';
import { JWT } from 'google-auth-library';
import { getAuthenticationClient } from './GoogleApi';
@@ -24,6 +24,18 @@ export interface ILookupValues {
lookupValue: string;
}
+export interface IToDeleteRange {
+ amount: number;
+ startIndex: number;
+ sheetId: number;
+}
+
+export interface IToDelete {
+ [key: string]: IToDeleteRange[] | undefined;
+ columns?: IToDeleteRange[];
+ rows?: IToDeleteRange[];
+}
+
export type ValueInputOption = 'RAW' | 'USER_ENTERED';
export type ValueRenderOption = 'FORMATTED_VALUE' | 'FORMULA' | 'UNFORMATTED_VALUE';
@@ -85,6 +97,44 @@ export class GoogleSheet {
}
+ /**
+ * Returns the sheets in a Spreadsheet
+ */
+ async spreadsheetGetSheets() {
+ const client = await this.getAuthenticationClient();
+
+ const response = await Sheets.spreadsheets.get(
+ {
+ auth: client,
+ spreadsheetId: this.id,
+ fields: 'sheets.properties'
+ }
+ );
+
+ return response.data;
+ }
+
+
+ /**
+ * Sets values in one or more ranges of a spreadsheet.
+ */
+ async spreadsheetBatchUpdate(requests: sheets_v4.Schema$Request[]) { // tslint:disable-line:no-any
+ const client = await this.getAuthenticationClient();
+
+ const response = await Sheets.spreadsheets.batchUpdate(
+ {
+ auth: client,
+ spreadsheetId: this.id,
+ requestBody: {
+ requests,
+ },
+ }
+ );
+
+ return response.data;
+ }
+
+
/**
* Sets the cell values
*/
diff --git a/packages/nodes-base/nodes/Google/GoogleSheets.node.ts b/packages/nodes-base/nodes/Google/GoogleSheets.node.ts
index be80ae375..36f59a267 100644
--- a/packages/nodes-base/nodes/Google/GoogleSheets.node.ts
+++ b/packages/nodes-base/nodes/Google/GoogleSheets.node.ts
@@ -1,7 +1,11 @@
+import { sheets_v4 } from 'googleapis';
+
import { IExecuteFunctions } from 'n8n-core';
import {
IDataObject,
+ ILoadOptionsFunctions,
INodeExecutionData,
+ INodePropertyOptions,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
@@ -11,6 +15,7 @@ import {
IGoogleAuthCredentials,
ILookupValues,
ISheetUpdateData,
+ IToDelete,
ValueInputOption,
ValueRenderOption,
} from './GoogleSheet';
@@ -52,6 +57,11 @@ export class GoogleSheets implements INodeType {
value: 'clear',
description: 'Clears data from a Sheet',
},
+ {
+ name: 'Delete',
+ value: 'delete',
+ description: 'Delete columns and rows from a Sheet',
+ },
{
name: 'Lookup',
value: 'lookup',
@@ -87,11 +97,120 @@ export class GoogleSheets implements INodeType {
displayName: 'Range',
name: 'range',
type: 'string',
+ displayOptions: {
+ hide: {
+ operation: [
+ 'delete'
+ ],
+ },
+ },
default: 'A:F',
required: true,
description: 'The table range to read from or to append data to. See the Google documentation for the details.
If it contains multiple sheets it can also be
added like this: "MySheet!A:F"',
},
+
+ // ----------------------------------
+ // Delete
+ // ----------------------------------
+ {
+ displayName: 'To Delete',
+ name: 'toDelete',
+ placeholder: 'Add Columns/Rows to delete',
+ description: 'Deletes colums and rows from a sheet.',
+ type: 'fixedCollection',
+ typeOptions: {
+ multipleValues: true,
+ },
+ displayOptions: {
+ show: {
+ operation: [
+ 'delete'
+ ],
+ },
+ },
+ default: {},
+ options: [
+ {
+ displayName: 'Columns',
+ name: 'columns',
+ values: [
+ {
+ displayName: 'Sheet',
+ name: 'sheetId',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getSheets',
+ },
+ options: [],
+ default: '',
+ required: true,
+ description: 'The sheet to delete columns from',
+ },
+ {
+ displayName: 'Start Index',
+ name: 'startIndex',
+ type: 'number',
+ typeOptions: {
+ minValue: 0,
+ },
+ default: 0,
+ description: 'The start index (0 based and inclusive) of column to delete.',
+ },
+ {
+ displayName: 'Amount',
+ name: 'amount',
+ type: 'number',
+ typeOptions: {
+ minValue: 1,
+ },
+ default: 1,
+ description: 'Number of columns to delete.',
+ },
+ ]
+ },
+ {
+ displayName: 'Rows',
+ name: 'rows',
+ values: [
+ {
+ displayName: 'Sheet',
+ name: 'sheetId',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getSheets',
+ },
+ options: [],
+ default: '',
+ required: true,
+ description: 'The sheet to delete columns from',
+ },
+ {
+ displayName: 'Start Index',
+ name: 'startIndex',
+ type: 'number',
+ typeOptions: {
+ minValue: 0,
+ },
+ default: 0,
+ description: 'The start index (0 based and inclusive) of row to delete.',
+ },
+ {
+ displayName: 'Amount',
+ name: 'amount',
+ type: 'number',
+ typeOptions: {
+ minValue: 1,
+ },
+ default: 1,
+ description: 'Number of rows to delete.',
+ },
+ ]
+ },
+ ],
+ },
+
+
// ----------------------------------
// Read
// ----------------------------------
@@ -178,6 +297,7 @@ export class GoogleSheets implements INodeType {
operation: [
'append',
'clear',
+ 'delete',
],
rawData: [
true
@@ -201,6 +321,7 @@ export class GoogleSheets implements INodeType {
hide: {
operation: [
'clear',
+ 'delete',
],
rawData: [
true
@@ -401,6 +522,48 @@ export class GoogleSheets implements INodeType {
};
+ methods = {
+ loadOptions: {
+ // Get all the sheets in a Spreadsheet
+ async getSheets(this: ILoadOptionsFunctions): Promise {
+ const spreadsheetId = this.getCurrentNodeParameter('sheetId') as string;
+
+ const credentials = this.getCredentials('googleApi');
+
+ if (credentials === undefined) {
+ throw new Error('No credentials got returned!');
+ }
+
+ const googleCredentials = {
+ email: credentials.email,
+ privateKey: credentials.privateKey,
+ } as IGoogleAuthCredentials;
+
+ const sheet = new GoogleSheet(spreadsheetId, googleCredentials);
+ const responseData = await sheet.spreadsheetGetSheets();
+
+ if (responseData === undefined) {
+ throw new Error('No data got returned');
+ }
+
+ const returnData: INodePropertyOptions[] = [];
+ for (const sheet of responseData.sheets!) {
+ if (sheet.properties!.sheetType !== 'GRID') {
+ continue;
+ }
+
+ returnData.push({
+ name: sheet.properties!.title as string,
+ value: sheet.properties!.sheetId as unknown as string,
+ });
+ }
+
+ return returnData;
+ },
+ },
+ };
+
+
async execute(this: IExecuteFunctions): Promise {
const spreadsheetId = this.getNodeParameter('sheetId', 0) as string;
const credentials = this.getCredentials('googleApi');
@@ -416,10 +579,13 @@ export class GoogleSheets implements INodeType {
const sheet = new GoogleSheet(spreadsheetId, googleCredentials);
- const range = this.getNodeParameter('range', 0) as string;
-
const operation = this.getNodeParameter('operation', 0) as string;
+ let range = '';
+ if (operation !== 'delete') {
+ range = this.getNodeParameter('range', 0) as string;
+ }
+
const options = this.getNodeParameter('options', 0, {}) as IDataObject;
const valueInputMode = (options.valueInputMode || 'RAW') as ValueInputOption;
@@ -452,6 +618,41 @@ export class GoogleSheets implements INodeType {
await sheet.clearData(range);
+ const items = this.getInputData();
+ return this.prepareOutputData(items);
+ } else if (operation === 'delete') {
+ // ----------------------------------
+ // delete
+ // ----------------------------------
+
+ const requests: sheets_v4.Schema$Request[] = [];
+
+ const toDelete = this.getNodeParameter('toDelete', 0) as IToDelete;
+
+ const deletePropertyToDimensions: IDataObject = {
+ 'columns': 'COLUMNS',
+ 'rows': 'ROWS',
+ };
+
+ for (const propertyName of Object.keys(deletePropertyToDimensions)) {
+ if (toDelete[propertyName] !== undefined) {
+ toDelete[propertyName]!.forEach(range => {
+ requests.push({
+ deleteDimension: {
+ range: {
+ sheetId: range.sheetId,
+ dimension: deletePropertyToDimensions[propertyName] as string,
+ startIndex: range.startIndex,
+ endIndex: range.startIndex + range.amount,
+ }
+ }
+ });
+ });
+ }
+ }
+
+ const data = await sheet.spreadsheetBatchUpdate(requests);
+
const items = this.getInputData();
return this.prepareOutputData(items);
} else if (operation === 'lookup') {