dynamodb-toolbox/dynamodb-toolbox

Numbers do not deserialize correctly on 0.8+ with wrapNumbers: true

Closed this issue · 1 comments

When fetching values stored as number types in Dynamo (either number, or bigint when written with older versions of the SDK), the values come back as {value: "12345"}.

However, this line of code in formatItem.ts assumes they come back as flat strings:

  if (attr && attr.type === 'number') {
    value = Number(value as number)
  }

I assume that this is probably true if wrapNumbers is set to false, but when using wrapNumbers some additional logic is needed to correctly transform these values.

I've patched this locally with the following, which is horrendous but does seem to fix the issue:

    if (value !== null && typeof value === 'object' && Object.prototype.hasOwnProperty.call(value, 'value')) {
      value = (value as {value: typeof value}).value
    }

The following test reproduces this issue, provided you have a compatible dynamo instance running locally:

const TestTable = new Table({
  name: 'test-table',
  partitionKey: 'pk',
  sortKey: 'sk',
  DocumentClient: DocumentClientWithWrappedNumbers
})

const TestEntity = new Entity({
  name: 'TestEntity',
  autoExecute: false,
  attributes: {
    email: { type: 'string', partitionKey: true },
    sort: { type: 'string', sortKey: true },
    test: 'string',
    num: 'number',
  },
  table: TestTable
} as const)

it('round-trips a number', async () => {
  const sk = randomUUID();
  await TestEntity.put({
    pk: 'test-pk',
    sk,
    num: 1337,
  }, { execute: true });
  const {Item: value} = await TestEntity.get({
    pk: 'test-pk',
    sk,
  }, { execute: true });
  console.log(value);
  expect(value.num).toEqual(1337); // fails
})

The entity that comes back is:

    {
      sort: '37a4cfaa-0dcc-455f-aa25-2fed8ca781ad',
      created: '2023-09-18T20:20:11.763Z',
      email: 'test-pk',
      modified: '2023-09-18T20:20:11.763Z',
      entity: 'TestEntity',
      num: NaN
    }

Hey @amccarthy1
will give it a look tomorrow. thanks for reporting this 🙏