diff --git a/src/v0/destinations/marketo_static_list/transform.js b/src/v0/destinations/marketo_static_list/transform.js index 976db8d740..1faae70443 100644 --- a/src/v0/destinations/marketo_static_list/transform.js +++ b/src/v0/destinations/marketo_static_list/transform.js @@ -6,7 +6,7 @@ const { generateErrorObject, } = require('../../util'); const { AUTH_CACHE_TTL, JSON_MIME_TYPE } = require('../../util/constant'); -const { getIds, validateMessageType } = require('./util'); +const { getIds, validateMessageType, transformForRecordEvent } = require('./util'); const { getDestinationExternalID, defaultRequestConfig, @@ -16,7 +16,7 @@ const { const { formatConfig, MAX_LEAD_IDS_SIZE } = require('./config'); const Cache = require('../../util/cache'); const { getAuthToken } = require('../marketo/transform'); -const { InstrumentationError, UnauthorizedError } = require('../../util/errorTypes'); +const { InstrumentationError, UnauthorizedError, AbortedError } = require('../../util/errorTypes'); const authCache = new Cache(AUTH_CACHE_TTL); // 1 hr @@ -71,9 +71,13 @@ const processEvent = (input) => { toRemove = getIds(message.properties.listData.remove); } if ( - (Array.isArray(toAdd) && toAdd.length > 0) || - (Array.isArray(toRemove) && toRemove.length > 0) + (!Array.isArray(toAdd) || toAdd.length === 0) && + (!Array.isArray(toRemove) || toRemove.length === 0) ) { + throw new InstrumentationError( + 'Invalid leadIds format or no leadIds found neither to add nor to remove', + ); + } else { if (Array.isArray(toRemove) && toRemove.length > 0) { const payload = batchResponseBuilder(message, Config, token, toRemove, 'remove'); if (payload) { @@ -86,47 +90,44 @@ const processEvent = (input) => { response.push(...payload); } } - } else { - throw new InstrumentationError( - 'Invalid leadIds format or no leadIds found neither to add nor to remove', - ); } return response; }; -function transformForRecordEvent(inputs, leadIdObj) { - const finalMetadata = []; - // iterate through each inputs metadata and create a final metadata - const tokenisedInputs = inputs.map((input) => { - const { message } = input; - const { metadata } = input; - finalMetadata.push(metadata); - const { fields, action } = message; - if (!message.properties) { - message.properties = {}; - } - if (!message.properties.listData) { - message.properties.listData = { add: [], remove: [] }; - } - // message.properties.listData = message.properties.listData || { add: [], remove: [] }; - if (action === 'insert') { - leadIdObj.insert.push({ id: fields.id }); - message.properties.listData.add.push({ id: fields.id }); - } else if (action === 'delete') { - leadIdObj.delete.push({ id: fields.id }); - message.properties.listData.remove.push({ id: fields.id }); - } else { - throw new InstrumentationError('Invalid action type'); - } - return input; - }); - const finalInput = [tokenisedInputs[0]]; - finalInput[0].metadata = finalMetadata; - finalInput[0].message.properties.listData.add = leadIdObj.insert; - finalInput[0].message.properties.listData.remove = leadIdObj.delete; +// function transformForRecordEvent(inputs, leadIdObj) { +// const finalMetadata = []; +// // iterate through each inputs metadata and create a final metadata +// const tokenisedInputs = inputs.map((input) => { +// const { message } = input; +// const { metadata } = input; +// finalMetadata.push(metadata); +// const { fields, action } = message; +// if (!message.properties) { +// message.properties = {}; +// } +// if (!message.properties.listData) { +// message.properties.listData = { add: [], remove: [] }; +// } +// // message.properties.listData = message.properties.listData || { add: [], remove: [] }; +// const fieldsId = fields.id; +// if (action === 'insert') { +// leadIdObj.insert.push({ id: fieldsId }); +// message.properties.listData.add.push({ id: fieldsId }); +// } else if (action === 'delete') { +// leadIdObj.delete.push({ id: fieldsId }); +// message.properties.listData.remove.push({ id: fieldsId }); +// } else { +// throw new InstrumentationError('Invalid action type'); +// } +// return input; +// }); +// const finalInput = [tokenisedInputs[0]]; +// finalInput[0].metadata = finalMetadata; +// finalInput[0].message.properties.listData.add = leadIdObj.insert; +// finalInput[0].message.properties.listData.remove = leadIdObj.delete; - return finalInput; -} +// return finalInput; +// } const process = async (event) => { const token = await getAuthToken(formatConfig(event.destination)); @@ -146,19 +147,20 @@ const processRouterDest = async (inputs, reqMetadata) => { try { token = await getAuthToken(formatConfig(inputs[0].destination)); if (!token) { - const errResp = { - status: 400, - message: 'Authorisation failed', - responseTransformFailure: true, - statTags: {}, - }; - const respEvents = getErrorRespEvents( - inputs.map((input) => input.metadata), - errResp.status, - errResp.message, - errResp.statTags, - ); - return [{ ...respEvents, destination: inputs?.[0]?.destination }]; + throw new AbortedError('Could not retrieve authorisation token', 400); + // const errResp = { + // status: 400, + // message: 'Authorisation failed', + // responseTransformFailure: true, + // statTags: {}, + // }; + // const respEvents = getErrorRespEvents( + // inputs.map((input) => input.metadata), + // errResp.status, + // errResp.message, + // errResp.statTags, + // ); + // return [{ ...respEvents, destination: inputs?.[0]?.destination }]; } } catch (error) { // Not using handleRtTfSingleEventError here as this is for multiple events @@ -181,7 +183,7 @@ const processRouterDest = async (inputs, reqMetadata) => { delete: [], }; let finalInputForRecordEvent; - if (inputs[0].message.channel === 'sources') { + if (inputs[0].message.channel === 'sources' && inputs[0].message.type === 'record') { finalInputForRecordEvent = transformForRecordEvent(tokenisedInputs, leadIdObj); respList = await simpleProcessRouterDest(finalInputForRecordEvent, processEvent, reqMetadata); } else { diff --git a/src/v0/destinations/marketo_static_list/util.js b/src/v0/destinations/marketo_static_list/util.js index 2d4fe493a0..4427891640 100644 --- a/src/v0/destinations/marketo_static_list/util.js +++ b/src/v0/destinations/marketo_static_list/util.js @@ -34,7 +34,47 @@ const validateMessageType = (message, allowedTypes) => { } }; +function transformForRecordEvent(inputs, leadIdObj) { + const finalMetadata = []; + // iterate through each inputs metadata and create a final metadata + const tokenisedInputs = inputs.map((input) => { + const { message } = input; + const { metadata } = input; + finalMetadata.push(metadata); + const { fields, action } = message; + let { properties } = message; + if (!properties) { + properties = {}; + } + if (!properties.listData) { + properties.listData = { add: [], remove: [] }; + } + // message.properties.listData = message.properties.listData || { add: [], remove: [] }; + const fieldsId = fields?.id; + if (fieldsId === undefined) { + throw new InstrumentationError('No lead id passed in the payload.'); + } + if (action === 'insert') { + leadIdObj.insert.push({ id: fieldsId }); + properties.listData.add.push({ id: fieldsId }); + } else if (action === 'delete') { + leadIdObj.delete.push({ id: fieldsId }); + properties.listData.remove.push({ id: fieldsId }); + } else { + throw new InstrumentationError('Invalid action type'); + } + return input; + }); + const finalInput = [tokenisedInputs[0]]; + finalInput[0].metadata = finalMetadata; + finalInput[0].message.properties.listData.add = leadIdObj.insert; + finalInput[0].message.properties.listData.remove = leadIdObj.delete; + + return finalInput; +} + module.exports = { getIds, validateMessageType, + transformForRecordEvent, }; diff --git a/src/v0/destinations/marketo_static_list/util.test.js b/src/v0/destinations/marketo_static_list/util.test.js new file mode 100644 index 0000000000..b8bb1e216d --- /dev/null +++ b/src/v0/destinations/marketo_static_list/util.test.js @@ -0,0 +1,239 @@ +const { InstrumentationError } = require('../../util/errorTypes'); +const { + transformForRecordEvent, +} = require('../../../../src/v0/destinations/marketo_static_list/util'); + +describe('transformForRecordEvent', () => { + // Should correctly transform an input with action 'insert' + test('should correctly transform an input with action "insert"', () => { + const inputs = [ + { + message: { + fields: { id: 1 }, + action: 'insert', + properties: { listData: { add: [], remove: [] } }, + }, + metadata: 'metadata1', + }, + ]; + const leadIdObj = { insert: [], delete: [] }; + const expectedOutput = [ + { + message: { + fields: { id: 1 }, + action: 'insert', + properties: { listData: { add: [{ id: 1 }], remove: [] } }, + }, + metadata: ['metadata1'], + }, + ]; + + const result = transformForRecordEvent(inputs, leadIdObj); + + expect(result).toEqual(expectedOutput); + }); + + // Should correctly transform an input with action 'delete' + test('should correctly transform an input with action "delete"', () => { + const inputs = [ + { + message: { + fields: { id: 1 }, + action: 'delete', + properties: { listData: { add: [], remove: [] } }, + }, + metadata: 'metadata1', + }, + ]; + const leadIdObj = { insert: [], delete: [] }; + const expectedOutput = [ + { + message: { + fields: { id: 1 }, + action: 'delete', + properties: { listData: { add: [], remove: [{ id: 1 }] } }, + }, + metadata: ['metadata1'], + }, + ]; + + const result = transformForRecordEvent(inputs, leadIdObj); + + expect(result).toEqual(expectedOutput); + }); + + // Should raise an InstrumentationError if action is not valid + test('should raise an InstrumentationError if action is not valid', () => { + const inputs = [ + { + message: { + fields: { id: 1 }, + action: 'invalid', + properties: { listData: { add: [], remove: [] } }, + }, + metadata: 'metadata1', + }, + ]; + const leadIdObj = { insert: [], delete: [] }; + + expect(() => { + transformForRecordEvent(inputs, leadIdObj); + }).toThrow(InstrumentationError); + }); + + // Should raise an InstrumentationError on input with no fields + test('should raise an InstrumentationError on input with no fields', () => { + const inputs = [ + { + message: { + action: 'insert', + properties: { listData: { add: [], remove: [] } }, + }, + metadata: 'metadata1', + }, + ]; + const leadIdObj = { insert: [], delete: [] }; + + expect(() => { + transformForRecordEvent(inputs, leadIdObj); + }).toThrow(InstrumentationError); + }); + + // Should correctly transform an input with 2 insert payloads + test('should correctly transform an input with 2 insert payloads', () => { + const inputs = [ + { + message: { + type: 'record', + fields: { id: 1 }, + action: 'insert', + properties: { listData: { add: [], remove: [] } }, + }, + metadata: 'metadata1', + }, + { + message: { + type: 'record', + fields: { id: 2 }, + action: 'insert', + properties: { listData: { add: [], remove: [] } }, + }, + metadata: 'metadata2', + }, + ]; + const leadIdObj = { insert: [], delete: [] }; + const expectedOutput = [ + { + message: { + type: 'record', + fields: { id: 1 }, + action: 'insert', + properties: { listData: { add: [{ id: 1 }, { id: 2 }], remove: [] } }, + }, + metadata: ['metadata1', 'metadata2'], + }, + ]; + + const result = transformForRecordEvent(inputs, leadIdObj); + + expect(result).toEqual(expectedOutput); + }); + + // Should correctly transform an input with 2 delete payloads + test('should correctly transform an input with 2 delete payloads', () => { + const inputs = [ + { + message: { + type: 'record', + fields: { id: 1 }, + action: 'delete', + properties: { listData: { add: [], remove: [] } }, + }, + metadata: 'metadata1', + }, + { + message: { + type: 'record', + fields: { id: 2 }, + action: 'delete', + properties: { listData: { add: [], remove: [] } }, + }, + metadata: 'metadata2', + }, + ]; + const leadIdObj = { insert: [], delete: [] }; + const expectedOutput = [ + { + message: { + type: 'record', + fields: { id: 1 }, + action: 'delete', + properties: { listData: { remove: [{ id: 1 }, { id: 2 }], add: [] } }, + }, + metadata: ['metadata1', 'metadata2'], + }, + ]; + + const result = transformForRecordEvent(inputs, leadIdObj); + + expect(result).toEqual(expectedOutput); + }); + + // Should correctly transform an input with 2 insert and 2 delete payloads + test('should correctly transform an input with 2 insert and 2 delete payloads', () => { + const inputs = [ + { + message: { + type: 'record', + fields: { id: 1 }, + action: 'delete', + properties: { listData: { add: [], remove: [] } }, + }, + metadata: 'metadata1', + }, + { + message: { + type: 'record', + fields: { id: 2 }, + action: 'insert', + properties: { listData: { add: [], remove: [] } }, + }, + metadata: 'metadata2', + }, + { + message: { + type: 'record', + fields: { id: 3 }, + action: 'delete', + properties: { listData: { add: [], remove: [] } }, + }, + metadata: 'metadata3', + }, + { + message: { + type: 'record', + fields: { id: 4 }, + action: 'insert', + properties: { listData: { add: [], remove: [] } }, + }, + metadata: 'metadata4', + }, + ]; + const leadIdObj = { insert: [], delete: [] }; + const expectedOutput = [ + { + message: { + type: 'record', + fields: { id: 1 }, + action: 'delete', + properties: { listData: { remove: [{ id: 1 }, { id: 3 }], add: [{ id: 2 }, { id: 4 }] } }, + }, + metadata: ['metadata1', 'metadata2', 'metadata3', 'metadata4'], + }, + ]; + + const result = transformForRecordEvent(inputs, leadIdObj); + + expect(result).toEqual(expectedOutput); + }); +});