fix(AWS DynamoDB Node): Add option to disable auto-parsing of numeric strings (#28093)

Co-authored-by: umut-polat <52835619+umut-polat@users.noreply.github.com>
Co-authored-by: RomanDavydchuk <roman.davydchuk@n8n.io>
This commit is contained in:
Bernhard Wittmann
2026-04-10 06:29:36 +00:00
committed by GitHub
co-authored by umut-polat RomanDavydchuk
parent dfdc6d2c75
commit 4b06720c8b
4 changed files with 60 additions and 6 deletions
@@ -138,6 +138,7 @@ export class AwsDynamoDB implements INodeType {
const dataToSend = this.getNodeParameter('dataToSend', 0) as
| 'defineBelow'
| 'autoMapInputData';
const autoParseNumbers = this.getNodeParameter('autoParseNumbers', i, true) as boolean;
const item: { [key: string]: string } = {};
if (dataToSend === 'autoMapInputData') {
@@ -150,11 +151,11 @@ export class AwsDynamoDB implements INodeType {
item[key] = items[i].json[key] as string;
}
body.Item = adjustPutItem(item as PutItemUi);
body.Item = adjustPutItem(item as PutItemUi, autoParseNumbers);
} else {
const fields = this.getNodeParameter('fieldsUi.fieldValues', i, []) as FieldsUiValues;
fields.forEach(({ fieldId, fieldValue }) => (item[fieldId] = fieldValue));
body.Item = adjustPutItem(item as PutItemUi);
body.Item = adjustPutItem(item as PutItemUi, autoParseNumbers);
}
const headers = {
@@ -90,6 +90,19 @@ export const itemFields: INodeProperties[] = [
default: 'defineBelow',
description: 'Whether to insert the input data this node receives in the new row',
},
{
displayName: 'Automatically Parse Numbers',
name: 'autoParseNumbers',
type: 'boolean',
displayOptions: {
show: {
operation: ['upsert'],
},
},
default: true,
description:
'Whether to convert number-looking string values to DynamoDB Number (N). Disable to keep strings as String (S).',
},
{
displayName: 'Inputs to Ignore',
name: 'inputsToIgnore',
@@ -0,0 +1,40 @@
import type { PutItemUi } from '../types';
import { adjustPutItem } from '../utils';
describe('adjustPutItem', () => {
it('maps actual numbers to N', () => {
expect(adjustPutItem({ count: 42 } as unknown as PutItemUi)).toEqual({
count: { N: '42' },
});
});
it('parses numeric strings as N when autoParseNumbers is enabled', () => {
expect(
adjustPutItem({ id: '34', executionId: '1234567890' } as unknown as PutItemUi, true),
).toEqual({
id: { N: '34' },
executionId: { N: '1234567890' },
});
});
it('keeps numeric strings as S when autoParseNumbers is disabled', () => {
expect(
adjustPutItem({ id: '34', executionId: '1234567890' } as unknown as PutItemUi, false),
).toEqual({
id: { S: '34' },
executionId: { S: '1234567890' },
});
});
it('maps booleans to BOOL', () => {
expect(adjustPutItem({ active: true } as unknown as PutItemUi)).toEqual({
active: { BOOL: 'true' },
});
});
it('maps non-numeric strings to S', () => {
expect(adjustPutItem({ name: 'hello' } as unknown as PutItemUi)).toEqual({
name: { S: 'hello' },
});
});
});
@@ -37,7 +37,7 @@ export function adjustExpressionAttributeName(eanUi: IAttributeNameUi[]) {
return ean;
}
export function adjustPutItem(putItemUi: PutItemUi) {
export function adjustPutItem(putItemUi: PutItemUi, autoParseNumbers = true) {
const adjustedPutItem: AdjustedPutItem = {};
Object.entries(putItemUi).forEach(([attribute, value]) => {
@@ -47,10 +47,10 @@ export function adjustPutItem(putItemUi: PutItemUi) {
type = 'BOOL';
} else if (typeof value === 'object' && !Array.isArray(value) && value !== null) {
type = 'M';
} else if (isNaN(Number(value))) {
type = 'S';
} else {
} else if (autoParseNumbers ? !isNaN(Number(value)) : typeof value === 'number') {
type = 'N';
} else {
type = 'S';
}
adjustedPutItem[attribute] = { [type]: value.toString() };