Skip to content

Commit a7e506b

Browse files
committed
fix: option to use #N/A to clear the target field and null to retain it in Bulk API 2.0.
1 parent 0b55f30 commit a7e506b

File tree

5 files changed

+56
-13
lines changed

5 files changed

+56
-13
lines changed

src/modules/components/api_engines/bulkApiV1_0Engine.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ export class BulkApiV1_0Engine extends ApiEngineBase implements IApiEngine {
4646
}
4747

4848
async createCRUDApiJobAsync(allRecords: Array<any>): Promise<IApiJobCreateResult> {
49+
50+
this._fixRecords(allRecords);
51+
4952
let connection = Sfdx.createOrgConnection(this.connectionData);
5053
connection.bulk.pollTimeout = CONSTANTS.POLL_TIMEOUT;
5154
let job = connection.bulk.createJob(
@@ -212,5 +215,14 @@ export class BulkApiV1_0Engine extends ApiEngineBase implements IApiEngine {
212215

213216

214217
// ----------------------- ---------------- -------------------------------------------
218+
private _fixRecords(allRecords: Array<any>) {
219+
allRecords.forEach(record => {
220+
Object.keys(record).forEach(key => {
221+
if (record[key] === '#N/A') {
222+
record[key] = null;
223+
}
224+
});
225+
});
226+
}
215227

216228
}

src/modules/components/api_engines/restApiEngine.ts

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77

88
import { CsvChunks } from '../../models';
99
import {
10-
ApiEngineBase,
11-
ApiInfo,
12-
IApiEngineInitParameters,
10+
ApiEngineBase,
11+
ApiInfo,
12+
IApiEngineInitParameters,
1313
} from '../../models/api_models';
1414
import {
15-
IApiEngine,
16-
IApiJobCreateResult,
17-
ICsvChunk,
15+
IApiEngine,
16+
IApiJobCreateResult,
17+
ICsvChunk,
1818
} from '../../models/api_models/helper_interfaces';
1919
import { Common } from '../common_components/common';
2020
import { OPERATION } from '../common_components/enumerations';
@@ -42,9 +42,12 @@ export class RestApiEngine extends ApiEngineBase implements IApiEngine {
4242
}
4343

4444
async createCRUDApiJobAsync(allRecords: Array<any>): Promise<IApiJobCreateResult> {
45+
46+
this._fixRecords(allRecords);
47+
4548
let connection = Sfdx.createOrgConnection(this.connectionData);
4649
let chunks: CsvChunks;
47-
if (!this.restApiBatchSize){
50+
if (!this.restApiBatchSize) {
4851
chunks = new CsvChunks().fromArray(this.getSourceRecordsArray(allRecords));
4952
} else {
5053
let recordChunks = Common.chunkArray(this.getSourceRecordsArray(allRecords), this.restApiBatchSize);
@@ -139,7 +142,7 @@ export class RestApiEngine extends ApiEngineBase implements IApiEngine {
139142
}
140143
});
141144
if (progressCallback) {
142-
if (self.numberJobRecordsFailed > 0) {
145+
if (self.numberJobRecordsFailed > 0) {
143146
// Some records are failed
144147
progressCallback(new ApiInfo({
145148
jobState: "JobComplete",
@@ -150,7 +153,7 @@ export class RestApiEngine extends ApiEngineBase implements IApiEngine {
150153
}));
151154
}
152155
// Progress message: operation finished
153-
if (self.numberJobRecordProcessed == self.numberJobTotalRecordsToProcess){
156+
if (self.numberJobRecordProcessed == self.numberJobTotalRecordsToProcess) {
154157
progressCallback(new ApiInfo({
155158
jobState: "OperationFinished",
156159
numberRecordsProcessed: self.numberJobRecordProcessed,
@@ -159,7 +162,7 @@ export class RestApiEngine extends ApiEngineBase implements IApiEngine {
159162
batchId: apiInfo.batchId
160163
}));
161164
} else {
162-
progressCallback (new ApiInfo({
165+
progressCallback(new ApiInfo({
163166
jobState: "InProgress",
164167
numberRecordsProcessed: self.numberJobRecordProcessed,
165168
numberRecordsFailed: self.numberJobRecordsFailed,
@@ -177,7 +180,17 @@ export class RestApiEngine extends ApiEngineBase implements IApiEngine {
177180
getEngineClassType(): typeof ApiEngineBase {
178181
return RestApiEngine;
179182
}
183+
180184
// ----------------------- ---------------- -------------------------------------------
185+
private _fixRecords(allRecords: Array<any>) {
186+
allRecords.forEach(record => {
187+
Object.keys(record).forEach(key => {
188+
if (record[key] === '#N/A') {
189+
record[key] = null;
190+
}
191+
});
192+
});
193+
}
181194

182195

183196

src/modules/components/common_components/common.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -803,9 +803,6 @@ export class Common {
803803
if (context.header || typeof context.column == "undefined") {
804804
return value;
805805
}
806-
if (value == "#N/A") {
807-
return null;
808-
}
809806
let fieldType = columnToColumnDataTypeMap && columnToColumnDataTypeMap.get(context.column);
810807
if (fieldType == "boolean") {
811808
if (value == "1" || value == "TRUE" || value == "true")

src/modules/models/job_models/migrationJobTask.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,6 +1293,10 @@ export default class MigrationJobTask {
12931293
processedData.recordsToInsert = __filterInserts(processedData.recordsToInsert);
12941294
processedData.recordsToUpdate = __filterUpdates(processedData.recordsToUpdate);
12951295

1296+
// Final data transforation (for example to set #N/A values)
1297+
__finalDataTransformation(processedData.recordsToInsert);
1298+
__finalDataTransformation(processedData.recordsToUpdate);
1299+
12961300
}
12971301

12981302
return processedData;
@@ -1606,6 +1610,19 @@ export default class MigrationJobTask {
16061610
return records;
16071611
}
16081612

1613+
1614+
function __finalDataTransformation(records: Array<any>): void {
1615+
if (self.script.sourceOrg.isOrgMedia) {
1616+
records.forEach(record => {
1617+
Object.keys(record).forEach(fieldName => {
1618+
if (record[fieldName] == null) {
1619+
record[fieldName] = '#N/A';
1620+
}
1621+
});
1622+
});
1623+
}
1624+
}
1625+
16091626
function ___truncateRecords(records: Array<any>): Array<any> {
16101627
if (records.length == 0) {
16111628
return records;

src/modules/models/script_models/scriptOrg.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ export default class ScriptOrg implements IAppScriptOrg, ISfdmuRunCustomAddonScr
7878
return this.media == DATA_MEDIA_TYPE.File;
7979
}
8080

81+
get isOrgMedia(): boolean {
82+
return this.media == DATA_MEDIA_TYPE.Org;
83+
}
84+
8185
get isDescribed(): boolean {
8286
return this.orgDescribe.size > 0;
8387
}

0 commit comments

Comments
 (0)