Custom Add-On Api.


Table of Contents



Overview

The Custom SFDMU Add-On API empowers developers to create bespoke extensions, significantly expanding the functionality of SFDMU. This API allows for the integration of an unlimited variety of custom features, specifically tailored to meet unique business requirements.

Built on the foundational principles of the SFDMU Add-On API Engine, it provides a robust framework for enhancing SFDMU's capabilities through personalized modifications.

Example of a Custom SFDMU Add-On Module

The source code for a test custom Add-On module is included with SFDMU's source code. This module serves as a foundational example for developing your own modules. It performs a straightforward modification to the source records just before they are uploaded to the target Salesforce environment.

Below is the sample code:

// Imports interfaces for custom Add-On module, context, result, and runtime from a package
import { ISfdmuRunCustomAddonContext, ISfdmuRunCustomAddonModule, ISfdmuRunCustomAddonResult, ISfdmuRunCustomAddonRuntime } from "../package";

/**
 * Defines a class implementing ISfdmuRunCustomAddonModule for custom manipulations of source records
 * before uploading to the Target system.
 */
export default class SfdmuCustomAddOnModule implements ISfdmuRunCustomAddonModule {

    /**
     * Constructor that initializes the Add-On module with the provided runtime from the Plugin.
     * @param {ISfdmuRunCustomAddonRuntime} runtime - Runtime provided by the Plugin to interact with the module.
     */
    constructor(runtime: ISfdmuRunCustomAddonRuntime) {
        this.runtime = runtime; // Assigns the passed runtime to this class's runtime property.
    }

    /**
     * The current instance of the Add-On module runtime to interact with the Salesforce Data Migration Utility (SFDMU) Plugin.
     */
    runtime: ISfdmuRunCustomAddonRuntime;

    /**
     * The main method that executes the custom logic for manipulating source records.
     * @param {ISfdmuRunCustomAddonContext} context - Provides context like module display name and event name.
     * @param {any} args - Arbitrary arguments that might be passed to the module for processing.
     * @returns {Promise<ISfdmuRunCustomAddonResult>} A promise resolving to null to continue the job.
     */
    async onExecute(context: ISfdmuRunCustomAddonContext, args: any): Promise<ISfdmuRunCustomAddonResult> {

        // Logs the start of the module execution
        this.runtime.service.log(this, `The Add-On module ${context.moduleDisplayName} has been successfully started. The event ${context.eventName} has been fired.`);

        // Logs a blank line for readability in the log output
        this.runtime.service.log(this, ''); // Prints new line
        // Logs a message indicating that arguments are about to be displayed
        this.runtime.service.log(this, 'The arguments are:'); // Prints string
        // Logs the passed arguments as formatted JSON
        this.runtime.service.log(this, args, "JSON"); // Prints object as formatted JSON
        // Logs another blank line for readability in the log output
        this.runtime.service.log(this, ''); // Prints new line

        // Retrieves the processed data relevant to the current context
        const data = this.runtime.service.getProcessedData(context);

        // Manipulates the source records based on the retrieved data and arguments
        [].concat(data.recordsToInsert, data.recordsToUpdate).forEach(record => {
            // Attempts to parse a 'LongText__c' field to JSON, or uses an empty JSON object as fallback
            const jsonString = String(record['LongText__c']) || '{}';
            // Parses the JSON string into an object
            if (jsonString) {
                const obj = JSON.parse(jsonString);
                // Assigns a value from the parsed object to 'TEST1__c' field of the record
                record['TEST1__c'] = obj['TEST1__c'];
            }
            // Iterates over args if they exist and assigns their properties to the current record
            if (args) {
                Object.keys(args).forEach(function (prop) {
                    record[prop] = args[prop];
                });
            }
        });

        // Logs the completion of the module execution
        this.runtime.service.log(this, `The Add-On module ${context.moduleDisplayName} has been successfully completed.`);

        // Returns null to indicate that the migration job should continue
        return null;
    }
}

How to Try This Module

Step 1: Install

Install the SFDMU source code.

Step 2: Compile

Navigate to the directory where the SFDMU source code is cloned and compile the project:

cd C:\SFDX-Data-Move-Utility
npm run build

Step 3: Create Root Directory and Copy Necessary Files

Create the root directory C:\MySfdmuAddOns for all custom Add-On modules.

Copy the compiled component's source from C:\SFDX-Data-Move-Utility\lib\addons\modules\sfdmu-run\custom-addons\CustomSfdmuRunAddonTemplate and the SFDMU Add-On Runtime Library package from C:\SFDX-Data-Move-Utility\lib\addons\modules\sfdmu-run\custom-addons\package to this directory.

The target directory structure should look as follows:

