UNPKG

@aws-lambda-powertools/parser

Version:
93 lines (92 loc) 3.92 kB
import { ZodError } from 'zod'; import { ParseError } from '../errors.js'; import { DynamoDBStreamSchema } from '../schemas/index.js'; import { envelopeDiscriminator } from './envelope.js'; /** * DynamoDB Stream Envelope to extract data within NewImage/OldImage * * Note: Values are the parsed models. Images' values can also be None, and * length of the list is the record's amount in the original event. */ export const DynamoDBStreamEnvelope = { /** * This is a discriminator to differentiate whether an envelope returns an array or an object * @hidden */ [envelopeDiscriminator]: 'array', parse(data, schema) { const parsedEnvelope = DynamoDBStreamSchema.parse(data); const processImage = (image, imageType, recordIndex) => { try { return image ? schema.parse(image) : undefined; } catch (error) { throw new ParseError(`Failed to parse DynamoDB record at index ${recordIndex}`, { cause: new ZodError(error.issues.map((issue) => ({ ...issue, path: [ 'Records', recordIndex, 'dynamodb', imageType, ...issue.path, ], }))), }); } }; return parsedEnvelope.Records.map((record, index) => ({ NewImage: processImage(record.dynamodb.NewImage, 'NewImage', index), OldImage: processImage(record.dynamodb.OldImage, 'OldImage', index), })); }, safeParse(data, schema) { const parsedEnvelope = DynamoDBStreamSchema.safeParse(data); if (!parsedEnvelope.success) { return { success: false, error: new ParseError('Failed to parse DynamoDB Stream envelope', { cause: parsedEnvelope.error, }), originalEvent: data, }; } const processImage = (image) => image ? schema.safeParse(image) : undefined; const result = parsedEnvelope.data.Records.reduce((acc, record, index) => { const newImage = processImage(record.dynamodb.NewImage); const oldImage = processImage(record.dynamodb.OldImage); if (newImage?.success === false || oldImage?.success === false) { const issues = []; for (const key of ['NewImage', 'OldImage']) { const image = key === 'NewImage' ? newImage : oldImage; if (image?.success === false) { issues.push(...image.error.issues.map((issue) => ({ ...issue, path: ['Records', index, 'dynamodb', key, ...issue.path], }))); } } acc.success = false; acc.errors[index] = { issues }; return acc; } acc.records.push({ NewImage: newImage?.data, OldImage: oldImage?.data, }); return acc; }, { success: true, records: [], errors: {} }); if (result.success) { return { success: true, data: result.records }; } const errorMessage = Object.keys(result.errors).length > 1 ? `Failed to parse records at indexes ${Object.keys(result.errors).join(', ')}` : `Failed to parse record at index ${Object.keys(result.errors)[0]}`; const errorCause = new ZodError(Object.values(result.errors).flatMap((error) => error.issues)); return { success: false, error: new ParseError(errorMessage, { cause: errorCause }), originalEvent: data, }; }, };