Skip to content

Commit

Permalink
fix(core): Do not enable strict type validation by default for resour…
Browse files Browse the repository at this point in the history
…ce mapper (#13037)
  • Loading branch information
elsmr authored Feb 4, 2025
1 parent 3a908ac commit fdcff90
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -247,65 +247,155 @@ describe('validateValueAgainstSchema', () => {
expect(typeof result).toEqual('number');
});

describe('when the mode is in Fixed mode, and the node is a resource mapper', () => {
const nodeType = {
description: {
properties: [
{
name: 'operation',
type: 'resourceMapper',
typeOptions: {
resourceMapper: {
mode: 'add',
describe('when validating a resource mapper value', () => {
describe('when attemptToConvertTypes === true', () => {
const nodeType = {
description: {
properties: [
{
name: 'operation',
type: 'resourceMapper',
typeOptions: {
resourceMapper: {
mode: 'add',
},
},
},
},
],
},
} as unknown as INodeType;

const node = {
parameters: {
operation: {
schema: [
{ id: 'num', type: 'number', required: true },
{ id: 'str', type: 'string', required: true },
{ id: 'obj', type: 'object', required: true },
{ id: 'arr', type: 'array', required: true },
],
attemptToConvertTypes: true,
mappingMode: '',
value: '',
},
},
} as unknown as INode;
} as unknown as INodeType;

const parameterName = 'operation.value';
const node = {
parameters: {
operation: {
schema: [
{ id: 'num', type: 'number', required: true },
{ id: 'str', type: 'string', required: true },
{ id: 'obj', type: 'object', required: true },
{ id: 'arr', type: 'array', required: true },
],
attemptToConvertTypes: true,
mappingMode: '',
value: '',
},
},
} as unknown as INode;

describe('should correctly validate values for', () => {
test.each([
{ num: 0 },
{ num: 23 },
{ num: -0 },
{ num: -Infinity },
{ num: Infinity },
{ str: '' },
{ str: ' ' },
{ str: 'hello' },
{ arr: [] },
{ obj: {} },
])('%s', (value) => {
expect(() =>
validateValueAgainstSchema(node, nodeType, value, parameterName, 0, 0),
).not.toThrow();
const parameterName = 'operation.value';

describe('should correctly validate values for', () => {
test.each([
{ num: 0 },
{ num: 23 },
{ num: -0 },
{ num: -Infinity },
{ num: Infinity },
{ str: '' },
{ str: ' ' },
{ str: 'hello' },
{ arr: [] },
{ obj: {} },
])('%s', (value) => {
expect(() =>
validateValueAgainstSchema(node, nodeType, value, parameterName, 0, 0),
).not.toThrow();
});
});

describe('should throw an error for', () => {
test.each([{ num: NaN }, { num: undefined }, { num: null }])('%s', (value) => {
expect(() =>
validateValueAgainstSchema(node, nodeType, value, parameterName, 0, 0),
).toThrow();
});
});
});

describe('should throw an error for', () => {
test.each([{ num: NaN }, { num: undefined }, { num: null }])('%s', (value) => {
expect(() =>
validateValueAgainstSchema(node, nodeType, value, parameterName, 0, 0),
).toThrow();
describe('when attemptToConvertTypes is not set (=default)', () => {
test('should correctly validate and convert types', () => {
const nodeType = {
description: {
properties: [
{
displayName: 'Columns',
name: 'columns',
type: 'resourceMapper',
noDataExpression: true,
default: {
mappingMode: 'defineBelow',
value: null,
},
required: true,
typeOptions: {
loadOptionsDependsOn: ['table.value', 'operation'],
resourceMapper: {
resourceMapperMethod: 'getMappingColumns',
mode: 'upsert',
fieldWords: {
singular: 'column',
plural: 'columns',
},
addAllFields: true,
multiKeyMatch: true,
},
},
},
],
},
} as unknown as INodeType;

const node: INode = {
parameters: {
columns: {
mappingMode: 'defineBelow',
value: {
id: 2,
count: '={{ $json.count }}',
},
matchingColumns: ['id'],
schema: [
{
id: 'id',
displayName: 'id',
required: false,
defaultMatch: true,
display: true,
type: 'number',
canBeUsedToMatch: true,
},
{
id: 'count',
displayName: 'count',
required: false,
defaultMatch: false,
display: true,
type: 'number',
canBeUsedToMatch: false,
},
],
},
options: {},
},
id: '8d6cec63-8db1-440c-8966-4d6311ee69a9',
name: 'add products to DB',
type: 'n8n-nodes-base.postgres',
typeVersion: 2.3,
position: [420, 0],
};

const value = {
id: 2,
count: '23',
};

const parameterName = 'columns.value';

const result = validateValueAgainstSchema(node, nodeType, value, parameterName, 0, 0);

expect(result).toEqual({
id: 2,
count: 23,
});
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ const validateResourceMapperValue = (
if (schemaEntry?.type) {
const validationResult = validateFieldType(key, resolvedValue, schemaEntry.type, {
valueOptions: schemaEntry.options,
strict: !resourceMapperField.attemptToConvertTypes,
parseStrings: !!resourceMapperField.convertFieldsToString,
strict: resourceMapperField.attemptToConvertTypes === false,
parseStrings: Boolean(resourceMapperField.convertFieldsToString),
});

if (!validationResult.valid) {
Expand Down
4 changes: 2 additions & 2 deletions packages/workflow/src/Interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2722,8 +2722,8 @@ export type ResourceMapperValue = {
value: { [key: string]: string | number | boolean | null } | null;
matchingColumns: string[];
schema: ResourceMapperField[];
attemptToConvertTypes: boolean;
convertFieldsToString: boolean;
attemptToConvertTypes?: boolean;
convertFieldsToString?: boolean;
};

export type FilterOperatorType =
Expand Down

0 comments on commit fdcff90

Please sign in to comment.