|-- C:\MySfdmuAddOns
    |-- CustomSfdmuRunAddonTemplate
    |   |-- index.d.ts
    |   |-- index.js
    |   |-- index.js.map
    |-- custom_module_1
    |-- custom_module_2
    |-- other custom modules
    |-- package
        |-- common.js
        |-- index.js
        |-- other package files
Notes
  • The /package folder does not need to be updated every time you create or compile your modules, only when a new release of SFDMU is pushed.
  • The essential file for a custom module is index.js (and its TypeScript source, index.ts), which serves as the main entry point and is executed by the SFDMU Plugin when a migration job starts.

Step 4: Create New export.json File

Create a new export.json file with the required content and place it in C:\SFDMU\CustomSfdmuRunAddonTemplate:

{
    "objects": [
        {
            "operation": "Upsert",
            "externalId": "Name",
            "deleteOldData": true,
            "query": "SELECT Id, Name, LongText__c, TEST__c, TEST1__c FROM Account WHERE Name = 'ACC_10000'",
            "beforeUpdateAddons": [
                {
                    "description": "This example of the Custom SFDMU AddOn module manipulates the source Account records right before the target SF object is updated. It extracts the value from the JSON stored in the LongText__c, then puts the extracted string into the TEST1__c.",
                    "path": "C:\\MySfdmuAddOns\\CustomSfdmuRunAddonTemplate",
                    "args": {
                        "TEST__c": "Another small manipulation with the source data: we want to populate the TEST__c field of each record with this constant text."
                    }
                }
            ]
        }
    ]
}

Step 5: Create New Custom Fields

In both the Source and Target Salesforce orgs, add three new custom fields to the Account object:

  • LongText__c: Long Text Area (32768)
  • TEST__c: Text (255)
  • TEST1__c: Text (255)

Step 6: Create New Account Record

Create a new Account record in the Source Salesforce org with the following values:

  • Name: "ACC_10000"
  • LongText__c: "{"TEST1__c": "Test Value"}"
  • Leave the fields TEST__c and TEST1__c blank as they will be populated on the fly using our Add-On module.

Step 7: Launch the Migration Job

Launch the SFDMU with the created export.json file:

sf sfdmu run --sourceusername source@name.com --targetusername target@name.com --path C:\\SFDMU\CustomSfdmuRunAddonTemplate

Step 8: Check the Results

After the job is completed, verify that the migration job was done correctly and the Add-On has worked as expected:

  • Open the Target Salesforce Org, then locate the Account record with the Name ACC_10000.

  • Click the "Details" tab to see the populated fields:

    LongText__c: "{"TEST1__c": "Test Value"}"
    TEST__c: "Another small manipulation with the source data: we want to populate the TEST__c field of each record with this constant text."
    TEST1__c: "Test Value"
    

Full Specification of the Add-On Event Declaration

Property Name Is Mandatory? Data Type Description
description No string The description of the module, passed to the Add-On instance using the module runtime context object.
path Yes string The absolute or relative path to the directory where the compiled module is located. Absolute paths are recommended to ensure the Plugin locates the module correctly.
args No Object An optional object passed as-is to the module's onExecute method using the args parameter. Use this for customized initialization of the Add-On instance via the export.json.

List of Supported Add-On Events and the Execution Lifecycle

For more information, see: Supported Add-On API Events

How to Create and Run Your Own Custom SFDMU Add-On Module

Create and compile a new module named TestModule using the same directory structure as described previously.

Step 1: Create Module Directory

Create a new subdirectory TestModule under C:\SFDX-Data-Move-Utility\src\addons\modules\sfdmu-run\custom-addons and create a new index.ts file inside it. Design your module's code inside this file.

Step 2: Compile

Compile the module using the following commands:

cd C:\SFDX-Data-Move-Utility
npm run build

Step 3: Copy Files to the Module Directory

Copy the compiled module component files to the root module folder C:\MySfdmuAddOns\TestModule.

Step 4: Create New export.json File

Create a new export.json file with the following content and place it in C:\SFDMU\TestModule:

{
    "objects": [
        {
            "operation": "Insert",
            "query": "SELECT Name FROM Account WHERE Name = 'ACC_10000'",
            "beforeUpdateAddons": [
                {
                    "path": "C:\\MySfdmuAddOns\\TestModule"
                }
            ]
        }
    ]
}
Notes:
  • The example above utilizes the beforeUpdateAddons event hook, but you can use any other event hook based on your needs.
  • Remember to provide the args parameter if your module requires it.

Step 5: Launch the Migration Job

Launch the SFDMU with the specified export.json file:

sf sfdmu run --sourceusername source@name.com --targetusername target@name.com --path C:\SFDMU\TestModule

Step 6: Check the Results

Verify the results after the job is completed.

How to Debug the Custom Add-On Module

Debug the custom Add-On module alongside the entire SFDMU Plugin by placing breakpoints in the module code and running the Plugin in debug mode.

Last updated on 23rd Apr 2024