Custom Add-On Api.
Table of Contents
- Overview
- Example of a Custom SFDMU Add-On Module
- How to Try This Module
- Full Specification of the Add-On Event Declaration
- List of Supported Add-On Events and the Execution Lifecycle
- How to Create and Run Your Own Custom SFDMU Add-On Module
- How to Debug the Custom Add-On Module
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.