fix(Evaluation Trigger Node): Respect the row limit when reading from a data table (#36948)

This commit is contained in:
Bernhard Wittmann
2026-08-26 09:43:37 +00:00
committed by GitHub
parent dce9ff0eb9
commit ced302ae43
2 changed files with 68 additions and 2 deletions
@@ -235,8 +235,9 @@ export class EvaluationTrigger implements INodeType {
throw new NodeOperationError(this.getNode(), 'No row found');
}
const effectiveTotal = Math.min(count, maxRows);
const rowsLeft = Math.max(0, effectiveTotal - 1);
// `count` is the number of rows still matching (current row included), so the
// row limit has to be measured against the rows already consumed.
const rowsLeft = Math.max(0, Math.min(count - 1, maxRows - currentIndex - 1));
const currentRow = {
json: {
@@ -451,6 +451,71 @@ describe('Evaluation Trigger Node', () => {
},
});
});
test('should stop after maxRows when the table has more matching rows', async () => {
mockDataTable.getManyRowsAndCount
.mockResolvedValueOnce({ data: [{ id: 1 }], count: 5 })
.mockResolvedValueOnce({ data: [{ id: 2 }], count: 4 })
.mockResolvedValueOnce({ data: [{ id: 3 }], count: 3 });
mockExecuteFunctions.getNodeParameter.mockImplementation(
(key: string, _: number, fallbackValue?: string | number | boolean | object) => {
const mockParams: { [key: string]: unknown } = {
source: 'dataTable',
limitRows: true,
maxRows: 3,
dataTableId: 'mockDataTableId',
'filters.conditions': [],
matchType: 'anyCondition',
};
return (mockParams[key] ?? fallbackValue) as NodeParameterValueType;
},
);
const evaluationTrigger = new EvaluationTrigger();
mockExecuteFunctions.getInputData.mockReturnValue([{ json: {} }]);
const result1 = await evaluationTrigger.execute.call(mockExecuteFunctions);
expect(result1[0][0].json._rowsLeft).toBe(2);
mockExecuteFunctions.getInputData.mockReturnValue(result1[0]);
const result2 = await evaluationTrigger.execute.call(mockExecuteFunctions);
expect(result2[0][0].json._rowsLeft).toBe(1);
mockExecuteFunctions.getInputData.mockReturnValue(result2[0]);
const result3 = await evaluationTrigger.execute.call(mockExecuteFunctions);
expect(result3[0][0].json._rowsLeft).toBe(0);
});
test('should stop early when the table runs out before maxRows', async () => {
mockDataTable.getManyRowsAndCount
.mockResolvedValueOnce({ data: [{ id: 1 }], count: 2 })
.mockResolvedValueOnce({ data: [{ id: 2 }], count: 1 });
mockExecuteFunctions.getNodeParameter.mockImplementation(
(key: string, _: number, fallbackValue?: string | number | boolean | object) => {
const mockParams: { [key: string]: unknown } = {
source: 'dataTable',
limitRows: true,
maxRows: 10,
dataTableId: 'mockDataTableId',
'filters.conditions': [],
matchType: 'anyCondition',
};
return (mockParams[key] ?? fallbackValue) as NodeParameterValueType;
},
);
const evaluationTrigger = new EvaluationTrigger();
mockExecuteFunctions.getInputData.mockReturnValue([{ json: {} }]);
const result1 = await evaluationTrigger.execute.call(mockExecuteFunctions);
expect(result1[0][0].json._rowsLeft).toBe(1);
mockExecuteFunctions.getInputData.mockReturnValue(result1[0]);
const result2 = await evaluationTrigger.execute.call(mockExecuteFunctions);
expect(result2[0][0].json._rowsLeft).toBe(0);
});
});
});