Add mass copy fields feature (#80)
The new copyField method can copy field values in bulk from one domain to another related domain
This commit is contained in:
@@ -734,17 +734,7 @@ public virtual class fflib_SObjects2
|
||||
*/
|
||||
@TestVisible
|
||||
protected virtual Map<Id, Object> getFieldValueByIdField(SObjectField valueField, SObjectField keyField) {
|
||||
Map<Id, Object> result = new Map<Id, Object>();
|
||||
for (SObject record : getRecords())
|
||||
{
|
||||
if (record.get(keyField) == null) continue;
|
||||
|
||||
result.put(
|
||||
(Id) record.get(keyField),
|
||||
record.get(valueField)
|
||||
);
|
||||
}
|
||||
return result;
|
||||
return fflib_ArrayUtils.getValueById(this, valueField, keyField);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1437,14 +1427,7 @@ public virtual class fflib_SObjects2
|
||||
Schema.SObjectField sObjectFieldToUpdate,
|
||||
Map<Id, Object> values)
|
||||
{
|
||||
for (SObject record : getRecords())
|
||||
{
|
||||
Id keyValue = (Id) record.get(sObjectIdFieldToCheck);
|
||||
if (values?.containsKey(keyValue))
|
||||
{
|
||||
record.put(sObjectFieldToUpdate, values.get(keyValue));
|
||||
}
|
||||
}
|
||||
fflib_ArrayUtils.setFieldValue(this, sObjectIdFieldToCheck, sObjectFieldToUpdate, values);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -59,6 +59,62 @@ public class fflib_ArrayUtils
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the given fields from the a domain to another domain
|
||||
*
|
||||
* @param source The domain holding the values that need to be copied over to the target
|
||||
* @param target The target domain that should be updated
|
||||
* @param targetRelationShipField The relationship field on the target linking to the source record
|
||||
* @param targetBySourceField The target SObjectField by the source SObjectField
|
||||
*
|
||||
* @example
|
||||
* Accounts accounts = Accounts.newInstance(accountRecords);
|
||||
* Contacts contact = Contact.newInstance(contactRecords
|
||||
* Map<Id, Object> accountNameById =
|
||||
* fflib_ArrayUtils.copyFields(
|
||||
* accounts,
|
||||
* contacts,
|
||||
* Contact.AccountId,
|
||||
* new Map<SObjectField, SObjectField>{
|
||||
* Account.BillingCity => Contact.MailingCity,
|
||||
* Account.BillingCountry => Contact.MailingCountry
|
||||
* });
|
||||
*/
|
||||
public static void copyFields(
|
||||
fflib_ISObjects2 source,
|
||||
fflib_ISObjects2 target,
|
||||
SObjectField targetRelationShipField,
|
||||
Map<SObjectField, SObjectField> targetBySourceField)
|
||||
{
|
||||
SObjectField sourceIdField = fflib_SObjectDescribe.getDescribe(source.getSObjectType()).getField('Id');
|
||||
|
||||
// Retrieve values
|
||||
Map<Id, Map<SObjectField, Object>> sourceFieldValueById = new Map<Id, Map<SObjectField, Object>>();
|
||||
for (SObject record : source.getRecords()) {
|
||||
|
||||
Map<SObjectField, Object> valueByField = new Map<SObjectField, Object>();
|
||||
for (SObjectField sourceField : targetBySourceField.keySet()) {
|
||||
valueByField.put(sourceField, record.get(sourceField));
|
||||
}
|
||||
sourceFieldValueById.put((Id) record.get(sourceIdField), valueByField);
|
||||
}
|
||||
|
||||
// Set values
|
||||
for (SObject record : target.getRecords()) {
|
||||
Id recordId = (Id) record.get(targetRelationShipField);
|
||||
if (sourceFieldValueById.containsKey(recordId) == false) continue;
|
||||
|
||||
Map<SObjectField, Object> valueByField = sourceFieldValueById.get(recordId);
|
||||
for (SObjectField sourceField : valueByField.keySet()) {
|
||||
if (targetBySourceField.containsKey(sourceField) == false) continue;
|
||||
|
||||
SObjectField targetField = targetBySourceField.get(sourceField);
|
||||
|
||||
record.put(targetField, valueByField.get(sourceField));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first value of the list
|
||||
*
|
||||
@@ -93,6 +149,35 @@ public class fflib_ArrayUtils
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a map with the values of two fields.
|
||||
* Key fields containing null values are omitted
|
||||
*
|
||||
* @param domain The domain holding the records
|
||||
* @param valueField The field to use as the Value of the Map
|
||||
* @param keyField The Id field to use as the Key of the map
|
||||
*
|
||||
* @return Returns a map with the values of two fields
|
||||
*
|
||||
* @example
|
||||
* Accounts accounts = Accounts.newInstance(records);
|
||||
* Map<Id, Object> accountNameById = fflib_ArrayUtils.getValueById(accounts, Account.Name, Account.Id);
|
||||
*/
|
||||
public static Map<Id, Object> getValueById(fflib_ISObjects2 domain, SObjectField valueField, SObjectField keyField)
|
||||
{
|
||||
Map<Id, Object> result = new Map<Id, Object>();
|
||||
for (SObject record : domain.getRecords())
|
||||
{
|
||||
if (record.get(keyField) == null) continue;
|
||||
|
||||
result.put(
|
||||
(Id) record.get(keyField),
|
||||
record.get(valueField)
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates if a list is empty
|
||||
*
|
||||
@@ -625,6 +710,30 @@ public class fflib_ArrayUtils
|
||||
return sObjects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a value to the given field only when key field Id value is provided in the given map
|
||||
*
|
||||
* @param domain The domain containing the records to update
|
||||
* @param sObjectIdFieldToCheck The SObject Id Field to match the key against in the provided map
|
||||
* @param sObjectFieldToUpdate The SObjectField to store the mapped value when the key matches the value in the sObjectFieldToUpdate field
|
||||
* @param values Map of values to store by the sObjectIdFieldToCheck fields value
|
||||
*/
|
||||
public static void setFieldValue(
|
||||
fflib_ISObjects2 domain,
|
||||
Schema.SObjectField sObjectIdFieldToCheck,
|
||||
Schema.SObjectField sObjectFieldToUpdate,
|
||||
Map<Id, Object> values)
|
||||
{
|
||||
for (SObject record : domain.getRecords())
|
||||
{
|
||||
Id keyValue = (Id) record.get(sObjectIdFieldToCheck);
|
||||
if (values.containsKey(keyValue))
|
||||
{
|
||||
record.put(sObjectFieldToUpdate, values.get(keyValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts all String of the list into uppercase
|
||||
* null values are ignored
|
||||
|
||||
@@ -30,6 +30,40 @@ private class fflib_ArrayUtilsTest
|
||||
);
|
||||
}
|
||||
|
||||
@IsTest
|
||||
static void itShouldCopyFields() {
|
||||
final String city = 'New York';
|
||||
final String country = 'United States';
|
||||
|
||||
Account accountRecord = new Account(
|
||||
Id = fflib_IDGenerator.generate(Account.SObjectType),
|
||||
BillingCity = city,
|
||||
BillingCountry = country);
|
||||
Accounts accounts = new Accounts(new List<Account>{
|
||||
accountRecord
|
||||
});
|
||||
|
||||
Contact contactRecord = new Contact(
|
||||
Id = fflib_IDGenerator.generate(Contact.SObjectType),
|
||||
AccountId = accountRecord.Id
|
||||
);
|
||||
Contacts contacts = new Contacts(new List<Contact>{
|
||||
contactRecord
|
||||
});
|
||||
|
||||
System.Test.startTest();
|
||||
fflib_ArrayUtils.copyFields(accounts, contacts, Contact.AccountId,
|
||||
new Map<SObjectField, SObjectField>{
|
||||
Account.BillingCity => Contact.MailingCity,
|
||||
Account.BillingCountry => Contact.MailingCountry
|
||||
}
|
||||
);
|
||||
System.Test.stopTest();
|
||||
|
||||
System.Assert.areEqual(city, contactRecord.MailingCity, 'Mailing City not Copied');
|
||||
System.Assert.areEqual(country, contactRecord.MailingCountry, 'Mailing Country not Copied');
|
||||
}
|
||||
|
||||
@IsTest
|
||||
static void itShouldReturnEmptyListOnEmptyObjectToString()
|
||||
{
|
||||
@@ -499,4 +533,24 @@ private class fflib_ArrayUtilsTest
|
||||
Datetime.newInstance(2018, 07, 07, 07, 7, 7)
|
||||
};
|
||||
}
|
||||
|
||||
private class Accounts extends fflib_SObjects2 {
|
||||
public Accounts(List<SObject> records) {
|
||||
super(records, Account.SObjectType);
|
||||
}
|
||||
|
||||
public override SObjectType getSObjectType() {
|
||||
return Account.SObjectType;
|
||||
}
|
||||
}
|
||||
|
||||
private class Contacts extends fflib_SObjects2 {
|
||||
public Contacts(List<SObject> records) {
|
||||
super(records, Account.SObjectType);
|
||||
}
|
||||
|
||||
public override SObjectType getSObjectType() {
|
||||
return Contact.SObjectType;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user