Skip to content

Commit

Permalink
Merge pull request #962 from ashitsalesforce/master
Browse files Browse the repository at this point in the history
poloymorphic relationship support in Bulk
  • Loading branch information
ashitsalesforce authored Feb 5, 2024
2 parents b83695d + 1e1040a commit 9a37256
Show file tree
Hide file tree
Showing 8 changed files with 266 additions and 111 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
import com.salesforce.dataloader.dao.DataReader;
import com.salesforce.dataloader.dao.DataWriter;
import com.salesforce.dataloader.dao.csv.CSVFileReader;
import com.salesforce.dataloader.dyna.RelationshipField;
import com.salesforce.dataloader.exception.DataAccessObjectException;
import com.salesforce.dataloader.exception.DataAccessObjectInitializationException;
import com.salesforce.dataloader.exception.LoadException;
Expand Down Expand Up @@ -280,7 +281,27 @@ private static void addFieldToBatchRequestHeader(PrintStream serverRequestOutput
if (!first) {
serverRequestOutput.print(',');
}
serverRequestOutput.print(sfdcColumn.replace(':', '.'));
// Make sure that relationship field header is in the formats
// specified at https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/datafiles_csv_rel_field_header_row.htm
// Format for Polymorphic relations: ObjectType:RelationshipName.IndexedFieldName
// Format for single parent type relations: RelationshipName.IndexedFieldName
String sfdcColumnForBulk = sfdcColumn;
if (RelationshipField.isRelationshipFieldMapping(sfdcColumn)) {
RelationshipField relField = new RelationshipField(sfdcColumn, true);
if (relField.getParentObjectName() == null) {
if (relField.getParentFieldName() == null) {
sfdcColumnForBulk = relField.getRelationshipName();
} else {
sfdcColumnForBulk = relField.getRelationshipName()
+ "." + relField.getParentFieldName();
}
} else {
sfdcColumnForBulk = relField.getParentObjectName()
+ ":" + relField.getRelationshipName()
+ "." + relField.getParentFieldName();
}
}
serverRequestOutput.print(sfdcColumnForBulk);
cols.add(sfdcColumn);
addedCols.add(sfdcColumn);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public RelationshipField(String parentObjectName, String relationshipName) {
}

// fieldName param can be in one of the following formats:
// format 1: alphanumeric string without any ':' or '#' in it. Represents name of child's non-polymorphic relationship field
// format 1: alphanumeric string without any ':' or '-' in it. Represents name of child's non-polymorphic relationship field
// format 1 => it is name of a non-polymorphic relationship field in child object.
//
// format 2: alphanumeric string with a ':' in it
Expand All @@ -67,7 +67,7 @@ public RelationshipField(String parentObjectName, String relationshipName) {
// - this is the new format for keys of the hashmap referenceEntitiesDescribeMap
// interpretation 2 (legacy format): <child relationship field name>:<parent idlookup field name>
//
// format 3: alphanumeric string with a single ':' and a single '#' in it
// format 3: alphanumeric string with a single ':' and a single '-' in it
// format 3 => it is name of a field in child object with reference to an idlookup field in parent object
//
// Given 2 interpretations of format 2, an additional parameter, 'isFieldName', is required.
Expand All @@ -92,12 +92,12 @@ public RelationshipField(String fieldName, boolean hasParentIdLookupFieldName) {
relationshipName = fieldNameParts[0];
parentObjectName = fieldNameParts[1];
}
} else { // Should not happen - no ':' char in name, may have '#' char
} else { // Should not happen - no ':' char in name, may have '-' char
if (parentFieldName == null) { // no ':' and no '.' in name
logger.error("field name " + fieldName + " does not have ':' or '.' char" );
logger.error("field name " + fieldName + " does not have ':' or '-' char" );
} else {
// '#' char in name but no ':'
logger.error("field name " + fieldName + " has '.' but does not have ':' char" );
// '-' char in name but no ':'
logger.error("field name " + fieldName + " has '-' but does not have ':' char" );
}
}
} else { // format 1 or format 2, interpretation 1
Expand Down Expand Up @@ -163,6 +163,19 @@ static public String formatAsString(String parentObjectName, String relationship
+ parentIDLookupFieldName;
}

static public boolean isRelationshipFieldMapping(String fieldName) {
if (fieldName == null || fieldName.isBlank()) {
return false;
}
if (fieldName.contains(NEW_FORMAT_PARENT_IDLOOKUP_FIELD_SEPARATOR_CHAR)) {
if (fieldName.contains(NEW_FORMAT_RELATIONSHIP_NAME_SEPARATOR_CHAR)) {
return true;
}
} else if (fieldName.contains(OLD_FORMAT_PARENT_IDLOOKUP_FIELD_SEPARATOR_CHAR)) {
return true;
}
return false;
}

/* (non-Javadoc)
* @see java.lang.Object#toString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ public void deleteSfdcRecords(String entityName, String whereClause,
entitySpecificClause = TESTFIELD_WHERE_CLAUSE;
break;
}
if (!whereClause.contains(entitySpecificClause)) {
if (whereClause == null || !whereClause.contains(entitySpecificClause)) {
if (whereClause == null || whereClause.isBlank()) {
whereClause = entitySpecificClause;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -480,29 +480,6 @@ private void doUpsertContact(boolean upsertFk) throws Exception {
}
}

private void doUpsert(String entity, Map<String, Object> sforceMapping) throws Exception {
// now convert to a dynabean array for the client
// setup our dynabeans
BasicDynaClass dynaClass = setupDynaClass(entity);

DynaBean sforceObj = dynaClass.newInstance();

// This does an automatic conversion of types.
BeanUtils.copyProperties(sforceObj, sforceMapping);

List<DynaBean> beanList = new ArrayList<DynaBean>();
beanList.add(sforceObj);

// get the client and make the insert call
PartnerClient client = new PartnerClient(getController());
UpsertResult[] results = client.loadUpserts(beanList);
for (UpsertResult result : results) {
if (!result.getSuccess()) {
Assert.fail("Upsert returned an error: " + result.getErrors()[0].getMessage());
}
}
}

/**
* Basic failing - forgetting the external id or foreign key external id
*/
Expand Down Expand Up @@ -651,68 +628,4 @@ private String getRandomAccountId() throws ConnectionException {

return records[0].getId();
}

/**
* Make sure to set external id field
*/
private String setExtIdField(String extIdField) {
getController().getConfig().setValue(Config.EXTERNAL_ID_FIELD, extIdField);
return extIdField;
}

/**
* Get a random account external id for upsert testing
*
* @param entity
* TODO
* @param whereClause
* TODO
* @param prevValue
* Indicate that the value should be different from the specified
* value or null if uniqueness not required
* @return String Account external id value
*/
private Object getRandomExtId(String entity, String whereClause, Object prevValue) throws ConnectionException {

// insert couple of accounts so there're at least two records to work with
upsertSfdcRecords(entity, 2);

// get the client and make the query call
String extIdField = getController().getConfig().getString(Config.EXTERNAL_ID_FIELD);
PartnerClient client = new PartnerClient(getController());
// only get the records that have external id set, avoid nulls
String soql = "select " + extIdField + " from " + entity + " where " + whereClause + " and " + extIdField
+ " != null";
if (prevValue != null) {
soql += " and "
+ extIdField
+ "!= "
+ (prevValue.getClass().equals(String.class) ? ("'" + prevValue + "'") : String
.valueOf(prevValue));
}
QueryResult result = client.query(soql);
SObject[] records = result.getRecords();
assertNotNull("Operation should return non-null values", records);
assertTrue("Operation should return 1 or more records", records.length > 0);
assertNotNull("Records should have non-null field: " + extIdField + " values", records[0]
.getField(extIdField));

return records[0].getField(extIdField);
}

private BasicDynaClass setupDynaClass(String entity) throws ConnectionException {
getController().getConfig().setValue(Config.ENTITY, entity);
PartnerClient client = getController().getPartnerClient();
if (!client.isLoggedIn()) {
client.connect();
}

getController().setFieldTypes();
getController().setReferenceDescribes();
DynaProperty[] dynaProps = SforceDynaBean.createDynaProps(getController().getPartnerClient().getFieldTypes(), getController());
BasicDynaClass dynaClass = SforceDynaBean.getDynaBeanInstance(dynaProps);
SforceDynaBean.registerConverters(getController().getConfig());
return dynaClass;
}

}
Loading

0 comments on commit 9a37256

Please sign in to comment.