fix(Data Table Node): Update ResourceMapper Copy (no-changelog) (#19048)

This commit is contained in:
Charlie Kolb
2025-09-01 14:16:22 +02:00
committed by GitHub
parent b527edb5f8
commit ec7eddc364
5 changed files with 32 additions and 29 deletions

View File

@@ -1,9 +1,9 @@
import type { DataStoreColumnJsType } from 'n8n-workflow';
export const ANY_FILTER = 'anyFilter';
export const ALL_FILTERS = 'allFilters';
export const ANY_CONDITION = 'anyCondition';
export const ALL_CONDITIONS = 'allConditions';
export type FilterType = typeof ANY_FILTER | typeof ALL_FILTERS;
export type FilterType = typeof ANY_CONDITION | typeof ALL_CONDITIONS;
export type FieldEntry =
| {

View File

@@ -7,7 +7,7 @@ import type {
INodeProperties,
} from 'n8n-workflow';
import type { FilterType } from './constants';
import { ALL_CONDITIONS, ANY_CONDITION, type FilterType } from './constants';
import { DATA_TABLE_ID_FIELD } from './fields';
import { buildGetManyFilter, isFieldArray, isMatchType } from './utils';
@@ -22,16 +22,16 @@ export function getSelectFields(
type: 'options',
options: [
{
name: 'Any Filter',
value: 'anyFilter',
name: 'Any Condition',
value: ANY_CONDITION,
},
{
name: 'All Filters',
value: 'allFilters',
name: 'All Conditions',
value: ALL_CONDITIONS,
},
] satisfies Array<{ value: FilterType; name: string }>,
displayOptions,
default: 'anyFilter',
default: ANY_CONDITION,
},
{
displayName: 'Conditions',
@@ -50,11 +50,13 @@ export function getSelectFields(
name: 'conditions',
values: [
{
displayName: 'Field Name or ID',
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Column',
name: 'keyName',
type: 'options',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
'Choose from the list, or specify using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
typeOptions: {
loadOptionsDependsOn: [DATA_TABLE_ID_FIELD],
loadOptionsMethod: 'getDataTableColumns',
@@ -74,7 +76,7 @@ export function getSelectFields(
default: 'eq',
},
{
displayName: 'Field Value',
displayName: 'Value',
name: 'keyValue',
type: 'string',
default: '',
@@ -94,7 +96,7 @@ export function getSelectFields(
export function getSelectFilter(ctx: IExecuteFunctions, index: number) {
const fields = ctx.getNodeParameter('filters.conditions', index, []);
const matchType = ctx.getNodeParameter('matchType', index, 'anyFilter');
const matchType = ctx.getNodeParameter('matchType', index, ANY_CONDITION);
const node = ctx.getNode();
if (!isMatchType(matchType)) {

View File

@@ -12,7 +12,7 @@ import type {
import { NodeOperationError } from 'n8n-workflow';
import type { FieldEntry, FilterType } from './constants';
import { ALL_FILTERS, ANY_FILTER } from './constants';
import { ALL_CONDITIONS, ANY_CONDITION } from './constants';
import { DATA_TABLE_ID_FIELD } from './fields';
type DateLike = { toISOString: () => string };
@@ -76,7 +76,7 @@ export function isFieldEntry(obj: unknown): obj is FieldEntry {
}
export function isMatchType(obj: unknown): obj is FilterType {
return typeof obj === 'string' && (obj === ANY_FILTER || obj === ALL_FILTERS);
return typeof obj === 'string' && (obj === ANY_CONDITION || obj === ALL_CONDITIONS);
}
export function buildGetManyFilter(
@@ -105,7 +105,7 @@ export function buildGetManyFilter(
};
}
});
return { type: matchType === 'allFilters' ? 'and' : 'or', filters };
return { type: matchType === ALL_CONDITIONS ? 'and' : 'or', filters };
}
export function isFieldArray(value: unknown): value is FieldEntry[] {

View File

@@ -6,7 +6,7 @@ import {
} from 'n8n-workflow';
import type { FieldEntry } from '../../common/constants';
import { ANY_FILTER, ALL_FILTERS } from '../../common/constants';
import { ANY_CONDITION, ALL_CONDITIONS } from '../../common/constants';
import { DATA_TABLE_ID_FIELD } from '../../common/fields';
import { executeSelectMany } from '../../common/selectMany';
@@ -37,7 +37,7 @@ describe('selectMany utils', () => {
case 'filters.conditions':
return filters;
case 'matchType':
return ANY_FILTER;
return ANY_CONDITION;
}
}),
} as unknown as IExecuteFunctions;
@@ -226,7 +226,7 @@ describe('selectMany utils', () => {
expect(result).toEqual([{ json: { id: 1, name: 'Anne-Marie' } }]);
});
it('should handle multiple conditions with ANY_FILTER (OR logic - matches records satisfying either condition)', async () => {
it('should handle multiple conditions with ANY_CONDITION (OR logic - matches records satisfying either condition)', async () => {
// ARRANGE
filters = [
{ condition: 'eq', keyName: 'status', keyValue: 'active' },
@@ -244,7 +244,7 @@ describe('selectMany utils', () => {
expect(result).toEqual([{ json: { id: 1, status: 'active', age: 25 } }]);
});
it('should handle multiple conditions with ALL_FILTERS (AND logic - matches records satisfying all conditions)', async () => {
it('should handle multiple conditions with ALL_CONDITIONS (AND logic - matches records satisfying all conditions)', async () => {
// ARRANGE
filters = [
{ condition: 'eq', keyName: 'status', keyValue: 'active' },
@@ -257,7 +257,7 @@ describe('selectMany utils', () => {
case 'filters.conditions':
return filters;
case 'matchType':
return ALL_FILTERS;
return ALL_CONDITIONS;
}
});
getManyRowsAndCount.mockReturnValue({
@@ -272,7 +272,7 @@ describe('selectMany utils', () => {
expect(result).toEqual([{ json: { id: 1, status: 'active', age: 25 } }]);
});
it('should handle ALL_FILTERS excluding records that match only one condition (proves AND logic)', async () => {
it('should handle ALL_CONDITIONS excluding records that match only one condition (proves AND logic)', async () => {
// ARRANGE
filters = [
{ condition: 'eq', keyName: 'status', keyValue: 'inactive' },
@@ -285,7 +285,7 @@ describe('selectMany utils', () => {
case 'filters.conditions':
return filters;
case 'matchType':
return ALL_FILTERS;
return ALL_CONDITIONS;
}
});
getManyRowsAndCount.mockReturnValue({
@@ -300,7 +300,7 @@ describe('selectMany utils', () => {
expect(result).toEqual([]);
});
it('should handle ANY_FILTER including records that match only one condition (proves OR logic)', async () => {
it('should handle ANY_CONDITION including records that match only one condition (proves OR logic)', async () => {
// ARRANGE
filters = [
{ condition: 'eq', keyName: 'status', keyValue: 'inactive' },
@@ -313,7 +313,7 @@ describe('selectMany utils', () => {
case 'filters.conditions':
return filters;
case 'matchType':
return ANY_FILTER;
return ANY_CONDITION;
}
});
getManyRowsAndCount.mockReturnValue({

View File

@@ -2,6 +2,7 @@ import { DateTime } from 'luxon';
import type { INode } from 'n8n-workflow';
import { NodeOperationError } from 'n8n-workflow';
import { ANY_CONDITION, ALL_CONDITIONS } from '../../common/constants';
import { dataObjectToApiInput, buildGetManyFilter } from '../../common/utils';
const mockNode: INode = {
@@ -206,7 +207,7 @@ describe('buildGetManyFilter - isEmpty/isNotEmpty translation', () => {
it('should translate isEmpty to eq with null value', () => {
const fieldEntries = [{ keyName: 'name', condition: 'isEmpty' as const, keyValue: 'ignored' }];
const result = buildGetManyFilter(fieldEntries, 'allFilters');
const result = buildGetManyFilter(fieldEntries, ALL_CONDITIONS);
expect(result).toEqual({
type: 'and',
@@ -225,7 +226,7 @@ describe('buildGetManyFilter - isEmpty/isNotEmpty translation', () => {
{ keyName: 'email', condition: 'isNotEmpty' as const, keyValue: 'ignored' },
];
const result = buildGetManyFilter(fieldEntries, 'anyFilter');
const result = buildGetManyFilter(fieldEntries, ANY_CONDITION);
expect(result).toEqual({
type: 'or',
@@ -246,7 +247,7 @@ describe('buildGetManyFilter - isEmpty/isNotEmpty translation', () => {
{ keyName: 'phone', condition: 'isNotEmpty' as const, keyValue: 'ignored' },
];
const result = buildGetManyFilter(fieldEntries, 'allFilters');
const result = buildGetManyFilter(fieldEntries, ALL_CONDITIONS);
expect(result).toEqual({
type: 'and',
@@ -276,7 +277,7 @@ describe('buildGetManyFilter - isEmpty/isNotEmpty translation', () => {
{ keyName: 'name', condition: 'like' as const, keyValue: '%john%' },
];
const result = buildGetManyFilter(fieldEntries, 'anyFilter');
const result = buildGetManyFilter(fieldEntries, ANY_CONDITION);
expect(result).toEqual({
type: 'or',