mirror of
https://github.com/n8n-io/n8n.git
synced 2026-06-01 17:27:14 +02:00
Add node changes
This commit is contained in:
parent
0cc59e407a
commit
860b5c9023
|
|
@ -17,7 +17,7 @@ export class DataTable implements INodeType {
|
|||
icon: 'fa:table',
|
||||
iconColor: 'orange-red',
|
||||
group: ['input', 'transform'],
|
||||
version: 1,
|
||||
version: [1, 1.1],
|
||||
subtitle: '={{$parameter["action"]}}',
|
||||
description: 'Permanently save data across workflow executions in a table',
|
||||
defaults: {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { DataTableColumnJsType } from 'n8n-workflow';
|
||||
import type { DataTableColumnJsType, DataTableColumnType } from 'n8n-workflow';
|
||||
|
||||
export const ANY_CONDITION = 'anyCondition';
|
||||
export const ALL_CONDITIONS = 'allConditions';
|
||||
|
|
@ -7,13 +7,17 @@ export const ROWS_LIMIT_DEFAULT = 50;
|
|||
|
||||
export type FilterType = typeof ANY_CONDITION | typeof ALL_CONDITIONS;
|
||||
|
||||
export type KeyNameType = `${string} (${DataTableColumnType})`;
|
||||
|
||||
export type FieldEntry =
|
||||
| {
|
||||
keyName: string;
|
||||
keyName: KeyNameType;
|
||||
condition: 'isEmpty' | 'isNotEmpty' | 'isTrue' | 'isFalse';
|
||||
path?: string;
|
||||
}
|
||||
| {
|
||||
keyName: string;
|
||||
keyName: KeyNameType;
|
||||
condition?: 'eq' | 'neq' | 'like' | 'ilike' | 'gt' | 'gte' | 'lt' | 'lte';
|
||||
keyValue: DataTableColumnJsType;
|
||||
path?: string;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -58,9 +58,12 @@ export async function getDataTableColumns(this: ILoadOptionsFunctions) {
|
|||
|
||||
const columns = await proxy.getColumns();
|
||||
for (const column of columns) {
|
||||
// From version 1.1 we start encoding the type as metadata on the value here
|
||||
// to support showing the `path` field for json columns
|
||||
const value = this.getNode().typeVersion > 1 ? `${column.name} (${column.type})` : column.name;
|
||||
returnData.push({
|
||||
name: `${column.name} (${column.type})`,
|
||||
value: column.name,
|
||||
value,
|
||||
type: column.type,
|
||||
});
|
||||
}
|
||||
|
|
@ -72,7 +75,8 @@ export async function getConditionsForColumn(this: ILoadOptionsFunctions) {
|
|||
if (!proxy) {
|
||||
return [];
|
||||
}
|
||||
const keyName = this.getCurrentNodeParameter('&keyName') as string;
|
||||
const rawKeyName = this.getCurrentNodeParameter('&keyName') as string;
|
||||
const keyName = rawKeyName?.split(' ')[0];
|
||||
|
||||
const nullConditions: INodePropertyOptions[] = [
|
||||
{ name: 'Is Empty', value: 'isEmpty' },
|
||||
|
|
@ -125,6 +129,12 @@ export async function getConditionsForColumn(this: ILoadOptionsFunctions) {
|
|||
|
||||
const conditions: INodePropertyOptions[] = [];
|
||||
|
||||
if (type === 'json') {
|
||||
conditions.push.apply(conditions, booleanConditions);
|
||||
conditions.push.apply(conditions, equalsConditions);
|
||||
conditions.push.apply(conditions, stringConditions);
|
||||
}
|
||||
|
||||
if (type === 'boolean') {
|
||||
conditions.push.apply(conditions, booleanConditions);
|
||||
}
|
||||
|
|
@ -156,7 +166,7 @@ export async function getDataTables(this: ILoadOptionsFunctions): Promise<Resour
|
|||
const fields: ResourceMapperField[] = [];
|
||||
|
||||
for (const field of result) {
|
||||
const type = field.type === 'date' ? 'dateTime' : field.type;
|
||||
const type = field.type === 'date' ? 'dateTime' : field.type === 'json' ? 'object' : field.type;
|
||||
|
||||
fields.push({
|
||||
id: field.name,
|
||||
|
|
|
|||
|
|
@ -94,6 +94,19 @@ export function getSelectFields(
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Path',
|
||||
name: 'path',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
"Path to value in the JSON object using lodash.get notation. { a: { b: [{c: 3}] } } -> 'a.b[0].c'.",
|
||||
displayOptions: {
|
||||
show: {
|
||||
keyName: [{ _cnd: { includes: '(json)' } }],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
|
@ -130,10 +143,12 @@ export async function getSelectFilter(
|
|||
...Object.fromEntries(availableColumns.map((col) => [col.name, col.type])),
|
||||
};
|
||||
|
||||
const invalidConditions = fields.filter((field) => !allColumnsWithTypes[field.keyName]);
|
||||
const invalidConditions = fields.filter(
|
||||
(field) => !allColumnsWithTypes[field.keyName.split(' ')[0]],
|
||||
);
|
||||
|
||||
if (invalidConditions.length > 0) {
|
||||
const invalidColumnNames = invalidConditions.map((c) => c.keyName).join(', ');
|
||||
const invalidColumnNames = invalidConditions.map((c) => c.keyName.split(' ')[0]).join(', ');
|
||||
throw new NodeOperationError(
|
||||
node,
|
||||
`Filter validation failed: Column(s) "${invalidColumnNames}" do not exist in the selected table. ` +
|
||||
|
|
|
|||
|
|
@ -91,34 +91,38 @@ export function buildGetManyFilter(
|
|||
node: INode,
|
||||
): DataTableFilter {
|
||||
const filters = fieldEntries.map((x) => {
|
||||
const common = {
|
||||
columnName: x.keyName.split(' ')[0],
|
||||
path: x.path,
|
||||
};
|
||||
switch (x.condition) {
|
||||
case 'isEmpty':
|
||||
return {
|
||||
columnName: x.keyName,
|
||||
...common,
|
||||
condition: 'eq' as const,
|
||||
value: null,
|
||||
};
|
||||
case 'isNotEmpty':
|
||||
return {
|
||||
columnName: x.keyName,
|
||||
...common,
|
||||
condition: 'neq' as const,
|
||||
value: null,
|
||||
};
|
||||
case 'isTrue':
|
||||
return {
|
||||
columnName: x.keyName,
|
||||
...common,
|
||||
condition: 'eq' as const,
|
||||
value: true,
|
||||
};
|
||||
case 'isFalse':
|
||||
return {
|
||||
columnName: x.keyName,
|
||||
...common,
|
||||
condition: 'eq' as const,
|
||||
value: false,
|
||||
};
|
||||
default: {
|
||||
let value = x.keyValue;
|
||||
const columnType = columnTypeMap[x.keyName];
|
||||
const columnType = columnTypeMap[common.columnName];
|
||||
|
||||
// Convert ISO date strings to Date objects for date columns
|
||||
if (columnType === 'date' && typeof value === 'string') {
|
||||
|
|
@ -126,13 +130,13 @@ export function buildGetManyFilter(
|
|||
if (isNaN(parsed.getTime())) {
|
||||
throw new NodeOperationError(
|
||||
node,
|
||||
`Invalid date string '${value}' for column '${x.keyName}'`,
|
||||
`Invalid date string '${value}' for column '${common.columnName}'`,
|
||||
);
|
||||
}
|
||||
value = parsed;
|
||||
}
|
||||
return {
|
||||
columnName: x.keyName,
|
||||
...common,
|
||||
condition: x.condition ?? 'eq',
|
||||
value,
|
||||
};
|
||||
|
|
@ -186,10 +190,7 @@ export function dataObjectToApiInput(
|
|||
}
|
||||
}
|
||||
|
||||
throw new NodeOperationError(
|
||||
node,
|
||||
`unexpected object input '${JSON.stringify(v)}' in row ${row}`,
|
||||
);
|
||||
return [k, dataObjectToApiInput(v as IDataObject, node, row)];
|
||||
}
|
||||
|
||||
return [k, v];
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ describe('selectMany utils', () => {
|
|||
filters = [
|
||||
{
|
||||
condition: 'eq',
|
||||
keyName: 'id',
|
||||
keyName: 'id (string) (string)',
|
||||
keyValue: 1,
|
||||
},
|
||||
];
|
||||
|
|
@ -132,7 +132,7 @@ describe('selectMany utils', () => {
|
|||
describe('filter conditions', () => {
|
||||
it('should handle "eq" condition', async () => {
|
||||
// ARRANGE
|
||||
filters = [{ condition: 'eq', keyName: 'name', keyValue: 'John' }];
|
||||
filters = [{ condition: 'eq', keyName: 'name (string)', keyValue: 'John' }];
|
||||
getManyRowsAndCount.mockReturnValue({ data: [{ id: 1, name: 'John' }], count: 1 });
|
||||
|
||||
// ACT
|
||||
|
|
@ -144,7 +144,7 @@ describe('selectMany utils', () => {
|
|||
|
||||
it('should handle "neq" condition', async () => {
|
||||
// ARRANGE
|
||||
filters = [{ condition: 'neq', keyName: 'name', keyValue: 'John' }];
|
||||
filters = [{ condition: 'neq', keyName: 'name (string)', keyValue: 'John' }];
|
||||
getManyRowsAndCount.mockReturnValue({ data: [{ id: 1, name: 'Jane' }], count: 1 });
|
||||
|
||||
// ACT
|
||||
|
|
@ -156,7 +156,7 @@ describe('selectMany utils', () => {
|
|||
|
||||
it('should handle "gt" condition with numbers', async () => {
|
||||
// ARRANGE
|
||||
filters = [{ condition: 'gt', keyName: 'age', keyValue: 25 }];
|
||||
filters = [{ condition: 'gt', keyName: 'age (number)', keyValue: 25 }];
|
||||
getManyRowsAndCount.mockReturnValue({ data: [{ id: 1, age: 30 }], count: 1 });
|
||||
|
||||
// ACT
|
||||
|
|
@ -168,7 +168,7 @@ describe('selectMany utils', () => {
|
|||
|
||||
it('should handle "gte" condition with numbers', async () => {
|
||||
// ARRANGE
|
||||
filters = [{ condition: 'gte', keyName: 'age', keyValue: 25 }];
|
||||
filters = [{ condition: 'gte', keyName: 'age (number)', keyValue: 25 }];
|
||||
getManyRowsAndCount.mockReturnValue({
|
||||
data: [
|
||||
{ id: 1, age: 25 },
|
||||
|
|
@ -186,7 +186,7 @@ describe('selectMany utils', () => {
|
|||
|
||||
it('should handle "lt" condition with numbers', async () => {
|
||||
// ARRANGE
|
||||
filters = [{ condition: 'lt', keyName: 'age', keyValue: 30 }];
|
||||
filters = [{ condition: 'lt', keyName: 'age (number)', keyValue: 30 }];
|
||||
getManyRowsAndCount.mockReturnValue({ data: [{ id: 1, age: 25 }], count: 1 });
|
||||
|
||||
// ACT
|
||||
|
|
@ -198,7 +198,7 @@ describe('selectMany utils', () => {
|
|||
|
||||
it('should handle "lte" condition with numbers', async () => {
|
||||
// ARRANGE
|
||||
filters = [{ condition: 'lte', keyName: 'age', keyValue: 30 }];
|
||||
filters = [{ condition: 'lte', keyName: 'age (number)', keyValue: 30 }];
|
||||
getManyRowsAndCount.mockReturnValue({
|
||||
data: [
|
||||
{ id: 1, age: 25 },
|
||||
|
|
@ -216,7 +216,7 @@ describe('selectMany utils', () => {
|
|||
|
||||
it('should handle "like" condition with pattern matching', async () => {
|
||||
// ARRANGE
|
||||
filters = [{ condition: 'like', keyName: 'name', keyValue: '%Mar%' }];
|
||||
filters = [{ condition: 'like', keyName: 'name (string)', keyValue: '%Mar%' }];
|
||||
getManyRowsAndCount.mockReturnValue({ data: [{ id: 1, name: 'Anne-Marie' }], count: 1 });
|
||||
|
||||
// ACT
|
||||
|
|
@ -228,7 +228,7 @@ describe('selectMany utils', () => {
|
|||
|
||||
it('should handle "ilike" condition with case-insensitive pattern matching', async () => {
|
||||
// ARRANGE
|
||||
filters = [{ condition: 'ilike', keyName: 'name', keyValue: '%mar%' }];
|
||||
filters = [{ condition: 'ilike', keyName: 'name (string)', keyValue: '%mar%' }];
|
||||
getManyRowsAndCount.mockReturnValue({ data: [{ id: 1, name: 'Anne-Marie' }], count: 1 });
|
||||
|
||||
// ACT
|
||||
|
|
@ -241,8 +241,8 @@ describe('selectMany utils', () => {
|
|||
it('should handle multiple conditions with ANY_CONDITION (OR logic - matches records satisfying either condition)', async () => {
|
||||
// ARRANGE
|
||||
filters = [
|
||||
{ condition: 'eq', keyName: 'status', keyValue: 'active' },
|
||||
{ condition: 'gt', keyName: 'age', keyValue: 50 },
|
||||
{ condition: 'eq', keyName: 'status (string)', keyValue: 'active' },
|
||||
{ condition: 'gt', keyName: 'age (number)', keyValue: 50 },
|
||||
];
|
||||
getManyRowsAndCount.mockReturnValue({
|
||||
data: [{ id: 1, status: 'active', age: 25 }],
|
||||
|
|
@ -259,8 +259,8 @@ describe('selectMany utils', () => {
|
|||
it('should handle multiple conditions with ALL_CONDITIONS (AND logic - matches records satisfying all conditions)', async () => {
|
||||
// ARRANGE
|
||||
filters = [
|
||||
{ condition: 'eq', keyName: 'status', keyValue: 'active' },
|
||||
{ condition: 'gte', keyName: 'age', keyValue: 21 },
|
||||
{ condition: 'eq', keyName: 'status (string)', keyValue: 'active' },
|
||||
{ condition: 'gte', keyName: 'age (number)', keyValue: 21 },
|
||||
];
|
||||
mockExecuteFunctions.getNodeParameter = jest.fn().mockImplementation((field) => {
|
||||
switch (field) {
|
||||
|
|
@ -287,8 +287,8 @@ describe('selectMany utils', () => {
|
|||
it('should handle ALL_CONDITIONS excluding records that match only one condition (proves AND logic)', async () => {
|
||||
// ARRANGE
|
||||
filters = [
|
||||
{ condition: 'eq', keyName: 'status', keyValue: 'inactive' },
|
||||
{ condition: 'gte', keyName: 'age', keyValue: 21 },
|
||||
{ condition: 'eq', keyName: 'status (string)', keyValue: 'inactive' },
|
||||
{ condition: 'gte', keyName: 'age (number)', keyValue: 21 },
|
||||
];
|
||||
mockExecuteFunctions.getNodeParameter = jest.fn().mockImplementation((field) => {
|
||||
switch (field) {
|
||||
|
|
@ -315,8 +315,8 @@ describe('selectMany utils', () => {
|
|||
it('should handle ANY_CONDITION including records that match only one condition (proves OR logic)', async () => {
|
||||
// ARRANGE
|
||||
filters = [
|
||||
{ condition: 'eq', keyName: 'status', keyValue: 'inactive' },
|
||||
{ condition: 'gte', keyName: 'age', keyValue: 21 },
|
||||
{ condition: 'eq', keyName: 'status (string)', keyValue: 'inactive' },
|
||||
{ condition: 'gte', keyName: 'age (number)', keyValue: 21 },
|
||||
];
|
||||
mockExecuteFunctions.getNodeParameter = jest.fn().mockImplementation((field) => {
|
||||
switch (field) {
|
||||
|
|
@ -346,8 +346,8 @@ describe('selectMany utils', () => {
|
|||
it('should validate filter conditions against table schema', async () => {
|
||||
// ARRANGE
|
||||
filters = [
|
||||
{ condition: 'eq', keyName: 'name', keyValue: 'John' }, // Valid column
|
||||
{ condition: 'eq', keyName: 'invalid_column', keyValue: 'test' }, // Invalid column
|
||||
{ condition: 'eq', keyName: 'name (string)', keyValue: 'John' }, // Valid column
|
||||
{ condition: 'eq', keyName: 'invalid_column (string)', keyValue: 'test' }, // Invalid column
|
||||
];
|
||||
|
||||
// ACT & ASSERT
|
||||
|
|
@ -364,8 +364,8 @@ describe('selectMany utils', () => {
|
|||
it('should allow system columns in filter conditions', async () => {
|
||||
// ARRANGE
|
||||
filters = [
|
||||
{ condition: 'eq', keyName: 'id', keyValue: 1 }, // System column
|
||||
{ condition: 'neq', keyName: 'createdAt', keyValue: null }, // System column
|
||||
{ condition: 'eq', keyName: 'id (string)', keyValue: 1 }, // System column
|
||||
{ condition: 'neq', keyName: 'createdAt (date)', keyValue: null }, // System column
|
||||
];
|
||||
|
||||
// ACT
|
||||
|
|
@ -379,8 +379,8 @@ describe('selectMany utils', () => {
|
|||
it('should allow combination of system and custom columns', async () => {
|
||||
// ARRANGE
|
||||
filters = [
|
||||
{ condition: 'eq', keyName: 'id', keyValue: 1 }, // System column
|
||||
{ condition: 'eq', keyName: 'name', keyValue: 'John' }, // Custom column
|
||||
{ condition: 'eq', keyName: 'id (string)', keyValue: 1 }, // System column
|
||||
{ condition: 'eq', keyName: 'name (string)', keyValue: 'John' }, // Custom column
|
||||
];
|
||||
|
||||
// ACT
|
||||
|
|
@ -406,8 +406,8 @@ describe('selectMany utils', () => {
|
|||
it('should report multiple invalid columns in error message', async () => {
|
||||
// ARRANGE
|
||||
filters = [
|
||||
{ condition: 'eq', keyName: 'invalid1', keyValue: 'test1' },
|
||||
{ condition: 'eq', keyName: 'invalid2', keyValue: 'test2' },
|
||||
{ condition: 'eq', keyName: 'invalid1 (string)', keyValue: 'test1' },
|
||||
{ condition: 'eq', keyName: 'invalid2 (string)', keyValue: 'test2' },
|
||||
];
|
||||
|
||||
// ACT & ASSERT
|
||||
|
|
|
|||
|
|
@ -107,18 +107,6 @@ describe('dataObjectToApiInput', () => {
|
|||
expect(result.createdAt).toBeInstanceOf(Date);
|
||||
expect((result.createdAt as Date).toISOString()).toBe('2025-09-01T12:00:00.000Z');
|
||||
});
|
||||
|
||||
it('should handle date-like objects where toISOString throws', () => {
|
||||
const dateLikeObject = {
|
||||
toISOString: () => {
|
||||
throw new Error('toISOString failed');
|
||||
},
|
||||
};
|
||||
const input = { createdAt: dateLikeObject, name: 'test' };
|
||||
|
||||
expect(() => dataObjectToApiInput(input, mockNode, 0)).toThrow(NodeOperationError);
|
||||
expect(() => dataObjectToApiInput(input, mockNode, 0)).toThrow('unexpected object input');
|
||||
});
|
||||
});
|
||||
|
||||
describe('error cases', () => {
|
||||
|
|
@ -134,29 +122,8 @@ describe('dataObjectToApiInput', () => {
|
|||
it('should throw error for plain objects', () => {
|
||||
const input = { metadata: { key: 'value' } };
|
||||
|
||||
expect(() => dataObjectToApiInput(input, mockNode, 0)).toThrow(NodeOperationError);
|
||||
expect(() => dataObjectToApiInput(input, mockNode, 0)).toThrow(
|
||||
'unexpected object input \'{"key":"value"}\' in row 0',
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw error for objects without toISOString method', () => {
|
||||
const input = { config: { setting1: true, setting2: 'value' } };
|
||||
|
||||
expect(() => dataObjectToApiInput(input, mockNode, 0)).toThrow(NodeOperationError);
|
||||
expect(() => dataObjectToApiInput(input, mockNode, 0)).toThrow('unexpected object input');
|
||||
});
|
||||
|
||||
test('dataObjectToApiInput throws on invalid date-like object', () => {
|
||||
const dateLikeObject = {
|
||||
toISOString: () => 'not-a-date',
|
||||
};
|
||||
const input = { createdAt: dateLikeObject, name: 'test' };
|
||||
|
||||
expect(() => dataObjectToApiInput(input, mockNode, 0)).toThrow(NodeOperationError);
|
||||
expect(() => dataObjectToApiInput(input, mockNode, 0)).toThrow(
|
||||
"unexpected object input '{}' in row 0",
|
||||
);
|
||||
const result = dataObjectToApiInput(input, mockNode, 0);
|
||||
expect(result).toEqual(input);
|
||||
});
|
||||
|
||||
it('should include correct row number in error message', () => {
|
||||
|
|
@ -206,9 +173,7 @@ describe('dataObjectToApiInput', () => {
|
|||
describe('buildGetManyFilter', () => {
|
||||
describe('isEmpty/isNotEmpty translation', () => {
|
||||
it('should translate isEmpty to eq with null value', () => {
|
||||
const fieldEntries = [
|
||||
{ keyName: 'name', condition: 'isEmpty' as const, keyValue: 'ignored' },
|
||||
];
|
||||
const fieldEntries: FieldEntry[] = [{ keyName: 'name (string)', condition: 'isEmpty' }];
|
||||
|
||||
const result = buildGetManyFilter(fieldEntries, ALL_CONDITIONS, { name: 'string' }, mockNode);
|
||||
|
||||
|
|
@ -225,9 +190,7 @@ describe('buildGetManyFilter', () => {
|
|||
});
|
||||
|
||||
it('should translate isNotEmpty to neq with null value', () => {
|
||||
const fieldEntries = [
|
||||
{ keyName: 'email', condition: 'isNotEmpty' as const, keyValue: 'ignored' },
|
||||
];
|
||||
const fieldEntries: FieldEntry[] = [{ keyName: 'email (string)', condition: 'isNotEmpty' }];
|
||||
|
||||
const result = buildGetManyFilter(fieldEntries, ANY_CONDITION, { email: 'string' }, mockNode);
|
||||
|
||||
|
|
@ -244,10 +207,10 @@ describe('buildGetManyFilter', () => {
|
|||
});
|
||||
|
||||
it('should handle mixed conditions including isEmpty/isNotEmpty', () => {
|
||||
const fieldEntries = [
|
||||
{ keyName: 'name', condition: 'eq' as const, keyValue: 'John' },
|
||||
{ keyName: 'email', condition: 'isEmpty' as const, keyValue: 'ignored' },
|
||||
{ keyName: 'phone', condition: 'isNotEmpty' as const, keyValue: 'ignored' },
|
||||
const fieldEntries: FieldEntry[] = [
|
||||
{ keyName: 'name (string)', condition: 'eq', keyValue: 'John' },
|
||||
{ keyName: 'email (string)', condition: 'isEmpty' },
|
||||
{ keyName: 'phone (string)', condition: 'isNotEmpty' },
|
||||
];
|
||||
|
||||
const result = buildGetManyFilter(
|
||||
|
|
@ -286,8 +249,8 @@ describe('buildGetManyFilter', () => {
|
|||
|
||||
describe('isTrue/isFalse translation', () => {
|
||||
it('should translate isTrue to eq with true value', () => {
|
||||
const fieldEntries = [
|
||||
{ keyName: 'isActive', condition: 'isTrue' as const, keyValue: 'ignored' },
|
||||
const fieldEntries: FieldEntry[] = [
|
||||
{ keyName: 'isActive (boolean)', condition: 'isTrue' as const },
|
||||
];
|
||||
|
||||
const result = buildGetManyFilter(
|
||||
|
|
@ -310,9 +273,7 @@ describe('buildGetManyFilter', () => {
|
|||
});
|
||||
|
||||
it('should translate isFalse to eq with false value', () => {
|
||||
const fieldEntries = [
|
||||
{ keyName: 'email', condition: 'isFalse' as const, keyValue: 'ignored' },
|
||||
];
|
||||
const fieldEntries: FieldEntry[] = [{ keyName: 'email (string)', condition: 'isFalse' }];
|
||||
|
||||
const result = buildGetManyFilter(
|
||||
fieldEntries,
|
||||
|
|
@ -334,10 +295,10 @@ describe('buildGetManyFilter', () => {
|
|||
});
|
||||
|
||||
it('should handle mixed conditions including isTrue/isFalse', () => {
|
||||
const fieldEntries = [
|
||||
{ keyName: 'name', condition: 'eq' as const, keyValue: 'John' },
|
||||
{ keyName: 'isActive', condition: 'isTrue' as const, keyValue: 'ignored' },
|
||||
{ keyName: 'isDeleted', condition: 'isFalse' as const, keyValue: 'ignored' },
|
||||
const fieldEntries: FieldEntry[] = [
|
||||
{ keyName: 'name (string)', condition: 'eq', keyValue: 'John' },
|
||||
{ keyName: 'isActive (boolean)', condition: 'isTrue' },
|
||||
{ keyName: 'isDeleted (boolean)', condition: 'isFalse' },
|
||||
];
|
||||
|
||||
const result = buildGetManyFilter(
|
||||
|
|
@ -375,9 +336,9 @@ describe('buildGetManyFilter', () => {
|
|||
});
|
||||
|
||||
it('should handle other conditions', () => {
|
||||
const fieldEntries = [
|
||||
{ keyName: 'age', condition: 'gt' as const, keyValue: 18 },
|
||||
{ keyName: 'name', condition: 'like' as const, keyValue: '%john%' },
|
||||
const fieldEntries: FieldEntry[] = [
|
||||
{ keyName: 'age (number)', condition: 'gt', keyValue: 18 },
|
||||
{ keyName: 'name (string)', condition: 'like', keyValue: '%john%' },
|
||||
];
|
||||
|
||||
const result = buildGetManyFilter(
|
||||
|
|
@ -411,7 +372,7 @@ describe('buildGetManyFilter', () => {
|
|||
it('should pass Date objects through unchanged', () => {
|
||||
const testDate = new Date('2025-10-06T08:14:42.274Z');
|
||||
const fieldEntries: FieldEntry[] = [
|
||||
{ keyName: 'createdAt', condition: 'lte', keyValue: testDate },
|
||||
{ keyName: 'createdAt (date)', condition: 'lte', keyValue: testDate },
|
||||
];
|
||||
|
||||
const result = buildGetManyFilter(
|
||||
|
|
@ -436,7 +397,7 @@ describe('buildGetManyFilter', () => {
|
|||
it('should convert ISO date strings to Date objects', () => {
|
||||
const dateString = '2025-10-06T08:14:42.274Z';
|
||||
const fieldEntries: FieldEntry[] = [
|
||||
{ keyName: 'createdAt', condition: 'lte', keyValue: dateString },
|
||||
{ keyName: 'createdAt (date)', condition: 'lte', keyValue: dateString },
|
||||
];
|
||||
|
||||
const result = buildGetManyFilter(
|
||||
|
|
@ -453,7 +414,7 @@ describe('buildGetManyFilter', () => {
|
|||
it('should throw an Error for invalid date strings', () => {
|
||||
const invalidDateString = 'invalid-date';
|
||||
const fieldEntries: FieldEntry[] = [
|
||||
{ keyName: 'createdAt', condition: 'lte', keyValue: invalidDateString },
|
||||
{ keyName: 'createdAt (date)', condition: 'lte', keyValue: invalidDateString },
|
||||
];
|
||||
|
||||
expect(() =>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user