Skip to content

Commit

Permalink
fix(Google Sheets Node): Append fails if cells have some default valu…
Browse files Browse the repository at this point in the history
…es added by data validation rules (#9950)
  • Loading branch information
michael-radency authored Jul 5, 2024
1 parent b910ed6 commit d1821eb
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 161 deletions.
28 changes: 14 additions & 14 deletions packages/nodes-base/nodes/Google/Sheet/test/v2/utils/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,11 +304,11 @@ describe('Test Google Sheets, lookupValues', () => {

const googleSheet = new GoogleSheet('spreadsheetId', fakeExecuteFunction);

const result = await googleSheet.lookupValues(
const result = await googleSheet.lookupValues({
inputData,
0,
1,
[
keyRowIndex: 0,
dataStartRowIndex: 1,
lookupValues: [
{
lookupColumn: 'num',
lookupValue: '1',
Expand All @@ -318,9 +318,9 @@ describe('Test Google Sheets, lookupValues', () => {
lookupValue: 'foo',
},
],
true,
'OR',
);
returnAllMatches: true,
combineFilters: 'OR',
});

expect(result).toBeDefined();
expect(result).toEqual([
Expand Down Expand Up @@ -366,11 +366,11 @@ describe('Test Google Sheets, lookupValues', () => {

const googleSheet = new GoogleSheet('spreadsheetId', fakeExecuteFunction);

const result = await googleSheet.lookupValues(
const result = await googleSheet.lookupValues({
inputData,
0,
1,
[
keyRowIndex: 0,
dataStartRowIndex: 1,
lookupValues: [
{
lookupColumn: 'num',
lookupValue: '1',
Expand All @@ -380,9 +380,9 @@ describe('Test Google Sheets, lookupValues', () => {
lookupValue: 'baz',
},
],
true,
'AND',
);
returnAllMatches: true,
combineFilters: 'AND',
});

expect(result).toBeDefined();
expect(result).toEqual([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ export const description: SheetProperties = [
export async function execute(
this: IExecuteFunctions,
sheet: GoogleSheet,
sheetName: string,
range: string,
sheetId: string,
): Promise<INodeExecutionData[]> {
const items = this.getInputData();
Expand All @@ -228,57 +228,62 @@ export async function execute(
const options = this.getNodeParameter('options', 0, {});
const locationDefine = (options.locationDefine as IDataObject)?.values as IDataObject;

let headerRow = 1;
let keyRowIndex = 1;
if (locationDefine?.headerRow) {
headerRow = locationDefine.headerRow as number;
keyRowIndex = locationDefine.headerRow as number;
}

const sheetData = await sheet.getData(range, 'FORMATTED_VALUE');

if (nodeVersion >= 4.4 && dataMode !== 'autoMapInputData') {
//not possible to refresh columns when mode is autoMapInputData
const sheetData = await sheet.getData(sheetName, 'FORMATTED_VALUE');

if (sheetData?.[headerRow - 1] === undefined) {
if (sheetData?.[keyRowIndex - 1] === undefined) {
throw new NodeOperationError(
this.getNode(),
`Could not retrieve the column names from row ${headerRow}`,
`Could not retrieve the column names from row ${keyRowIndex}`,
);
}

const schema = this.getNodeParameter('columns.schema', 0) as ResourceMapperField[];
checkForSchemaChanges(this.getNode(), sheetData[headerRow - 1], schema);
checkForSchemaChanges(this.getNode(), sheetData[keyRowIndex - 1], schema);
}

let setData: IDataObject[] = [];
let inputData: IDataObject[] = [];

if (dataMode === 'autoMapInputData') {
setData = await autoMapInputData.call(this, sheetName, sheet, items, options);
inputData = await autoMapInputData.call(this, range, sheet, items, options);
} else {
setData = mapFields.call(this, items.length);
inputData = mapFields.call(this, items.length);
}

if (setData.length === 0) {
if (inputData.length === 0) {
return [];
} else if (options.useAppend) {
await sheet.appendSheetData(
setData,
sheetName,
headerRow,
(options.cellFormat as ValueInputOption) || cellFormatDefault(nodeVersion),
false,
undefined,
undefined,
options.useAppend as boolean,
);
}

const valueInputMode = (options.cellFormat as ValueInputOption) || cellFormatDefault(nodeVersion);
const useAppend = options.useAppend as boolean;

if (options.useAppend) {
await sheet.appendSheetData({
inputData,
range,
keyRowIndex,
valueInputMode,
useAppend,
});
} else {
//if no trailing empty row exists in the sheet update operation will fail
await sheet.appendEmptyRowsOrColumns(sheetId, 1, 0);

await sheet.appendSheetData(
setData,
sheetName,
headerRow,
(options.cellFormat as ValueInputOption) || cellFormatDefault(nodeVersion),
false,
);
const lastRow = (sheetData ?? []).length + 1;

await sheet.appendSheetData({
inputData,
range,
keyRowIndex,
valueInputMode,
lastRow,
});
}

if (nodeVersion < 4 || dataMode === 'autoMapInputData') {
Expand All @@ -288,7 +293,7 @@ export async function execute(
});
} else {
const returnData: INodeExecutionData[] = [];
for (const [index, entry] of setData.entries()) {
for (const [index, entry] of inputData.entries()) {
returnData.push({
json: entry,
pairedItem: { item: index },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,15 +246,15 @@ export async function execute(

const locationDefineOption = (options.locationDefine as IDataObject)?.values as IDataObject;

let headerRow = 0;
let firstDataRow = 1;
let keyRowIndex = 0;
let dataStartRowIndex = 1;

if (locationDefineOption) {
if (locationDefineOption.headerRow) {
headerRow = parseInt(locationDefineOption.headerRow as string, 10) - 1;
keyRowIndex = parseInt(locationDefineOption.headerRow as string, 10) - 1;
}
if (locationDefineOption.firstDataRow) {
firstDataRow = parseInt(locationDefineOption.firstDataRow as string, 10) - 1;
dataStartRowIndex = parseInt(locationDefineOption.firstDataRow as string, 10) - 1;
}
}

Expand All @@ -267,14 +267,14 @@ export async function execute(

const sheetData = (await sheet.getData(sheetName, 'FORMATTED_VALUE')) ?? [];

if (!sheetData[headerRow] && dataMode !== 'autoMapInputData') {
if (!sheetData[keyRowIndex] && dataMode !== 'autoMapInputData') {
throw new NodeOperationError(
this.getNode(),
`Could not retrieve the column names from row ${headerRow + 1}`,
`Could not retrieve the column names from row ${keyRowIndex + 1}`,
);
}

columnNames = sheetData[headerRow] ?? [];
columnNames = sheetData[keyRowIndex] ?? [];

if (nodeVersion >= 4.4) {
const schema = this.getNodeParameter('columns.schema', 0) as ResourceMapperField[];
Expand All @@ -291,13 +291,13 @@ export async function execute(
// TODO: Add support for multiple columns to match on in the next overhaul
const keyIndex = columnNames.indexOf(columnsToMatchOn[0]);

const columnValues = await sheet.getColumnValues(
const columnValuesList = await sheet.getColumnValues({
range,
keyIndex,
firstDataRow,
dataStartRowIndex,
valueRenderMode,
sheetData,
);
});

const updateData: ISheetUpdateData[] = [];
const appendData: IDataObject[] = [];
Expand All @@ -321,20 +321,20 @@ export async function execute(
for (let i = 0; i < items.length; i++) {
if (dataMode === 'nothing') continue;

const data: IDataObject[] = [];
const inputData: IDataObject[] = [];

if (dataMode === 'autoMapInputData') {
const handlingExtraDataOption = (options.handlingExtraData as string) || 'insertInNewColumn';
if (handlingExtraDataOption === 'ignoreIt') {
data.push(items[i].json);
inputData.push(items[i].json);
}
if (handlingExtraDataOption === 'error') {
Object.keys(items[i].json).forEach((key) => errorOnUnexpectedColumn(key, i));
data.push(items[i].json);
inputData.push(items[i].json);
}
if (handlingExtraDataOption === 'insertInNewColumn') {
Object.keys(items[i].json).forEach(addNewColumn);
data.push(items[i].json);
inputData.push(items[i].json);
}
} else {
const valueToMatchOn =
Expand Down Expand Up @@ -364,7 +364,7 @@ export async function execute(
return acc;
}, {} as IDataObject);
fields[columnsToMatchOn[0]] = valueToMatchOn;
data.push(fields);
inputData.push(fields);
} else {
const mappingValues = this.getNodeParameter('columns.value', i) as IDataObject;
if (Object.keys(mappingValues).length === 0) {
Expand All @@ -379,7 +379,7 @@ export async function execute(
mappingValues[key] = '';
}
});
data.push(mappingValues);
inputData.push(mappingValues);
mappedValues.push(mappingValues);
}
}
Expand All @@ -390,56 +390,60 @@ export async function execute(
sheetName,
[newColumnNames],
(options.cellFormat as ValueInputOption) || cellFormatDefault(nodeVersion),
headerRow + 1,
keyRowIndex + 1,
);
columnNames = newColumnNames;
sheetData[headerRow] = newColumnNames;
sheetData[keyRowIndex] = newColumnNames;
newColumns.clear();
}

const preparedData = await sheet.prepareDataForUpdateOrUpsert(
data,
columnsToMatchOn[0],
const indexKey = columnsToMatchOn[0];

const preparedData = await sheet.prepareDataForUpdateOrUpsert({
inputData,
indexKey,
range,
headerRow,
firstDataRow,
keyRowIndex,
dataStartRowIndex,
valueRenderMode,
true,
[columnNames.concat([...newColumns])],
columnValues,
);
upsert: true,
columnNamesList: [columnNames.concat([...newColumns])],
columnValuesList,
});

updateData.push(...preparedData.updateData);
appendData.push(...preparedData.appendData);
}

const columnNamesList = [columnNames.concat([...newColumns])];

if (updateData.length) {
await sheet.batchUpdate(updateData, valueInputMode);
}
if (appendData.length) {
const lastRow = sheetData.length + 1;
const useAppend = options.useAppend as boolean;

if (options.useAppend) {
await sheet.appendSheetData(
appendData,
await sheet.appendSheetData({
inputData: appendData,
range,
headerRow + 1,
keyRowIndex: keyRowIndex + 1,
valueInputMode,
false,
[columnNames.concat([...newColumns])],
columnNamesList,
lastRow,
options.useAppend as boolean,
);
useAppend,
});
} else {
await sheet.appendEmptyRowsOrColumns(sheetId, 1, 0);
await sheet.appendSheetData(
appendData,
await sheet.appendSheetData({
inputData: appendData,
range,
headerRow + 1,
keyRowIndex: keyRowIndex + 1,
valueInputMode,
false,
[columnNames.concat([...newColumns])],
columnNamesList,
lastRow,
);
});
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,11 @@ export async function execute(
return [];
}

const { data, headerRow, firstDataRow } = prepareSheetData(
sheetData,
dataLocationOnSheetOptions,
);
const {
data,
headerRow: keyRowIndex,
firstDataRow: dataStartRowIndex,
} = prepareSheetData(sheetData, dataLocationOnSheetOptions);

let responseData = [];

Expand All @@ -215,6 +216,8 @@ export async function execute(
[],
) as ILookupValues[];

const inputData = data as string[][];

if (lookupValues.length) {
const returnAllMatches = options.returnAllMatches === 'returnAllMatches' ? true : false;

Expand All @@ -235,16 +238,16 @@ export async function execute(
| 'AND'
| 'OR';

responseData = await sheet.lookupValues(
data as string[][],
headerRow,
firstDataRow,
responseData = await sheet.lookupValues({
inputData,
keyRowIndex,
dataStartRowIndex,
lookupValues,
returnAllMatches,
combineFilters,
);
});
} else {
responseData = sheet.structureArrayDataByColumn(data as string[][], headerRow, firstDataRow);
responseData = sheet.structureArrayDataByColumn(inputData, keyRowIndex, dataStartRowIndex);
}

returnData.push(
Expand Down
Loading

0 comments on commit d1821eb

Please sign in to comment.