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
|
@TestVisible
|
||||||
protected virtual Map<Id, Object> getFieldValueByIdField(SObjectField valueField, SObjectField keyField) {
|
protected virtual Map<Id, Object> getFieldValueByIdField(SObjectField valueField, SObjectField keyField) {
|
||||||
Map<Id, Object> result = new Map<Id, Object>();
|
return fflib_ArrayUtils.getValueById(this, valueField, keyField);
|
||||||
for (SObject record : getRecords())
|
|
||||||
{
|
|
||||||
if (record.get(keyField) == null) continue;
|
|
||||||
|
|
||||||
result.put(
|
|
||||||
(Id) record.get(keyField),
|
|
||||||
record.get(valueField)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1437,14 +1427,7 @@ public virtual class fflib_SObjects2
|
|||||||
Schema.SObjectField sObjectFieldToUpdate,
|
Schema.SObjectField sObjectFieldToUpdate,
|
||||||
Map<Id, Object> values)
|
Map<Id, Object> values)
|
||||||
{
|
{
|
||||||
for (SObject record : getRecords())
|
fflib_ArrayUtils.setFieldValue(this, sObjectIdFieldToCheck, sObjectFieldToUpdate, values);
|
||||||
{
|
|
||||||
Id keyValue = (Id) record.get(sObjectIdFieldToCheck);
|
|
||||||
if (values?.containsKey(keyValue))
|
|
||||||
{
|
|
||||||
record.put(sObjectFieldToUpdate, values.get(keyValue));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -59,6 +59,62 @@ public class fflib_ArrayUtils
|
|||||||
return result;
|
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
|
* Gets the first value of the list
|
||||||
*
|
*
|
||||||
@@ -93,6 +149,35 @@ public class fflib_ArrayUtils
|
|||||||
return result;
|
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
|
* Validates if a list is empty
|
||||||
*
|
*
|
||||||
@@ -625,6 +710,30 @@ public class fflib_ArrayUtils
|
|||||||
return sObjects;
|
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
|
* Converts all String of the list into uppercase
|
||||||
* null values are ignored
|
* 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
|
@IsTest
|
||||||
static void itShouldReturnEmptyListOnEmptyObjectToString()
|
static void itShouldReturnEmptyListOnEmptyObjectToString()
|
||||||
{
|
{
|
||||||
@@ -499,4 +533,24 @@ private class fflib_ArrayUtilsTest
|
|||||||
Datetime.newInstance(2018, 07, 07, 07, 7, 7)
|
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