Skip to content

Commit

Permalink
fix(Google Sheets Node): Fix for append operation if no empty rows in…
Browse files Browse the repository at this point in the history
… sheet
  • Loading branch information
michael-radency authored Dec 1, 2022
1 parent 6d4e959 commit 741c7da
Show file tree
Hide file tree
Showing 8 changed files with 200 additions and 160 deletions.
30 changes: 22 additions & 8 deletions packages/nodes-base/nodes/Google/Sheet/v2/actions/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ export async function router(this: IExecuteFunctions): Promise<INodeExecutionDat

const googleSheet = new GoogleSheet(spreadsheetId, this);

let sheetWithinDocument = '';
let sheetId = '';
if (operation !== 'create') {
sheetWithinDocument = this.getNodeParameter('sheetName', 0, undefined, {
sheetId = this.getNodeParameter('sheetName', 0, undefined, {
extractValue: true,
}) as string;
}

if (sheetWithinDocument === 'gid=0') {
sheetWithinDocument = '0';
if (sheetId === 'gid=0') {
sheetId = '0';
}

let sheetName = '';
Expand All @@ -41,17 +41,22 @@ export async function router(this: IExecuteFunctions): Promise<INodeExecutionDat
sheetName = spreadsheetId;
break;
case 'delete':
sheetName = sheetWithinDocument;
sheetName = sheetId;
break;
case 'remove':
sheetName = `${spreadsheetId}||${sheetWithinDocument}`;
sheetName = `${spreadsheetId}||${sheetId}`;
break;
default:
sheetName = await googleSheet.spreadsheetGetSheetNameById(sheetWithinDocument);
sheetName = await googleSheet.spreadsheetGetSheetNameById(sheetId);
}

operationResult.push(
...(await sheet[googleSheets.operation].execute.call(this, googleSheet, sheetName)),
...(await sheet[googleSheets.operation].execute.call(
this,
googleSheet,
sheetName,
sheetId,
)),
);
} else if (googleSheets.resource === 'spreadsheet') {
operationResult.push(...(await spreadsheet[googleSheets.operation].execute.call(this)));
Expand All @@ -60,6 +65,15 @@ export async function router(this: IExecuteFunctions): Promise<INodeExecutionDat
if (this.continueOnFail()) {
operationResult.push({ json: this.getInputData(0)[0].json, error: err });
} else {
if (
err.message &&
(err.message.toLowerCase().includes('bad request') ||
err.message.toLowerCase().includes('uknown error')) &&
err.description
) {
err.message = err.description;
err.description = undefined;
}
throw err;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ export async function execute(
this: IExecuteFunctions,
sheet: GoogleSheet,
sheetName: string,
sheetId: string,
): Promise<INodeExecutionData[]> {
const items = this.getInputData();
const dataMode = this.getNodeParameter('dataMode', 0) as string;
Expand All @@ -176,6 +177,12 @@ export async function execute(
setData = mapFields.call(this, items.length);
}

if (setData.length === 0) {
return [];
} else {
await sheet.appendEmptyRowsOrColumns(sheetId, 1, 0);
}

await sheet.appendSheetData(
setData,
sheetName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ export async function execute(
this: IExecuteFunctions,
sheet: GoogleSheet,
sheetName: string,
sheetId: string,
): Promise<INodeExecutionData[]> {
const items = this.getInputData();
const valueInputMode = this.getNodeParameter('options.cellFormat', 0, 'RAW') as ValueInputOption;
Expand Down Expand Up @@ -248,23 +249,22 @@ export async function execute(
} else {
const valueToMatchOn = this.getNodeParameter('valueToMatchOn', i) as string;

const fields = (this.getNodeParameter('fieldsUi.values', i, {}) as IDataObject[]).reduce(
(acc, entry) => {
if (entry.column === 'newColumn') {
const columnName = entry.columnName as string;
const fields = (
(this.getNodeParameter('fieldsUi.values', i, {}) as IDataObject[]) || []
).reduce((acc, entry) => {
if (entry.column === 'newColumn') {
const columnName = entry.columnName as string;

if (columnNames.includes(columnName) === false) {
newColumns.add(columnName);
}

acc[columnName] = entry.fieldValue as string;
} else {
acc[entry.column as string] = entry.fieldValue as string;
if (columnNames.includes(columnName) === false) {
newColumns.add(columnName);
}
return acc;
},
{} as IDataObject,
);

acc[columnName] = entry.fieldValue as string;
} else {
acc[entry.column as string] = entry.fieldValue as string;
}
return acc;
}, {} as IDataObject);

fields[columnToMatchOn] = valueToMatchOn;

Expand Down Expand Up @@ -300,6 +300,7 @@ export async function execute(
await sheet.batchUpdate(updateData, valueInputMode);
}
if (appendData.length) {
await sheet.appendEmptyRowsOrColumns(sheetId, 1, 0);
const lastRow = sheetData.length + 1;
await sheet.appendSheetData(
appendData,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,23 +247,22 @@ export async function execute(
} else {
const valueToMatchOn = this.getNodeParameter('valueToMatchOn', i) as string;

const fields = (this.getNodeParameter('fieldsUi.values', i, {}) as IDataObject[]).reduce(
(acc, entry) => {
if (entry.column === 'newColumn') {
const columnName = entry.columnName as string;
const fields = (
(this.getNodeParameter('fieldsUi.values', i, {}) as IDataObject[]) || []
).reduce((acc, entry) => {
if (entry.column === 'newColumn') {
const columnName = entry.columnName as string;

if (columnNames.includes(columnName) === false) {
newColumns.add(columnName);
}

acc[columnName] = entry.fieldValue as string;
} else {
acc[entry.column as string] = entry.fieldValue as string;
if (columnNames.includes(columnName) === false) {
newColumns.add(columnName);
}
return acc;
},
{} as IDataObject,
);

acc[columnName] = entry.fieldValue as string;
} else {
acc[entry.column as string] = entry.fieldValue as string;
}
return acc;
}, {} as IDataObject);

fields[columnToMatchOn] = valueToMatchOn;

Expand Down
37 changes: 37 additions & 0 deletions packages/nodes-base/nodes/Google/Sheet/v2/helpers/GoogleSheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,43 @@ export class GoogleSheet {
return response;
}

async appendEmptyRowsOrColumns(sheetId: string, rowsToAdd = 1, columnsToAdd = 1) {
const requests: IDataObject[] = [];

if (rowsToAdd > 0) {
requests.push({
appendDimension: {
sheetId,
dimension: 'ROWS',
length: rowsToAdd,
},
});
}

if (columnsToAdd > 0) {
requests.push({
appendDimension: {
sheetId,
dimension: 'COLUMNS',
length: columnsToAdd,
},
});
}

if (requests.length === 0) {
throw new Error('Must specify at least one column or row to add');
}

const response = await apiRequest.call(
this.executeFunctions,
'POST',
`/v4/spreadsheets/${this.id}:batchUpdate`,
{ requests },
);

return response;
}

/**
* Appends the cell values
*/
Expand Down
128 changes: 60 additions & 68 deletions packages/nodes-base/nodes/Google/Sheet/v2/methods/listSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,91 +6,83 @@ import {
NodeOperationError,
} from 'n8n-workflow';
import { ResourceLocator } from '../helpers/GoogleSheets.types';
import { getSpreadsheetId, sortLoadOptions } from '../helpers/GoogleSheets.utils';
import { apiRequest, apiRequestAllItems } from '../transport';
import { getSpreadsheetId } from '../helpers/GoogleSheets.utils';
import { apiRequest } from '../transport';

export async function spreadSheetsSearch(
this: ILoadOptionsFunctions,
filter?: string,
paginationToken?: string,
): Promise<INodeListSearchResult> {
try {
const returnData: INodeListSearchItems[] = [];
const query: string[] = [];
if (filter) {
query.push(`name contains '${filter.replace("'", "\\'")}'`);
}
query.push("mimeType = 'application/vnd.google-apps.spreadsheet'");
const qs = {
pageSize: 50,
orderBy: 'modifiedTime desc',
fields: 'nextPageToken, files(id, name, webViewLink)',
q: query.join(' and '),
includeItemsFromAllDrives: true,
supportsAllDrives: true,
};

const sheets = await apiRequestAllItems.call(
this,
'files',
'GET',
'',
{},
qs,
'https://www.googleapis.com/drive/v3/files',
);
for (const sheet of sheets) {
returnData.push({
name: sheet.name as string,
value: sheet.id as string,
url: sheet.webViewLink as string,
});
}
return { results: sortLoadOptions(returnData) };
} catch (error) {
return { results: [] };
const query: string[] = [];
if (filter) {
query.push(`name contains '${filter.replace("'", "\\'")}'`);
}
query.push("mimeType = 'application/vnd.google-apps.spreadsheet'");

const qs = {
q: query.join(' and '),
pageToken: (paginationToken as string) || undefined,
fields: 'nextPageToken, files(id, name, webViewLink)',
orderBy: 'name_natural',
includeItemsFromAllDrives: true,
supportsAllDrives: true,
};

const res = await apiRequest.call(
this,
'GET',
'',
{},
qs,
'https://www.googleapis.com/drive/v3/files',
);
return {
results: res.files.map((sheet: IDataObject) => ({
name: sheet.name as string,
value: sheet.id as string,
url: sheet.webViewLink as string,
})),
paginationToken: res.nextPageToken,
};
}

export async function sheetsSearch(
this: ILoadOptionsFunctions,
_filter?: string,
): Promise<INodeListSearchResult> {
try {
const { mode, value } = this.getNodeParameter('documentId', 0) as IDataObject;
const spreadsheetId = getSpreadsheetId(mode as ResourceLocator, value as string);
const { mode, value } = this.getNodeParameter('documentId', 0) as IDataObject;
const spreadsheetId = getSpreadsheetId(mode as ResourceLocator, value as string);

const query = {
fields: 'sheets.properties',
};
const query = {
fields: 'sheets.properties',
};

const responseData = await apiRequest.call(
this,
'GET',
`/v4/spreadsheets/${spreadsheetId}`,
{},
query,
);
const responseData = await apiRequest.call(
this,
'GET',
`/v4/spreadsheets/${spreadsheetId}`,
{},
query,
);

if (responseData === undefined) {
throw new NodeOperationError(this.getNode(), 'No data got returned');
}

const returnData: INodeListSearchItems[] = [];
for (const sheet of responseData.sheets!) {
if (sheet.properties!.sheetType !== 'GRID') {
continue;
}
if (responseData === undefined) {
throw new NodeOperationError(this.getNode(), 'No data got returned');
}

returnData.push({
name: sheet.properties!.title as string,
value: (sheet.properties!.sheetId as number) || 'gid=0',
//prettier-ignore
url: `https://docs.google.com/spreadsheets/d/${spreadsheetId}/edit#gid=${sheet.properties!.sheetId}`,
});
const returnData: INodeListSearchItems[] = [];
for (const sheet of responseData.sheets!) {
if (sheet.properties!.sheetType !== 'GRID') {
continue;
}

return { results: returnData };
} catch (error) {
return { results: [] };
returnData.push({
name: sheet.properties!.title as string,
value: (sheet.properties!.sheetId as number) || 'gid=0',
//prettier-ignore
url: `https://docs.google.com/spreadsheets/d/${spreadsheetId}/edit#gid=${sheet.properties!.sheetId}`,
});
}

return { results: returnData };
}
Loading

0 comments on commit 741c7da

Please sign in to comment.