fix(Google Sheets Trigger Node): Filter by first data row on rowAdded event (#14731)

This commit is contained in:
RomanDavydchuk
2025-04-22 16:05:47 +03:00
committed by GitHub
parent 82b7be5d29
commit 1593fe3de5
2 changed files with 223 additions and 4 deletions

View File

@@ -534,13 +534,18 @@ export class GoogleSheetsTrigger implements INodeType {
);
if (Array.isArray(sheetData) && sheetData.length !== 0) {
const zeroBasedKeyRow = keyRow - 1;
sheetData.splice(zeroBasedKeyRow, 1); // Remove key row
sheetData.splice(0, 1); // Remove header row
}
let dataStartIndex = 0;
if (rangeDefinition === 'specifyRange' && keyRow < startIndex) {
dataStartIndex = startIndex - keyRow - 1;
}
if (this.getMode() === 'manual') {
if (Array.isArray(sheetData)) {
const returnData = arrayOfArraysToJson(sheetData, columns);
const sheetDataFromStartIndex = sheetData.slice(dataStartIndex);
const returnData = arrayOfArraysToJson(sheetDataFromStartIndex, columns);
if (Array.isArray(returnData) && returnData.length !== 0) {
return [this.helpers.returnJsonArray(returnData)];
@@ -554,7 +559,11 @@ export class GoogleSheetsTrigger implements INodeType {
return null;
}
const addedRows = sheetData?.slice(workflowStaticData.lastIndexChecked as number) || [];
const rowsStartIndex = Math.max(
workflowStaticData.lastIndexChecked as number,
dataStartIndex,
);
const addedRows = sheetData?.slice(rowsStartIndex) || [];
const returnData = arrayOfArraysToJson(addedRows, columns);
workflowStaticData.lastIndexChecked = sheetData.length;

View File

@@ -49,5 +49,215 @@ describe('GoogleSheetsTrigger', () => {
[{ json: { count: 14, name: 'apple' } }, { json: { count: 12, name: 'banana' } }],
]);
});
it('should return rows starting from first data row', async () => {
const scope = nock(baseUrl);
scope
.get('/v4/spreadsheets/testDocumentId')
.query({ fields: 'sheets.properties' })
.reply(200, {
sheets: [{ properties: { sheetId: 1, title: 'testSheetName' } }],
});
scope
.get((uri) => uri.startsWith('/v4/spreadsheets/testDocumentId/values/testSheetName!A5:ZZZ'))
.times(2)
.reply(200, {
values: [
['name', 'count'],
['apple', 14],
['banana', 12],
['orange', 10],
],
});
const { response } = await testPollingTriggerNode(GoogleSheetsTrigger, {
credential: mockDeep(),
mode: 'manual',
node: {
parameters: {
documentId: 'testDocumentId',
sheetName: 1,
event: 'rowAdded',
options: {
dataLocationOnSheet: {
values: {
rangeDefinition: 'specifyRange',
headerRow: 5,
firstDataRow: 7,
},
},
},
},
},
});
scope.done();
expect(response).toEqual([
[{ json: { count: 12, name: 'banana' } }, { json: { count: 10, name: 'orange' } }],
]);
});
it('should return rows starting from header row when first data row is less than header row', async () => {
const scope = nock(baseUrl);
scope
.get('/v4/spreadsheets/testDocumentId')
.query({ fields: 'sheets.properties' })
.reply(200, {
sheets: [{ properties: { sheetId: 1, title: 'testSheetName' } }],
});
scope
.get((uri) => uri.startsWith('/v4/spreadsheets/testDocumentId/values/testSheetName!A5:ZZZ'))
.times(2)
.reply(200, {
values: [
['name', 'count'],
['apple', 14],
['banana', 12],
['orange', 10],
],
});
const { response } = await testPollingTriggerNode(GoogleSheetsTrigger, {
credential: mockDeep(),
mode: 'manual',
node: {
parameters: {
documentId: 'testDocumentId',
sheetName: 1,
event: 'rowAdded',
options: {
dataLocationOnSheet: {
values: {
rangeDefinition: 'specifyRange',
headerRow: 5,
firstDataRow: 4,
},
},
},
},
},
});
scope.done();
expect(response).toEqual([
[
{ json: { count: 14, name: 'apple' } },
{ json: { count: 12, name: 'banana' } },
{ json: { count: 10, name: 'orange' } },
],
]);
});
it('should return rows starting from first data row in trigger mode', async () => {
const scope = nock(baseUrl);
scope
.get('/v4/spreadsheets/testDocumentId')
.query({ fields: 'sheets.properties' })
.reply(200, {
sheets: [{ properties: { sheetId: 1, title: 'testSheetName' } }],
});
scope
.get((uri) => uri.startsWith('/v4/spreadsheets/testDocumentId/values/testSheetName!A5:ZZZ'))
.times(2)
.reply(200, {
values: [
['name', 'count'],
['apple', 14],
['banana', 12],
['orange', 10],
],
});
const { response } = await testPollingTriggerNode(GoogleSheetsTrigger, {
credential: mockDeep(),
mode: 'trigger',
workflowStaticData: {
documentId: 'testDocumentId',
sheetId: 1,
lastIndexChecked: 0,
},
node: {
parameters: {
documentId: 'testDocumentId',
sheetName: 1,
event: 'rowAdded',
options: {
dataLocationOnSheet: {
values: {
rangeDefinition: 'specifyRange',
headerRow: 5,
firstDataRow: 7,
},
},
},
},
},
});
scope.done();
expect(response).toEqual([
[{ json: { count: 12, name: 'banana' } }, { json: { count: 10, name: 'orange' } }],
]);
});
it('should return rows starting from header row when first data row is less than header row in trigger mode', async () => {
const scope = nock(baseUrl);
scope
.get('/v4/spreadsheets/testDocumentId')
.query({ fields: 'sheets.properties' })
.reply(200, {
sheets: [{ properties: { sheetId: 1, title: 'testSheetName' } }],
});
scope
.get((uri) => uri.startsWith('/v4/spreadsheets/testDocumentId/values/testSheetName!A5:ZZZ'))
.times(2)
.reply(200, {
values: [
['name', 'count'],
['apple', 14],
['banana', 12],
['orange', 10],
],
});
const { response } = await testPollingTriggerNode(GoogleSheetsTrigger, {
credential: mockDeep(),
mode: 'trigger',
workflowStaticData: {
documentId: 'testDocumentId',
sheetId: 1,
lastIndexChecked: 0,
},
node: {
parameters: {
documentId: 'testDocumentId',
sheetName: 1,
event: 'rowAdded',
options: {
dataLocationOnSheet: {
values: {
rangeDefinition: 'specifyRange',
headerRow: 5,
firstDataRow: 4,
},
},
},
},
},
});
scope.done();
expect(response).toEqual([
[
{ json: { count: 14, name: 'apple' } },
{ json: { count: 12, name: 'banana' } },
{ json: { count: 10, name: 'orange' } },
],
]);
});
});
});