Skip to content

Commit 1593fe3

Browse files
fix(Google Sheets Trigger Node): Filter by first data row on rowAdded event (#14731)
1 parent 82b7be5 commit 1593fe3

File tree

2 files changed

+223
-4
lines changed

2 files changed

+223
-4
lines changed

packages/nodes-base/nodes/Google/Sheet/GoogleSheetsTrigger.node.ts

+13-4
Original file line numberDiff line numberDiff line change
@@ -534,13 +534,18 @@ export class GoogleSheetsTrigger implements INodeType {
534534
);
535535

536536
if (Array.isArray(sheetData) && sheetData.length !== 0) {
537-
const zeroBasedKeyRow = keyRow - 1;
538-
sheetData.splice(zeroBasedKeyRow, 1); // Remove key row
537+
sheetData.splice(0, 1); // Remove header row
538+
}
539+
540+
let dataStartIndex = 0;
541+
if (rangeDefinition === 'specifyRange' && keyRow < startIndex) {
542+
dataStartIndex = startIndex - keyRow - 1;
539543
}
540544

541545
if (this.getMode() === 'manual') {
542546
if (Array.isArray(sheetData)) {
543-
const returnData = arrayOfArraysToJson(sheetData, columns);
547+
const sheetDataFromStartIndex = sheetData.slice(dataStartIndex);
548+
const returnData = arrayOfArraysToJson(sheetDataFromStartIndex, columns);
544549

545550
if (Array.isArray(returnData) && returnData.length !== 0) {
546551
return [this.helpers.returnJsonArray(returnData)];
@@ -554,7 +559,11 @@ export class GoogleSheetsTrigger implements INodeType {
554559
return null;
555560
}
556561

557-
const addedRows = sheetData?.slice(workflowStaticData.lastIndexChecked as number) || [];
562+
const rowsStartIndex = Math.max(
563+
workflowStaticData.lastIndexChecked as number,
564+
dataStartIndex,
565+
);
566+
const addedRows = sheetData?.slice(rowsStartIndex) || [];
558567
const returnData = arrayOfArraysToJson(addedRows, columns);
559568

560569
workflowStaticData.lastIndexChecked = sheetData.length;

packages/nodes-base/nodes/Google/Sheet/test/GoogleSheetsTrigger.test.ts

+210
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,215 @@ describe('GoogleSheetsTrigger', () => {
4949
[{ json: { count: 14, name: 'apple' } }, { json: { count: 12, name: 'banana' } }],
5050
]);
5151
});
52+
53+
it('should return rows starting from first data row', async () => {
54+
const scope = nock(baseUrl);
55+
scope
56+
.get('/v4/spreadsheets/testDocumentId')
57+
.query({ fields: 'sheets.properties' })
58+
.reply(200, {
59+
sheets: [{ properties: { sheetId: 1, title: 'testSheetName' } }],
60+
});
61+
scope
62+
.get((uri) => uri.startsWith('/v4/spreadsheets/testDocumentId/values/testSheetName!A5:ZZZ'))
63+
.times(2)
64+
.reply(200, {
65+
values: [
66+
['name', 'count'],
67+
['apple', 14],
68+
['banana', 12],
69+
['orange', 10],
70+
],
71+
});
72+
73+
const { response } = await testPollingTriggerNode(GoogleSheetsTrigger, {
74+
credential: mockDeep(),
75+
mode: 'manual',
76+
node: {
77+
parameters: {
78+
documentId: 'testDocumentId',
79+
sheetName: 1,
80+
event: 'rowAdded',
81+
options: {
82+
dataLocationOnSheet: {
83+
values: {
84+
rangeDefinition: 'specifyRange',
85+
headerRow: 5,
86+
firstDataRow: 7,
87+
},
88+
},
89+
},
90+
},
91+
},
92+
});
93+
94+
scope.done();
95+
96+
expect(response).toEqual([
97+
[{ json: { count: 12, name: 'banana' } }, { json: { count: 10, name: 'orange' } }],
98+
]);
99+
});
100+
101+
it('should return rows starting from header row when first data row is less than header row', async () => {
102+
const scope = nock(baseUrl);
103+
scope
104+
.get('/v4/spreadsheets/testDocumentId')
105+
.query({ fields: 'sheets.properties' })
106+
.reply(200, {
107+
sheets: [{ properties: { sheetId: 1, title: 'testSheetName' } }],
108+
});
109+
scope
110+
.get((uri) => uri.startsWith('/v4/spreadsheets/testDocumentId/values/testSheetName!A5:ZZZ'))
111+
.times(2)
112+
.reply(200, {
113+
values: [
114+
['name', 'count'],
115+
['apple', 14],
116+
['banana', 12],
117+
['orange', 10],
118+
],
119+
});
120+
121+
const { response } = await testPollingTriggerNode(GoogleSheetsTrigger, {
122+
credential: mockDeep(),
123+
mode: 'manual',
124+
node: {
125+
parameters: {
126+
documentId: 'testDocumentId',
127+
sheetName: 1,
128+
event: 'rowAdded',
129+
options: {
130+
dataLocationOnSheet: {
131+
values: {
132+
rangeDefinition: 'specifyRange',
133+
headerRow: 5,
134+
firstDataRow: 4,
135+
},
136+
},
137+
},
138+
},
139+
},
140+
});
141+
142+
scope.done();
143+
144+
expect(response).toEqual([
145+
[
146+
{ json: { count: 14, name: 'apple' } },
147+
{ json: { count: 12, name: 'banana' } },
148+
{ json: { count: 10, name: 'orange' } },
149+
],
150+
]);
151+
});
152+
153+
it('should return rows starting from first data row in trigger mode', async () => {
154+
const scope = nock(baseUrl);
155+
scope
156+
.get('/v4/spreadsheets/testDocumentId')
157+
.query({ fields: 'sheets.properties' })
158+
.reply(200, {
159+
sheets: [{ properties: { sheetId: 1, title: 'testSheetName' } }],
160+
});
161+
scope
162+
.get((uri) => uri.startsWith('/v4/spreadsheets/testDocumentId/values/testSheetName!A5:ZZZ'))
163+
.times(2)
164+
.reply(200, {
165+
values: [
166+
['name', 'count'],
167+
['apple', 14],
168+
['banana', 12],
169+
['orange', 10],
170+
],
171+
});
172+
173+
const { response } = await testPollingTriggerNode(GoogleSheetsTrigger, {
174+
credential: mockDeep(),
175+
mode: 'trigger',
176+
workflowStaticData: {
177+
documentId: 'testDocumentId',
178+
sheetId: 1,
179+
lastIndexChecked: 0,
180+
},
181+
node: {
182+
parameters: {
183+
documentId: 'testDocumentId',
184+
sheetName: 1,
185+
event: 'rowAdded',
186+
options: {
187+
dataLocationOnSheet: {
188+
values: {
189+
rangeDefinition: 'specifyRange',
190+
headerRow: 5,
191+
firstDataRow: 7,
192+
},
193+
},
194+
},
195+
},
196+
},
197+
});
198+
199+
scope.done();
200+
201+
expect(response).toEqual([
202+
[{ json: { count: 12, name: 'banana' } }, { json: { count: 10, name: 'orange' } }],
203+
]);
204+
});
205+
206+
it('should return rows starting from header row when first data row is less than header row in trigger mode', async () => {
207+
const scope = nock(baseUrl);
208+
scope
209+
.get('/v4/spreadsheets/testDocumentId')
210+
.query({ fields: 'sheets.properties' })
211+
.reply(200, {
212+
sheets: [{ properties: { sheetId: 1, title: 'testSheetName' } }],
213+
});
214+
scope
215+
.get((uri) => uri.startsWith('/v4/spreadsheets/testDocumentId/values/testSheetName!A5:ZZZ'))
216+
.times(2)
217+
.reply(200, {
218+
values: [
219+
['name', 'count'],
220+
['apple', 14],
221+
['banana', 12],
222+
['orange', 10],
223+
],
224+
});
225+
226+
const { response } = await testPollingTriggerNode(GoogleSheetsTrigger, {
227+
credential: mockDeep(),
228+
mode: 'trigger',
229+
workflowStaticData: {
230+
documentId: 'testDocumentId',
231+
sheetId: 1,
232+
lastIndexChecked: 0,
233+
},
234+
node: {
235+
parameters: {
236+
documentId: 'testDocumentId',
237+
sheetName: 1,
238+
event: 'rowAdded',
239+
options: {
240+
dataLocationOnSheet: {
241+
values: {
242+
rangeDefinition: 'specifyRange',
243+
headerRow: 5,
244+
firstDataRow: 4,
245+
},
246+
},
247+
},
248+
},
249+
},
250+
});
251+
252+
scope.done();
253+
254+
expect(response).toEqual([
255+
[
256+
{ json: { count: 14, name: 'apple' } },
257+
{ json: { count: 12, name: 'banana' } },
258+
{ json: { count: 10, name: 'orange' } },
259+
],
260+
]);
261+
});
52262
});
53263
});

0 commit comments

Comments
 (0)