diff --git a/sfdx-source/apex-extensions/main/default/classes/domains/fflib_SObjects2.cls b/sfdx-source/apex-extensions/main/default/classes/domains/fflib_SObjects2.cls index 6d2907d..9181259 100644 --- a/sfdx-source/apex-extensions/main/default/classes/domains/fflib_SObjects2.cls +++ b/sfdx-source/apex-extensions/main/default/classes/domains/fflib_SObjects2.cls @@ -28,1192 +28,1106 @@ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -public virtual class fflib_SObjects2 extends fflib_SObjects implements fflib_ISObjects2 { - protected Schema.DescribeSObjectResult SObjectDescribe { get; private set; } - - /** - * Class constructors - * - * @param objects The Objects of type SObjectType, to contain inside the domain - */ - public fflib_SObjects2(List objects) { - // todo - assert of objects of type SObject - this((List) objects); - } - - /** - * Class constructor - * - * @param records The records to contain inside the domain - */ - public fflib_SObjects2(List records) { - this(records, records.getSObjectType()); - } - - /** - * Class constructor - * - * @param records The records to contain inside the domain - * @param sObjectType The SObjectType of the records - */ - public fflib_SObjects2( - List records, - Schema.SObjectType sObjectType - ) { - super(records, sObjectType); - SObjectDescribe = sObjectType.getDescribe(); - } - - /** - * @param id Domain containing primary key (Id field) values - * - * @return Returns only the SObjects from the domain matching the given Ids. - */ - public virtual SObject getRecord(Id id) { - List result = getRecords(new Set{ id }); - - return (result.size() == 0) ? null : result.get(0); - } - - /** - * Creates a map between the record Ids of this domain to the last given grandparent domain. - * - * @param domainsByRelationshipField A Map of domains and the in hierarchical order from first parent to grandparent - * - * @return Returns a map with KEY: The Ids of the records in this domain, - * to the VALUE: The Id of the last grandparent record listed in the relatedDomains, - * null if no grandparent exists. - * - * @example - * ICases casesDomain = Cases.newInstance(caseRecords); - * IContacts contactsDomain = Contacts.newInstance(contactRecords); - * IAccount accountDomain = Accounts.newInstance(accountRecords); - * - * // A map with key - Case.Id to value - Account.Id - * Map accountIdByCaseId = - * casesDomain.getParentIdById( - * new Map - * { - * Schema.Case.ContactId => contactDomain, - * Schema.Contact.AccountId => accountDomain - * }); - */ - public virtual Map getParentIdById( - Map domainsByRelationshipField - ) { - // Takes the highest related domain from the domainsByRelationshipField - Schema.SObjectField relationshipField = new List( - domainsByRelationshipField.keySet() - ) - .get(0); - fflib_SObjects2 relatedDomain = domainsByRelationshipField.remove( - relationshipField - ); - - // Extract the Id values of the related SObjectType - Map result = getIdFieldByIdField( - relationshipField, - getSObjectType().getDescribe().fields.getMap().get('Id') - ); - - // Check if we need to resolve another parent relation, if not return the results - if (domainsByRelationshipField.isEmpty()) - return result; - - // Fetch the Ids of the related SObjectType - Map parentIdByChildId = relatedDomain.getParentIdById( - domainsByRelationshipField - ); - - // Replace the maps value (ParentId) with the grand parent Id - return fflib_ArrayUtils.replaceValue(result, parentIdByChildId); - } - - /** DEPRECATED **/ - public virtual Map getGrandParentIdById( - List relatedDomains - ) { - System.debug( - LoggingLevel.WARN, - 'The \'getGrandParentIdById(List relatedDomains)\' method is deprecated,' + - 'please refactor to \'getParentIdById(Map relatedDomains)\'' - ); - - fflib_ISObjects2 relatedDomain = relatedDomains.remove(0); - SObjectType relatedDomainType = relatedDomain.getSObjectType(); - Map relatedFieldByDomainType = getRelatedFieldByDomainType(); - - if (relatedFieldByDomainType.containsKey(relatedDomainType) == false) - throw new DeveloperException( - String.format( - 'RelatedDomain type {0} not present in method getRelatedFieldByDomainType', - new List{ String.valueOf(relatedDomainType) } - ) - ); - - Map result = getIdFieldByIdField( - relatedFieldByDomainType.get(relatedDomainType), - getSObjectType().getDescribe().fields.getMap().get('Id') - ); - - // Check if we need to resolve another parent relation, if not return the results - if (relatedDomains.isEmpty()) - return result; - - Map grandChildIdByChildId = relatedDomain.getGrandParentIdById( - relatedDomains - ); - - // Replace the maps value (childId) with the grand child Id - return fflib_ArrayUtils.replaceValue(result, grandChildIdByChildId); - } - - /** - * Creates a map between the record Ids of this domain to the last given child domain. - * This method is using getRelatedFieldByDomainType to determine which SObjectField - * is related to the given parent domain - * - * @param domainsByRelationshipField A Map of domains in hierarchical order from first child to grandchild - * - * @return Returns a map with KEY: The Ids of the records in this domain, - * to the VALUE: The record Ids of the lowest child related record listed in the relatedDomains, - * null if no grandchild exists. - * - * @example - * ICases casesDomain = Cases.newInstance(caseRecords); - * IContacts contactsDomain = Contacts.newInstance(contactRecords); - * IAccount accountDomain = Accounts.newInstance(accountRecords); - * - * // A map with key - Case.Id to value - Account.Id - * Map> caseIdsByAccountId = - * accountsDomain.getChildIdsById( - * new Map - * { - * Schema.Contact.AccountId => contactsDomain - * Schema.Case.ContactId => casesDomain, - * }); - */ - public virtual Map> getChildIdsById( - Map domainsByRelationshipField - ) { - // Takes the highest related domain from the domainsByRelationshipField - Schema.SObjectField relationshipField = new List( - domainsByRelationshipField.keySet() - ) - .get(0); - fflib_SObjects2 relatedDomain = domainsByRelationshipField.remove( - relationshipField - ); - - Map> result = relatedDomain.getIdFieldsByIdField( - relatedDomain.getSObjectType().getDescribe().fields.getMap().get('Id'), - relationshipField - ); - - // Check if we need to resolve another child relation, if not return the results - if (domainsByRelationshipField.isEmpty()) - return result; - - Map> childIdsById = relatedDomain.getChildIdsById( - domainsByRelationshipField - ); - - // Replace the maps value (childIds) with the grand child Id - return fflib_ArrayUtils.replaceValues(result, childIdsById); - } - - /** DEPRECATED **/ - public virtual Map> getChildIdsById( - List relatedDomains - ) { - System.debug( - LoggingLevel.WARN, - 'The \'getChildIdsById(List relatedDomains)\' method is deprecated,' + - 'please refactor to \'getChildIdsById(Map relatedDomains)\'' - ); - - SObjectType thisDomainType = getSObjectType(); - fflib_SObjects2 relatedDomain = relatedDomains.remove(0); - Map relatedFieldByDomainType = relatedDomain.getRelatedFieldByDomainType(); - - if (relatedFieldByDomainType.containsKey(thisDomainType) == false) - throw new DeveloperException( - String.format( - 'RelatedDomain type {0} not present in method getRelatedFieldByDomainType', - new List{ String.valueOf(thisDomainType) } - ) - ); - - SObjectField relatedLookupFieldOnChild = relatedFieldByDomainType.get( - thisDomainType - ); - Map> result = relatedDomain.getIdFieldsByIdField( - relatedDomain.getSObjectType().getDescribe().fields.getMap().get('Id'), - relatedLookupFieldOnChild - ); - - // Check if we need to resolve another child relation, if not return the results - if (relatedDomains.isEmpty()) - return result; - - Map> childIdsById = relatedDomain.getChildIdsById( - relatedDomains - ); - - // Replace the maps value (childIds) with the grand child Id - return fflib_ArrayUtils.replaceValues(result, childIdsById); - } - - /** - * @return Returns the contents of the Domain by their primary Key ('Id' field) - */ - public virtual Map getSObjectById() { - return new Map(getRecords()); - } - - /** - * @param ids Domain containing primary key (Id field) values - * - * @return Returns only the SObjects from the domain matching the given Ids. - */ - public virtual List getRecords(fflib_Ids ids) { - return getRecords(ids.getIds()); - } - - /** - * @param ids A Set containing primary key (Id field) values - * - * @return Returns only the SObjects from the domain matching the given Ids. - */ - public virtual List getRecords(Set ids) { - Map sObjectsByIds = getSObjectById(); - List result = new List(); - for (Id id : ids) { - if (sObjectsByIds.containsKey(id) == false) - continue; - - result.add(sObjectsByIds.get(id)); - } - return result; - } - - /** - * @param criteria The condition the returned record must meet - * - * @return Return the SObject records contained in the domain matching the criteria - */ - public virtual List getRecords(fflib_Criteria criteria) { - List result = new List(); - for (SObject record : getRecords()) { - if (!criteria.evaluate(record)) - continue; - - result.add(record); - } - return result; - } - - /** - * @return Trip the records from fields that the user doesn't have access to - */ - public virtual List stripInaccessibleFields() { - return stripInaccessibleFields(AccessType.READABLE); - } - - /** - * @param accessType - * - * @return Trip the records from fields that the user doesn't have access to - */ - public virtual List stripInaccessibleFields( - System.AccessType accessType - ) { - return Security.stripInaccessible(accessType, getRecords()).getRecords(); - } - - /** - * @param sObjectField The Schema.SObjectField to get their Id values - * - * @return The Date values of the given sObjectField, null values are omitted - */ - @TestVisible - protected virtual fflib_Dates getDateFieldValues( - Schema.SObjectField sObjectField - ) { - Set result = new Set(); - for (SObject record : getRecords()) { - Object fieldValue = record.get(sObjectField); - if (fieldValue == null) - continue; - result.add((Date) fieldValue); - } - return new fflib_Dates(result); - } - - /** - * @param sObjectField The Schema.SObjectField to get their Id values - * @param criteria The criteria condition that must be met to include the value in the return - * - * @return The Date values of the given sObjectField, null values are omitted - */ - @TestVisible - protected virtual fflib_Dates getDateFieldValues( - Schema.SObjectField sObjectField, - fflib_Criteria criteria - ) { - return new fflib_SObjects2(getRecords(criteria), getSObjectType()) - .getDateFieldValues(sObjectField); - } - - /** - * @param sObjectField The Schema.SObjectField to get their Id values - * - * @return The DateTime values of the given sObjectField, null values are omitted - */ - @TestVisible - protected virtual fflib_DateTimes getDateTimeFieldValues( - Schema.SObjectField sObjectField - ) { - Set result = new Set(); - for (SObject record : getRecords()) { - Object fieldValue = record.get(sObjectField); - if (fieldValue == null) - continue; - result.add((Datetime) fieldValue); - } - return new fflib_DateTimes(result); - } - - /** - * @param sObjectField The Schema.SObjectField to get their Id values - * @param criteria The criteria condition that must be met to include the value in the return - * - * @return The DateTime values of the given sObjectField, null values are omitted - */ - @TestVisible - protected virtual fflib_DateTimes getDateTimeFieldValues( - Schema.SObjectField sObjectField, - fflib_Criteria criteria - ) { - return new fflib_SObjects2(getRecords(criteria), getSObjectType()) - .getDateTimeFieldValues(sObjectField); - } - - /** - * @param decimalField The field to use as the Value of the returned Map - * @param idField The field to use as the Key of the returned map - * - * @return Returns a map with the values of two fields - */ - @TestVisible - protected virtual Map getDecimalById( - Schema.SObjectField decimalField, - Schema.SObjectField idField - ) { - Map result = new Map(); - for (SObject record : getRecords()) { - if (record.get(idField) == null) - continue; - - result.put((Id) record.get(idField), (Decimal) record.get(decimalField)); - } - return result; - } - - /** - * @param sObjectField The Schema.SObjectField to get the SUM of - * - * @return The total SUM of the given field - */ - @TestVisible - protected virtual Decimal getDecimalFieldSum( - Schema.SObjectField sObjectField - ) { - Decimal result = 0; - for (SObject record : getRecords()) { - result += record.get(sObjectField) == null - ? 0 - : (Decimal) record.get(sObjectField); - } - return result; - } - - /** - * @param sObjectField The Schema.SObjectField to get their Id values - * - * @return The Decimal values of the given sObjectField, null values are omitted - */ - @TestVisible - protected virtual fflib_Decimals getDecimalFieldValues( - Schema.SObjectField sObjectField - ) { - Set result = new Set(); - for (SObject record : getRecords()) { - Object fieldValue = record.get(sObjectField); - if (fieldValue == null) - continue; - result.add((Decimal) fieldValue); - } - return new fflib_Decimals(result); - } - - /** - * @param sObjectField The Schema.SObjectField to get their Id values - * @param criteria The criteria condition that must be met to include the value in the return - * - * @return The Decimal values of the given sObjectField, null values are omitted - */ - @TestVisible - protected virtual fflib_Decimals getDecimalFieldValues( - Schema.SObjectField sObjectField, - fflib_Criteria criteria - ) { - return new fflib_SObjects2(getRecords(criteria), getSObjectType()) - .getDecimalFieldValues(sObjectField); - } - - /** - * @param sObjectField The Schema.SObjectField to get their Id values - * - * @return The Double values of the given sObjectField, null values are omitted - */ - @TestVisible - protected virtual fflib_Doubles getDoubleFieldValues( - Schema.SObjectField sObjectField - ) { - Set result = new Set(); - for (SObject record : getRecords()) { - Object fieldValue = record.get(sObjectField); - if (fieldValue == null) - continue; - result.add((Double) fieldValue); - } - return new fflib_Doubles(result); - } - - /** - * @param sObjectField The Schema.SObjectField to get their Id values - * @param criteria The criteria condition that must be met to include the value in the return - * - * @return The Double values of the given sObjectField, null values are omitted - */ - @TestVisible - protected virtual fflib_Doubles getDoubleFieldValues( - Schema.SObjectField sObjectField, - fflib_Criteria criteria - ) { - return new fflib_SObjects2(getRecords(criteria), getSObjectType()) - .getDoubleFieldValues(sObjectField); - } - - /** - * Get a map with the values of two fields. - * Key fields containing null values are omitted - * - * @param valueField The field to use as the Value of the Map - * @param keyField The 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 accountNameById = accounts.getFieldByField(Account.Name, Account.Id); - */ - @TestVisible - protected virtual Map getFieldByField( - Schema.SObjectField valueField, - Schema.SObjectField keyField - ) { - Map result = new Map(); - for (SObject record : getRecords()) { - if (record.get(keyField) == null) - continue; - - result.put(record.get(keyField), record.get(valueField)); - } - return result; - } - - /** - * Get a map with the values of two fields - * Key fields containing null values are omitted - * - * @param valueField The field to use as the Value of the Map - * @param keyField The field to use as the Key of the map - * - * @return Returns a map with the values of two fields - * - * @example - * Contacts contacts = Contacts.newInstance(records); - * Map> contactIdByAccountId = contacts.getFieldsByField(Contact.Id, Contact.AccountId); - */ - @TestVisible - protected virtual Map> getFieldsByField( - Schema.SObjectField valueField, - Schema.SObjectField keyField - ) { - Map> result = new Map>(); - for (SObject record : getRecords()) { - Object keyFieldValue = record.get(keyField); - if (keyFieldValue == null) - continue; - - if (!result.containsKey(keyFieldValue)) { - result.put(keyFieldValue, new Set()); - } - result.get(keyFieldValue).add(record.get(valueField)); - } - return result; - } - - /** - * @return Returns only the first SObject contained in the domain. - */ - public SObject getFirstSObject() { - if (isEmpty()) - return null; - - return getRecords().get(0); - } - - /** - * Get a map with the values of a String field as key and Id field - * Key fields containing null values are omitted - * - * @param valueField The Id field to use as the Value of the Map - * @param keyField The String field to use as the Key of the map - * - * @return Returns a map with the values of two fields - * - * @example - * Contacts contacts = Contacts.newInstance(records); - * Map accountIdByContactId = contacts.getIdFieldByStringField(Contact.Id, Contact.Name); - */ - @TestVisible - protected virtual Map getIdFieldByStringField( - Schema.SObjectField valueField, - Schema.SObjectField keyField - ) { - Map result = new Map(); - for (SObject record : getRecords()) { - if (record.get(keyField) == null) - continue; - - result.put((String) record.get(keyField), (Id) record.get(valueField)); - } - return result; - } - - /** - * Get a map with the values of two Id fields - * Key fields containing null values are omitted - * - * @param valueField The Id 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 - * Contacts contacts = Contacts.newInstance(records); - * Map accountIdByContactId = contacts.getIdFieldByIdField(Contact.AccountId, Contact.Id); - */ - @TestVisible - protected virtual Map getIdFieldByIdField( - Schema.SObjectField valueField, - Schema.SObjectField keyField - ) { - Map result = new Map(); - for (SObject record : getRecords()) { - if (record.get(keyField) == null) - continue; - - result.put((Id) record.get(keyField), (Id) record.get(valueField)); - } - return result; - } - - /** - * Get a map with the values of two Id fields with a one to many relation - * Key fields containing null values are omitted - * - * @param valueField The Id 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 - * Contacts contacts = Contacts.newInstance(records); - * Map> contactIdByAccountId = contacts.getIdFieldsByIdField(Contact.Id, Contact.AccountId); - */ - @TestVisible - protected virtual Map> getIdFieldsByIdField( - Schema.SObjectField valueField, - Schema.SObjectField keyField - ) { - Map> result = new Map>(); - for (SObject record : getRecords()) { - Id keyFieldId = (Id) record.get(keyField); - if (keyFieldId == null) - continue; - - if (!result.containsKey(keyFieldId)) { - result.put(keyFieldId, new Set()); - } - result.get(keyFieldId).add((Id) record.get(valueField)); - } - return result; - } - - /** - * Get a map with the values of an Id field by a String field with a one to many relation - * Key fields containing null values are omitted - * - * @param valueField The Id field to use as the Value of the Map - * @param keyField The String 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> accountIdsByCountry = accounts.getIdFieldsByStringField(Account.BillingCountry, Account.Id); - */ - @TestVisible - protected virtual Map> getIdFieldsByStringField( - Schema.SObjectField valueField, - Schema.SObjectField keyField - ) { - Map> result = new Map>(); - for (SObject record : getRecords()) { - String keyFieldString = String.valueOf(record.get(keyField)); - if (keyFieldString == null) - continue; - - if (!result.containsKey(keyFieldString)) { - result.put(keyFieldString, new Set()); - } - result.get(keyFieldString).add((Id) record.get(valueField)); - } - return result; - } - - /** - * Gets the Id values, but with the option to omit null values - * - * @param field The Schema.SObjectField to get their Id values - * @param omitNulls If set to TRUE, null values will be removed from the result - * - * @return The Id values of the given sObjectField, null values are omitted - */ - @TestVisible - protected Set getIdFieldValues( - Schema.SObjectField field, - Boolean omitNulls - ) { - Set result = getIdFieldValues(field); - - if (omitNulls) { - result.remove(null); - } - return result; - } - - /** - * @param sObjectField The Schema.SObjectField to get their Id values - * @param criteria The criteria condition that must be met to include the value in the return - * - * @return The Id values of the given sObjectField, null values are omitted - */ - @TestVisible - protected virtual fflib_Ids getIdFieldValues( - Schema.SObjectField sObjectField, - fflib_Criteria criteria - ) { - return new fflib_Ids( - new fflib_SObjects2(getRecords(criteria), getSObjectType()) - .getIdFieldValues(sObjectField) - ); - } - - /** - * @param sObjectField The Schema.SObjectField to get their values - * - * @return The Integer values of the given sObjectField, null values are omitted - */ - @TestVisible - protected virtual fflib_Integers getIntegerFieldValues( - Schema.SObjectField sObjectField - ) { - Set result = new Set(); - for (SObject record : getRecords()) { - Object fieldValue = record.get(sObjectField); - if (fieldValue == null) - continue; - - result.add(Integer.valueOf(fieldValue)); - } - return new fflib_Integers(result); - } - - /** - * @param sObjectField The Schema.SObjectField to get their values - * @param criteria The criteria condition that must be met to include the value in the return - * - * @return The Integer values of the given sObjectField, null values are omitted - */ - @TestVisible - protected virtual fflib_Integers getIntegerFieldValues( - Schema.SObjectField sObjectField, - fflib_Criteria criteria - ) { - return new fflib_SObjects2(getRecords(criteria), getSObjectType()) - .getIntegerFieldValues(sObjectField); - } - - /** - * @param sObjectField The Schema.SObjectField to get their values - * - * @return The Long values of the given sObjectField, null values are omitted - */ - @TestVisible - protected virtual fflib_Longs getLongFieldValues( - Schema.SObjectField sObjectField - ) { - Set result = new Set(); - for (SObject record : getRecords()) { - Object fieldValue = record.get(sObjectField); - if (fieldValue == null) - continue; - result.add((Long) fieldValue); - } - return new fflib_Longs(result); - } - - /** - * @param sObjectField The Schema.SObjectField to get their values - * @param criteria The criteria condition that must be met to include the value in the return - * - * @return The Long values of the given sObjectField, null values are omitted - */ - @TestVisible - protected virtual fflib_Longs getLongFieldValues( - Schema.SObjectField sObjectField, - fflib_Criteria criteria - ) { - return new fflib_SObjects2(getRecords(criteria), getSObjectType()) - .getLongFieldValues(sObjectField); - } - - @TestVisible - protected virtual List getRecords( - Schema.SObjectField sObjectField, - Id idValue - ) { - return getRecords(sObjectField, new Set{ idValue }); - } - - @TestVisible - protected virtual List getRecords( - Schema.SObjectField sObjectField, - Set values - ) { - List result = new List(); - for (SObject record : getRecords()) { - if (values?.contains((Id) record.get(sObjectField))) { - result.add(record); - } - } - return result; - } - - @TestVisible - protected virtual List getRecords( - Schema.SObjectField sObjectField, - String value - ) { - return getRecords(sObjectField, new Set{ value }); - } - - @TestVisible - protected virtual List getRecords( - Schema.SObjectField sObjectField, - Set values - ) { - List result = new List(); - for (SObject record : getRecords()) { - if (values?.contains((String) record.get(sObjectField))) { - result.add(record); - } - } - return result; - } - - @TestVisible - protected virtual List getRecordsIsNot( - Schema.SObjectField sObjectField, - String value - ) { - return getRecordsNotIn(sObjectField, new Set{ value }); - } - - @TestVisible - protected virtual List getRecordsNotIn( - Schema.SObjectField sObjectField, - Set values - ) { - List result = new List(); - for (SObject record : getRecords()) { - if (values?.contains((String) record.get(sObjectField))) - continue; - result.add(record); - } - return result; - } - - @TestVisible - protected virtual List getRecordsIsNot( - Schema.SObjectField sObjectField, - Id idValue - ) { - return getRecordsNotIn(sObjectField, new Set{ idValue }); - } - - @TestVisible - protected virtual List getRecordsNotIn( - Schema.SObjectField sObjectField, - Set idValues - ) { - List result = new List(); - for (SObject record : getRecords()) { - if (idValues?.contains((Id) record.get(sObjectField)) == false) { - result.add(record); - } - } - return result; - } - - @TestVisible - protected virtual List getRecords( - Schema.SObjectField sObjectField, - Boolean value - ) { - List result = new List(); - for (SObject record : getRecords()) { - if ((Boolean) record.get(sObjectField) == value) { - result.add(record); - } - } - return result; - } - - /** - * Get Parent Domain SObjectType to SObjectField.relationship field on this domain SObjectType - * - * @return Returns a map of the Parent Domain SObjectType to SObjectField.relationship field on the SObjectType - */ - protected virtual Map getRelatedFieldByDomainType() { - return new Map(); - } - - /** - * Get a map with the record mapped to the given Id field value - * Key fields containing null values are omitted - * - * @param sObjectField The field to use as key for the map - * - * @return Returns a map with the record mapped to the given Id field value - * - * @example - * Account account = Account.newInstance(records); - * Map accountById = account.getSObjectByIdField(Account.Id); - */ - @TestVisible - protected virtual Map getSObjectByIdField( - Schema.SObjectField sObjectField - ) { - Map result = new Map(); - for (SObject record : getRecords()) { - if (record.get(sObjectField) == null) - continue; - - result.put((Id) record.get(sObjectField), record); - } - return result; - } - - /** - * Get a map with the records mapped to the given Id field value - * Key fields containing null values are omitted - * - * @param sObjectField The field to use as key for the map - * - * @return Returns a map with the records mapped to the given Id field value - * - * @example - * Contacts contacts = Contacts.newInstance(records); - * Map> contactsByAccountId = contacts.getSObjectsByIdField(Contact.AccountId); - */ - @TestVisible - protected virtual Map> getSObjectsByIdField( - Schema.SObjectField sObjectField - ) { - Map> result = new Map>(); - for (SObject record : getRecords()) { - Id fieldId = (Id) record.get(sObjectField); - if (fieldId == null) - continue; - - if (!result.containsKey(fieldId)) { - result.put(fieldId, new List()); - } - result.get(fieldId).add(record); - } - return result; - } - - /** - * Get a map with the record mapped to the given String field value - * Key fields containing null values are omitted - * - * @param sObjectField The field to use as key for the map - * - * @return Returns a map with the record mapped to the given String field value - * - * @example - * Account account = Account.newInstance(records); - * Map accountByNumber = account.getSObjectByStringField(Account.AccountNumber); - */ - @TestVisible - protected virtual Map getSObjectByStringField( - Schema.SObjectField sObjectField - ) { - Map result = new Map(); - for (SObject record : getRecords()) { - if (record.get(sObjectField) == null) - continue; - - String fieldValue = (String) record.get(sObjectField); - result.put(fieldValue, record); - } - return result; - } - - /** - * Get a map with the records mapped to the given String field value - * Key fields containing null values are omitted - * - * @param sObjectField The field to use as key for the map - * - * @return Returns a map with the records mapped to the given String field value - * - * @example - * Accounts accounts = Account.newInstance(records); - * Map> accountByName = accounts.getSObjectsByStringField(Account.AccountName); - */ - @TestVisible - protected virtual Map> getSObjectsByStringField( - Schema.SObjectField sObjectField - ) { - Map> result = new Map>(); - for (SObject record : getRecords()) { - String fieldValue = (String) record.get(sObjectField); - if (fieldValue == null) - continue; - - if (!result.containsKey(fieldValue)) { - result.put(fieldValue, new List()); - } - result.get(fieldValue).add(record); - } - return result; - } - - /** - * Get a map with the given String field value mapped to the given Id field - * Key fields containing null values are omitted - * - * @param valueField The String field to use as value for the map - * @param keyField The Id field to use as key for the map - * - * @return a map with the given String field value mapped to the given Id field - * - * @example - * Account account = Account.newInstance(records); - * Map accountNameById = account.getStringFieldByIdField(Account.AccountName, Account.Id); - */ - @TestVisible - protected virtual Map getStringFieldByIdField( - Schema.SObjectField valueField, - Schema.SObjectField keyField - ) { - Map result = new Map(); - Map fieldByField = getFieldByField(valueField, keyField); - for (Object obj : fieldByField.keySet()) { - result.put((Id) obj, (String) fieldByField.get(obj)); - } - return result; - } - - /** - * Get a map with the given Date field value mapped to the given Id field - * Key fields containing null values are omitted - * - * @param valueField The Date field to use as value for the map - * @param keyField The Id field to use as key for the map - * - * @return a map with the given Date field value mapped to the given Id field - * - * @example - * Account account = Account.newInstance(records); - * Map createdDateById = account.getDateFieldByIdField(Account.CreatedDate, Account.Id); - */ - @TestVisible - protected virtual Map getDateFieldByIdField( - Schema.SObjectField valueField, - Schema.SObjectField keyField - ) { - Map result = new Map(); - Map fieldByField = getFieldByField(valueField, keyField); - for (Object obj : fieldByField.keySet()) { - Object value = fieldByField.get(obj); - Date dateValue; - if (value instanceof Date) { - dateValue = (Date) value; - } else if (value != null) { - dateValue = ((Datetime) value).date(); - } - result.put((Id) obj, dateValue); - } - return result; - } - - /** - * Get a map with the given Date field value mapped to the given Id field - * Key fields containing null values are omitted - * - * @param valueField The DateTime field to use as value for the map - * @param keyField The Id field to use as key for the map - * - * @return a map with the given Date field value mapped to the given Id field - * - * @example - * Account account = Account.newInstance(records); - * Map createdDateById = account.getDateFieldByIdField(Account.CreatedDate, Account.Id); - */ - @TestVisible - protected virtual Map getDateTimeFieldByIdField( - Schema.SObjectField valueField, - Schema.SObjectField keyField - ) { - Map result = new Map(); - Map fieldByField = getFieldByField(valueField, keyField); - for (Object obj : fieldByField.keySet()) { - result.put((Id) obj, (Datetime) fieldByField.get(obj)); - } - return result; - } - - /** - * Get a map with the records mapped to the given String field value - * Key fields containing null values are omitted - * - * @param valueField The field to use as value for the map - * @param keyField The field to use as key for the map - * - * @return Returns a map with the record mapped to the given Id field value - * - * @example - * Account account = Account.newInstance(records); - * Map accountNameById = account.getStringFieldByStringField(Account.AccountName, Account.Id); - */ - @TestVisible - protected virtual Map getStringFieldByStringField( - Schema.SObjectField valueField, - Schema.SObjectField keyField - ) { - Map result = new Map(); - Map fieldByField = getFieldByField(keyField, valueField); - for (Object obj : fieldByField.keySet()) { - result.put((String) obj, (String) fieldByField.get(obj)); - } - return result; - } - - /** - * @param sObjectField The Schema.SObjectField to get their values - * @param criteria The criteria condition that must be met to include the value in the return - * - * @return The String values of the given sObjectField - */ - @TestVisible - protected virtual fflib_Strings getStringFieldValues( - Schema.SObjectField sObjectField, - fflib_Criteria criteria - ) { - return new fflib_Strings( - new fflib_SObjects2(getRecords(criteria), getSObjectType()) - .getStringFieldValues(sObjectField) - ); - } - - /** - * Sets the given value to the given field only when the criteria is met for the record - * - * @param sObjectField The Schema.SObjectField to change its value - * @param value The new value for the given sObjectField - * @param criteria The criteria condition that must be met to include the value in the return - */ - @TestVisible - protected virtual void setFieldValue( - Schema.SObjectField sObjectField, - Object value, - fflib_Criteria criteria - ) { - new fflib_SObjects2(getRecords(criteria), getSObjectType()) - .setFieldValue(sObjectField, value); - } - - /** - * Sets a value to the given field only when key field Id value is provided in the given map - * - * @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 - */ - @TestVisible - protected virtual void setFieldValue( - Schema.SObjectField sObjectIdFieldToCheck, - Schema.SObjectField sObjectFieldToUpdate, - Map values - ) { - for (SObject record : getRecords()) { - Id keyValue = (Id) record.get(sObjectIdFieldToCheck); - if (values?.containsKey(keyValue)) { - record.put(sObjectFieldToUpdate, values.get(keyValue)); - } - } - } - - /** - * Sets a value to the given field only when key field String value is provided in the given map - * - * @param sObjectStringFieldToCheck The SObject String 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 - */ - @TestVisible - protected virtual void setFieldValue( - Schema.SObjectField sObjectStringFieldToCheck, - Schema.SObjectField sObjectFieldToUpdate, - Map values - ) { - for (SObject record : getRecords()) { - String keyValue = (String) record.get(sObjectStringFieldToCheck); - if (values?.containsKey(keyValue)) { - record.put(sObjectFieldToUpdate, values.get(keyValue)); - } - } - } - - public class DeveloperException extends Exception { - } -} +public virtual class fflib_SObjects2 + extends fflib_SObjects + implements fflib_ISObjects2 +{ + protected Schema.DescribeSObjectResult SObjectDescribe { get; private set; } + + /** + * Class constructors + * + * @param objects The Objects of type SObjectType, to contain inside the domain + */ + public fflib_SObjects2(List objects) + { + // todo - assert of objects of type SObject + this((List) objects); + } + + /** + * Class constructor + * + * @param records The records to contain inside the domain + */ + public fflib_SObjects2(List records) + { + this(records, records.getSObjectType()); + } + + /** + * Class constructor + * + * @param records The records to contain inside the domain + * @param sObjectType The SObjectType of the records + */ + public fflib_SObjects2(List records, Schema.SObjectType sObjectType) + { + super(records, sObjectType); + SObjectDescribe = sObjectType.getDescribe(); + } + + /** + * @param id Domain containing primary key (Id field) values + * + * @return Returns only the SObjects from the domain matching the given Ids. + */ + public virtual SObject getRecord(Id id) + { + List result = getRecords(new Set {id}); + + return (result.size() == 0) ? null : result.get(0); + } + + /** + * Creates a map between the record Ids of this domain to the last given grandparent domain. + * + * @param domainsByRelationshipField A Map of domains and the in hierarchical order from first parent to grandparent + * + * @return Returns a map with KEY: The Ids of the records in this domain, + * to the VALUE: The Id of the last grandparent record listed in the relatedDomains, + * null if no grandparent exists. + * + * @example + * ICases casesDomain = Cases.newInstance(caseRecords); + * IContacts contactsDomain = Contacts.newInstance(contactRecords); + * IAccount accountDomain = Accounts.newInstance(accountRecords); + * + * // A map with key - Case.Id to value - Account.Id + * Map accountIdByCaseId = + * casesDomain.getParentIdById( + * new Map + * { + * Schema.Case.ContactId => contactDomain, + * Schema.Contact.AccountId => accountDomain + * }); + */ + public virtual Map getParentIdById(Map domainsByRelationshipField) + { + // Takes the highest related domain from the domainsByRelationshipField + Schema.SObjectField relationshipField = + new List(domainsByRelationshipField.keySet()) + .get(0); + fflib_SObjects2 relatedDomain = domainsByRelationshipField.remove(relationshipField); + + // Extract the Id values of the related SObjectType + Map result = getIdFieldByIdField( + relationshipField, + getSObjectType().getDescribe().fields.getMap().get('Id')); + + // Check if we need to resolve another parent relation, if not return the results + if (domainsByRelationshipField.isEmpty()) return result; + + // Fetch the Ids of the related SObjectType + Map parentIdByChildId = relatedDomain.getParentIdById(domainsByRelationshipField); + + // Replace the maps value (ParentId) with the grand parent Id + return fflib_ArrayUtils.replaceValue(result, parentIdByChildId); + } + + /** DEPRECATED **/ + public virtual Map getGrandParentIdById(List relatedDomains) + { + System.debug(LoggingLevel.WARN, + 'The \'getGrandParentIdById(List relatedDomains)\' method is deprecated,' + + 'please refactor to \'getParentIdById(Map relatedDomains)\''); + + fflib_ISObjects2 relatedDomain = relatedDomains.remove(0); + SObjectType relatedDomainType = relatedDomain.getSObjectType(); + Map relatedFieldByDomainType = getRelatedFieldByDomainType(); + + if (relatedFieldByDomainType.containsKey(relatedDomainType) == false) + throw new DeveloperException( + String.format( + 'RelatedDomain type {0} not present in method getRelatedFieldByDomainType', + new List {String.valueOf(relatedDomainType)})); + + Map result = getIdFieldByIdField( + relatedFieldByDomainType.get(relatedDomainType), + getSObjectType().getDescribe().fields.getMap().get('Id')); + + // Check if we need to resolve another parent relation, if not return the results + if (relatedDomains.isEmpty()) return result; + + Map grandChildIdByChildId = relatedDomain.getGrandParentIdById(relatedDomains); + + // Replace the maps value (childId) with the grand child Id + return fflib_ArrayUtils.replaceValue(result, grandChildIdByChildId); + } + + /** + * Creates a map between the record Ids of this domain to the last given child domain. + * This method is using getRelatedFieldByDomainType to determine which SObjectField + * is related to the given parent domain + * + * @param domainsByRelationshipField A Map of domains in hierarchical order from first child to grandchild + * + * @return Returns a map with KEY: The Ids of the records in this domain, + * to the VALUE: The record Ids of the lowest child related record listed in the relatedDomains, + * null if no grandchild exists. + * + * @example + * ICases casesDomain = Cases.newInstance(caseRecords); + * IContacts contactsDomain = Contacts.newInstance(contactRecords); + * IAccount accountDomain = Accounts.newInstance(accountRecords); + * + * // A map with key - Case.Id to value - Account.Id + * Map> caseIdsByAccountId = + * accountsDomain.getChildIdsById( + * new Map + * { + * Schema.Contact.AccountId => contactsDomain + * Schema.Case.ContactId => casesDomain, + * }); + */ + public virtual Map> getChildIdsById(Map domainsByRelationshipField) + { + // Takes the highest related domain from the domainsByRelationshipField + Schema.SObjectField relationshipField = + new List(domainsByRelationshipField.keySet()) + .get(0); + fflib_SObjects2 relatedDomain = domainsByRelationshipField.remove(relationshipField); + + Map> result = relatedDomain.getIdFieldsByIdField( + relatedDomain.getSObjectType().getDescribe().fields.getMap().get('Id'), + relationshipField); + + // Check if we need to resolve another child relation, if not return the results + if (domainsByRelationshipField.isEmpty()) return result; + + Map> childIdsById = relatedDomain.getChildIdsById(domainsByRelationshipField); + + // Replace the maps value (childIds) with the grand child Id + return fflib_ArrayUtils.replaceValues(result, childIdsById); + } + + /** DEPRECATED **/ + public virtual Map> getChildIdsById(List relatedDomains) + { + System.debug(LoggingLevel.WARN, + 'The \'getChildIdsById(List relatedDomains)\' method is deprecated,' + + 'please refactor to \'getChildIdsById(Map relatedDomains)\''); + + + SObjectType thisDomainType = getSObjectType(); + fflib_SObjects2 relatedDomain = relatedDomains.remove(0); + Map relatedFieldByDomainType = relatedDomain.getRelatedFieldByDomainType(); + + if (relatedFieldByDomainType.containsKey(thisDomainType) == false) + throw new DeveloperException( + String.format( + 'RelatedDomain type {0} not present in method getRelatedFieldByDomainType', + new List {String.valueOf(thisDomainType)})); + + SObjectField relatedLookupFieldOnChild = relatedFieldByDomainType.get(thisDomainType); + Map> result = relatedDomain.getIdFieldsByIdField( + relatedDomain.getSObjectType().getDescribe().fields.getMap().get('Id'), + relatedLookupFieldOnChild); + + // Check if we need to resolve another child relation, if not return the results + if (relatedDomains.isEmpty()) return result; + + Map> childIdsById = relatedDomain.getChildIdsById(relatedDomains); + + // Replace the maps value (childIds) with the grand child Id + return fflib_ArrayUtils.replaceValues(result, childIdsById); + } + + /** + * @return Returns the contents of the Domain by their primary Key ('Id' field) + */ + public virtual Map getSObjectById() + { + return new Map(getRecords()); + } + + /** + * @param ids Domain containing primary key (Id field) values + * + * @return Returns only the SObjects from the domain matching the given Ids. + */ + public virtual List getRecords(fflib_Ids ids) + { + return getRecords(ids.getIds()); + } + + /** + * @param ids A Set containing primary key (Id field) values + * + * @return Returns only the SObjects from the domain matching the given Ids. + */ + public virtual List getRecords(Set ids) + { + Map sObjectsByIds = getSObjectById(); + List result = new List(); + for (Id id : ids) + { + if (sObjectsByIds.containsKey(id) == false) continue; + + result.add(sObjectsByIds.get(id)); + } + return result; + } + + /** + * @param criteria The condition the returned record must meet + * + * @return Return the SObject records contained in the domain matching the criteria + */ + public virtual List getRecords(fflib_Criteria criteria) + { + List result = new List(); + for (SObject record : getRecords()) + { + if (!criteria.evaluate(record)) continue; + + result.add(record); + } + return result; + } + + /** + * @return Trip the records from fields that the user doesn't have access to + */ + public virtual List stripInaccessibleFields() + { + return stripInaccessibleFields(AccessType.READABLE); + } + + /** + * @param accessType + * + * @return Trip the records from fields that the user doesn't have access to + */ + public virtual List stripInaccessibleFields( + System.AccessType accessType + ) + { + return Security.stripInaccessible(accessType, getRecords()).getRecords(); + } + + /** + * @param sObjectField The Schema.SObjectField to get their Id values + * + * @return The Date values of the given sObjectField, null values are omitted + */ + @TestVisible + protected virtual fflib_Dates getDateFieldValues(Schema.SObjectField sObjectField) + { + Set result = new Set(); + for (SObject record : getRecords()) + { + Object fieldValue = record.get(sObjectField); + if (fieldValue == null) continue; + result.add((Date) fieldValue); + } + return new fflib_Dates(result); + } + + /** + * @param sObjectField The Schema.SObjectField to get their Id values + * @param criteria The criteria condition that must be met to include the value in the return + * + * @return The Date values of the given sObjectField, null values are omitted + */ + @TestVisible + protected virtual fflib_Dates getDateFieldValues(Schema.SObjectField sObjectField, fflib_Criteria criteria) + { + return new fflib_SObjects2(getRecords(criteria), getSObjectType()) + .getDateFieldValues(sObjectField); + } + + /** + * @param sObjectField The Schema.SObjectField to get their Id values + * + * @return The DateTime values of the given sObjectField, null values are omitted + */ + @TestVisible + protected virtual fflib_DateTimes getDateTimeFieldValues(Schema.SObjectField sObjectField) + { + Set result = new Set(); + for (SObject record : getRecords()) + { + Object fieldValue = record.get(sObjectField); + if (fieldValue == null) continue; + result.add((Datetime) fieldValue); + } + return new fflib_DateTimes(result); + } + + /** + * @param sObjectField The Schema.SObjectField to get their Id values + * @param criteria The criteria condition that must be met to include the value in the return + * + * @return The DateTime values of the given sObjectField, null values are omitted + */ + @TestVisible + protected virtual fflib_DateTimes getDateTimeFieldValues(Schema.SObjectField sObjectField, fflib_Criteria criteria) + { + return new fflib_SObjects2(getRecords(criteria), getSObjectType()) + .getDateTimeFieldValues(sObjectField); + } + + /** + * @param decimalField The field to use as the Value of the returned Map + * @param idField The field to use as the Key of the returned map + * + * @return Returns a map with the values of two fields + */ + @TestVisible + protected virtual Map getDecimalById(Schema.SObjectField decimalField, Schema.SObjectField idField) { + Map result = new Map(); + for (SObject record : getRecords()) + { + if (record.get(idField) == null) continue; + + result.put( + (Id) record.get(idField), + (Decimal) record.get(decimalField) + ); + } + return result; + } + + /** + * @param sObjectField The Schema.SObjectField to get the SUM of + * + * @return The total SUM of the given field + */ + @TestVisible + protected virtual Decimal getDecimalFieldSum(Schema.SObjectField sObjectField) + { + Decimal result = 0; + for (SObject record : getRecords()) + { + result += record.get(sObjectField) == null ? 0 : (Decimal) record.get(sObjectField); + } + return result; + } + + /** + * @param sObjectField The Schema.SObjectField to get their Id values + * + * @return The Decimal values of the given sObjectField, null values are omitted + */ + @TestVisible + protected virtual fflib_Decimals getDecimalFieldValues(Schema.SObjectField sObjectField) + { + Set result = new Set(); + for (SObject record : getRecords()) + { + Object fieldValue = record.get(sObjectField); + if (fieldValue == null) continue; + result.add((Decimal) fieldValue); + } + return new fflib_Decimals(result); + } + + /** + * @param sObjectField The Schema.SObjectField to get their Id values + * @param criteria The criteria condition that must be met to include the value in the return + * + * @return The Decimal values of the given sObjectField, null values are omitted + */ + @TestVisible + protected virtual fflib_Decimals getDecimalFieldValues(Schema.SObjectField sObjectField, fflib_Criteria criteria) + { + return new fflib_SObjects2(getRecords(criteria), getSObjectType()) + .getDecimalFieldValues(sObjectField); + } + + /** + * @param sObjectField The Schema.SObjectField to get their Id values + * + * @return The Double values of the given sObjectField, null values are omitted + */ + @TestVisible + protected virtual fflib_Doubles getDoubleFieldValues(Schema.SObjectField sObjectField) + { + Set result = new Set(); + for (SObject record : getRecords()) + { + Object fieldValue = record.get(sObjectField); + if (fieldValue == null) continue; + result.add((Double) fieldValue); + } + return new fflib_Doubles(result); + } + + /** + * @param sObjectField The Schema.SObjectField to get their Id values + * @param criteria The criteria condition that must be met to include the value in the return + * + * @return The Double values of the given sObjectField, null values are omitted + */ + @TestVisible + protected virtual fflib_Doubles getDoubleFieldValues(Schema.SObjectField sObjectField, fflib_Criteria criteria) + { + return new fflib_SObjects2(getRecords(criteria), getSObjectType()) + .getDoubleFieldValues(sObjectField); + } + + /** + * Get a map with the values of two fields. + * Key fields containing null values are omitted + * + * @param valueField The field to use as the Value of the Map + * @param keyField The 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 accountNameById = accounts.getFieldByField(Account.Name, Account.Id); + */ + @TestVisible + protected virtual Map getFieldByField(Schema.SObjectField valueField, Schema.SObjectField keyField) + { + Map result = new Map(); + for (SObject record : getRecords()) + { + if (record.get(keyField) == null) continue; + + result.put( + record.get(keyField), + record.get(valueField) + ); + } + return result; + } + + /** + * Get a map with the values of two fields + * Key fields containing null values are omitted + * + * @param valueField The field to use as the Value of the Map + * @param keyField The field to use as the Key of the map + * + * @return Returns a map with the values of two fields + * + * @example + * Contacts contacts = Contacts.newInstance(records); + * Map> contactIdByAccountId = contacts.getFieldsByField(Contact.Id, Contact.AccountId); + */ + @TestVisible + protected virtual Map> getFieldsByField(Schema.SObjectField valueField, Schema.SObjectField keyField) + { + Map> result = new Map>(); + for (SObject record : getRecords()) + { + Object keyFieldValue = record.get(keyField); + if (keyFieldValue == null) continue; + + if (!result.containsKey(keyFieldValue)) + { + result.put(keyFieldValue, new Set()); + } + result.get(keyFieldValue).add(record.get(valueField)); + } + return result; + } + + /** + * @return Returns only the first SObject contained in the domain. + */ + public SObject getFirstSObject() + { + if (isEmpty()) return null; + + return getRecords().get(0); + } + + /** + * Get a map with the values of a String field as key and Id field + * Key fields containing null values are omitted + * + * @param valueField The Id field to use as the Value of the Map + * @param keyField The String field to use as the Key of the map + * + * @return Returns a map with the values of two fields + * + * @example + * Contacts contacts = Contacts.newInstance(records); + * Map accountIdByContactId = contacts.getIdFieldByStringField(Contact.Id, Contact.Name); + */ + @TestVisible + protected virtual Map getIdFieldByStringField(Schema.SObjectField valueField, Schema.SObjectField keyField) + { + Map result = new Map(); + for (SObject record : getRecords()) + { + if (record.get(keyField) == null) continue; + + result.put( + (String) record.get(keyField), + (Id) record.get(valueField) + ); + } + return result; + } + + /** + * Get a map with the values of two Id fields + * Key fields containing null values are omitted + * + * @param valueField The Id 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 + * Contacts contacts = Contacts.newInstance(records); + * Map accountIdByContactId = contacts.getIdFieldByIdField(Contact.AccountId, Contact.Id); + */ + @TestVisible + protected virtual Map getIdFieldByIdField(Schema.SObjectField valueField, Schema.SObjectField keyField) + { + Map result = new Map(); + for (SObject record : getRecords()) + { + if (record.get(keyField) == null) continue; + + result.put( + (Id) record.get(keyField), + (Id) record.get(valueField) + ); + } + return result; + } + + /** + * Get a map with the values of two Id fields with a one to many relation + * Key fields containing null values are omitted + * + * @param valueField The Id 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 + * Contacts contacts = Contacts.newInstance(records); + * Map> contactIdByAccountId = contacts.getIdFieldsByIdField(Contact.Id, Contact.AccountId); + */ + @TestVisible + protected virtual Map> getIdFieldsByIdField(Schema.SObjectField valueField, Schema.SObjectField keyField) + { + Map> result = new Map>(); + for (SObject record : getRecords()) + { + Id keyFieldId = (Id) record.get(keyField); + if (keyFieldId == null) continue; + + if (!result.containsKey(keyFieldId)) + { + result.put(keyFieldId, new Set()); + } + result.get(keyFieldId).add((Id) record.get(valueField)); + } + return result; + } + + /** + * Get a map with the values of an Id field by a String field with a one to many relation + * Key fields containing null values are omitted + * + * @param valueField The Id field to use as the Value of the Map + * @param keyField The String 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> accountIdsByCountry = accounts.getIdFieldsByStringField(Account.BillingCountry, Account.Id); + */ + @TestVisible + protected virtual Map> getIdFieldsByStringField(Schema.SObjectField valueField, Schema.SObjectField keyField) + { + Map> result = new Map>(); + for (SObject record : getRecords()) + { + String keyFieldString = String.valueOf(record.get(keyField)); + if (keyFieldString == null) continue; + + if (!result.containsKey(keyFieldString)) + { + result.put(keyFieldString, new Set()); + } + result.get(keyFieldString).add((Id) record.get(valueField)); + } + return result; + } + + /** + * @param sObjectField The Schema.SObjectField to get their Id values + * @param criteria The criteria condition that must be met to include the value in the return + * + * @return The Id values of the given sObjectField, null values are omitted + */ + @TestVisible + protected virtual fflib_Ids getIdFieldValues(Schema.SObjectField sObjectField, fflib_Criteria criteria) + { + return new fflib_Ids(new fflib_SObjects2(getRecords(criteria), getSObjectType()) + .getIdFieldValues(sObjectField)); + } + + /** + * @param sObjectField The Schema.SObjectField to get their values + * + * @return The Integer values of the given sObjectField, null values are omitted + */ + @TestVisible + protected virtual fflib_Integers getIntegerFieldValues(Schema.SObjectField sObjectField) + { + Set result = new Set(); + for (SObject record : getRecords()) + { + Object fieldValue = record.get(sObjectField); + if (fieldValue == null) continue; + + result.add(Integer.valueOf(fieldValue)); + } + return new fflib_Integers(result); + } + + /** + * @param sObjectField The Schema.SObjectField to get their values + * @param criteria The criteria condition that must be met to include the value in the return + * + * @return The Integer values of the given sObjectField, null values are omitted + */ + @TestVisible + protected virtual fflib_Integers getIntegerFieldValues(Schema.SObjectField sObjectField, fflib_Criteria criteria) + { + return new fflib_SObjects2(getRecords(criteria), getSObjectType()) + .getIntegerFieldValues(sObjectField); + } + + /** + * @param sObjectField The Schema.SObjectField to get their values + * + * @return The Long values of the given sObjectField, null values are omitted + */ + @TestVisible + protected virtual fflib_Longs getLongFieldValues(Schema.SObjectField sObjectField) + { + Set result = new Set(); + for (SObject record : getRecords()) + { + Object fieldValue = record.get(sObjectField); + if (fieldValue == null) continue; + result.add((Long) fieldValue); + } + return new fflib_Longs(result); + } + + /** + * @param sObjectField The Schema.SObjectField to get their values + * @param criteria The criteria condition that must be met to include the value in the return + * + * @return The Long values of the given sObjectField, null values are omitted + */ + @TestVisible + protected virtual fflib_Longs getLongFieldValues(Schema.SObjectField sObjectField, fflib_Criteria criteria) + { + return new fflib_SObjects2(getRecords(criteria), getSObjectType()) + .getLongFieldValues(sObjectField); + } + + @TestVisible + protected virtual List getRecords(Schema.SObjectField sObjectField, Id idValue) + { + return getRecords(sObjectField, new Set{ idValue }); + } + + @TestVisible + protected virtual List getRecords(Schema.SObjectField sObjectField, Set values) + { + List result = new List(); + for (SObject record : getRecords()) + { + if (values?.contains((Id) record.get(sObjectField))) + { + result.add(record); + } + } + return result; + } + + @TestVisible + protected virtual List getRecords(Schema.SObjectField sObjectField, String value) + { + return getRecords(sObjectField, new Set{ value }); + } + + @TestVisible + protected virtual List getRecords(Schema.SObjectField sObjectField, Set values) + { + List result = new List(); + for (SObject record : getRecords()) + { + if (values?.contains((String) record.get(sObjectField))) + { + result.add(record); + } + } + return result; + } + + @TestVisible + protected virtual List getRecordsIsNot(Schema.SObjectField sObjectField, String value) + { + return getRecordsNotIn(sObjectField, new Set{ value }); + } + + @TestVisible + protected virtual List getRecordsNotIn(Schema.SObjectField sObjectField, Set values) + { + List result = new List(); + for (SObject record : getRecords()) + { + if (values?.contains((String) record.get(sObjectField))) continue; + result.add(record); + } + return result; + } + + protected virtual List getRecordsIsNot(Schema.SObjectField sObjectField, Id idValue) + { + return getRecordsNotIn(sObjectField, new Set{ idValue }); + } + + protected virtual List getRecordsNotIn(Schema.SObjectField sObjectField, Set idValues) + { + List result = new List(); + for (SObject record : getRecords()) + { + if (idValues?.contains((Id) record.get(sObjectField)) == false) + { + result.add(record); + } + } + return result; + } + + @TestVisible + protected virtual List getRecords(Schema.SObjectField sObjectField, Boolean value) + { + List result = new List(); + for (SObject record : getRecords()) + { + if ((Boolean) record.get(sObjectField) == value) + { + result.add(record); + } + } + return result; + } + + /** + * Get Parent Domain SObjectType to SObjectField.relationship field on this domain SObjectType + * + * @return Returns a map of the Parent Domain SObjectType to SObjectField.relationship field on the SObjectType + */ + protected virtual Map getRelatedFieldByDomainType() + { + return new Map(); + } + + /** + * Get a map with the record mapped to the given Id field value + * Key fields containing null values are omitted + * + * @param sObjectField The field to use as key for the map + * + * @return Returns a map with the record mapped to the given Id field value + * + * @example + * Account account = Account.newInstance(records); + * Map accountById = account.getSObjectByIdField(Account.Id); + */ + @TestVisible + protected virtual Map getSObjectByIdField(Schema.SObjectField sObjectField) + { + Map result = new Map(); + for (SObject record : getRecords()) + { + if (record.get(sObjectField) == null) continue; + + result.put((Id) record.get(sObjectField), record); + } + return result; + } + + /** + * Get a map with the records mapped to the given Id field value + * Key fields containing null values are omitted + * + * @param sObjectField The field to use as key for the map + * + * @return Returns a map with the records mapped to the given Id field value + * + * @example + * Contacts contacts = Contacts.newInstance(records); + * Map> contactsByAccountId = contacts.getSObjectsByIdField(Contact.AccountId); + */ + @TestVisible + protected virtual Map> getSObjectsByIdField(Schema.SObjectField sObjectField) + { + Map> result = new Map>(); + for (SObject record : getRecords()) + { + Id fieldId = (Id) record.get(sObjectField); + if (fieldId == null) continue; + + if (!result.containsKey(fieldId)) + { + result.put(fieldId, new List()); + } + result.get(fieldId).add(record); + } + return result; + } + + /** + * Get a map with the record mapped to the given String field value + * Key fields containing null values are omitted + * + * @param sObjectField The field to use as key for the map + * + * @return Returns a map with the record mapped to the given String field value + * + * @example + * Account account = Account.newInstance(records); + * Map accountByNumber = account.getSObjectByStringField(Account.AccountNumber); + */ + @TestVisible + protected virtual Map getSObjectByStringField(Schema.SObjectField sObjectField) + { + Map result = new Map(); + for (SObject record : getRecords()) + { + if (record.get(sObjectField) == null) continue; + + String fieldValue = (String) record.get(sObjectField); + result.put(fieldValue, record); + } + return result; + } + + /** + * Get a map with the records mapped to the given String field value + * Key fields containing null values are omitted + * + * @param sObjectField The field to use as key for the map + * + * @return Returns a map with the records mapped to the given String field value + * + * @example + * Accounts accounts = Account.newInstance(records); + * Map> accountByName = accounts.getSObjectsByStringField(Account.AccountName); + */ + @TestVisible + protected virtual Map> getSObjectsByStringField(Schema.SObjectField sObjectField) + { + Map> result = new Map>(); + for (SObject record : getRecords()) + { + String fieldValue = (String) record.get(sObjectField); + if (fieldValue == null) continue; + + if (!result.containsKey(fieldValue)) + { + result.put(fieldValue, new List()); + } + result.get(fieldValue).add(record); + } + return result; + } + + /** + * Get a map with the given String field value mapped to the given Id field + * Key fields containing null values are omitted + * + * @param valueField The String field to use as value for the map + * @param keyField The Id field to use as key for the map + * + * @return a map with the given String field value mapped to the given Id field + * + * @example + * Account account = Account.newInstance(records); + * Map accountNameById = account.getStringFieldByIdField(Account.AccountName, Account.Id); + */ + @TestVisible + protected virtual Map getStringFieldByIdField(Schema.SObjectField valueField, Schema.SObjectField keyField) + { + Map result = new Map(); + Map fieldByField = getFieldByField(valueField, keyField); + for (Object obj : fieldByField.keySet()) + { + result.put((Id) obj, (String) fieldByField.get(obj)); + } + return result; + } + + /** + * Get a map with the given Date field value mapped to the given Id field + * Key fields containing null values are omitted + * + * @param valueField The Date field to use as value for the map + * @param keyField The Id field to use as key for the map + * + * @return a map with the given Date field value mapped to the given Id field + * + * @example + * Account account = Account.newInstance(records); + * Map createdDateById = account.getDateFieldByIdField(Account.CreatedDate, Account.Id); + */ + @TestVisible + protected virtual Map getDateFieldByIdField(Schema.SObjectField valueField, Schema.SObjectField keyField) + { + Map result = new Map(); + Map fieldByField = getFieldByField(valueField, keyField); + for (Object obj : fieldByField.keySet()) + { + Object value = fieldByField.get(obj); + Date dateValue; + if (value instanceof Date) + { + dateValue = (Date) value; + } + else if (value != null) + { + dateValue = ((Datetime) value).date(); + } + result.put((Id) obj, dateValue); + } + return result; + } + + /** + * Get a map with the given Date field value mapped to the given Id field + * Key fields containing null values are omitted + * + * @param valueField The DateTime field to use as value for the map + * @param keyField The Id field to use as key for the map + * + * @return a map with the given Date field value mapped to the given Id field + * + * @example + * Account account = Account.newInstance(records); + * Map createdDateById = account.getDateFieldByIdField(Account.CreatedDate, Account.Id); + */ + @TestVisible + protected virtual Map getDateTimeFieldByIdField(Schema.SObjectField valueField, Schema.SObjectField keyField) + { + Map result = new Map(); + Map fieldByField = getFieldByField(valueField, keyField); + for (Object obj : fieldByField.keySet()) + { + result.put((Id) obj, (Datetime) fieldByField.get(obj)); + } + return result; + } + + /** + * Get a map with the records mapped to the given String field value + * Key fields containing null values are omitted + * + * @param valueField The field to use as value for the map + * @param keyField The field to use as key for the map + * + * @return Returns a map with the record mapped to the given Id field value + * + * @example + * Account account = Account.newInstance(records); + * Map accountNameById = account.getStringFieldByStringField(Account.AccountName, Account.Id); + */ + @TestVisible + protected virtual Map getStringFieldByStringField(Schema.SObjectField valueField, Schema.SObjectField keyField) + { + Map result = new Map(); + Map fieldByField = getFieldByField(keyField, valueField); + for (Object obj : fieldByField.keySet()) + { + result.put((String) obj, (String) fieldByField.get(obj)); + } + return result; + } + + + /** + * @param sObjectField The Schema.SObjectField to get their values + * @param criteria The criteria condition that must be met to include the value in the return + * + * @return The String values of the given sObjectField + */ + @TestVisible + protected virtual fflib_Strings getStringFieldValues(Schema.SObjectField sObjectField, fflib_Criteria criteria) + { + return new fflib_Strings(new fflib_SObjects2(getRecords(criteria), getSObjectType()) + .getStringFieldValues(sObjectField)); + } + + /** + * Sets the given value to the given field only when the criteria is met for the record + * + * @param sObjectField The Schema.SObjectField to change its value + * @param value The new value for the given sObjectField + * @param criteria The criteria condition that must be met to include the value in the return + */ + @TestVisible + protected virtual void setFieldValue(Schema.SObjectField sObjectField, Object value, fflib_Criteria criteria) + { + new fflib_SObjects2(getRecords(criteria), getSObjectType()) + .setFieldValue(sObjectField, value); + } + + /** + * Sets a value to the given field only when key field Id value is provided in the given map + * + * @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 + */ + @TestVisible + protected virtual void setFieldValue( + Schema.SObjectField sObjectIdFieldToCheck, + Schema.SObjectField sObjectFieldToUpdate, + Map values) + { + for (SObject record : getRecords()) + { + Id keyValue = (Id) record.get(sObjectIdFieldToCheck); + if (values?.containsKey(keyValue)) + { + record.put(sObjectFieldToUpdate, values.get(keyValue)); + } + } + } + + /** + * Sets a value to the given field only when key field String value is provided in the given map + * + * @param sObjectStringFieldToCheck The SObject String 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 + */ + @TestVisible + protected virtual void setFieldValue( + Schema.SObjectField sObjectStringFieldToCheck, + Schema.SObjectField sObjectFieldToUpdate, + Map values) + { + for (SObject record : getRecords()) + { + String keyValue = (String) record.get(sObjectStringFieldToCheck); + if (values?.containsKey(keyValue)) + { + record.put(sObjectFieldToUpdate, values.get(keyValue)); + } + } + + } + + public class DeveloperException extends Exception { } +} \ No newline at end of file diff --git a/sfdx-source/apex-extensions/tests/classes/domains/fflib_SObjects2Test.cls b/sfdx-source/apex-extensions/tests/classes/domains/fflib_SObjects2Test.cls index e0bb4d6..506b241 100644 --- a/sfdx-source/apex-extensions/tests/classes/domains/fflib_SObjects2Test.cls +++ b/sfdx-source/apex-extensions/tests/classes/domains/fflib_SObjects2Test.cls @@ -29,931 +29,814 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ @IsTest(IsParallel=true) -private class fflib_SObjects2Test { - @IsTest - static void itShouldAddErrorMessage() { - SObjectType accountSObjectType = Schema.Account.SObjectType; - final Id idA = fflib_IDGenerator.generate(accountSObjectType); - final Id idB = fflib_IDGenerator.generate(accountSObjectType); - - DomainAccounts domain = new DomainAccounts( - new List{ new Account(Id = idA), new Account(Id = idB) } - ); - - domain.addError(Schema.Account.Name, 'Oops'); - - System.Assert.areEqual(2, fflib_SObjects.Errors.getAll().size()); - } - - @IsTest - static void itShouldClearTheField() { - Account record = new Account(ShippingCountry = 'Holland'); - DomainAccounts domain = new DomainAccounts(new List{ record }); - System.Assert.isFalse( - domain.selectByShippingCountry('Holland').isEmpty(), - 'Incorrect test data' - ); - - domain.clearShippingCountry(); - - System.Assert.isTrue( - domain.selectByShippingCountry('Holland').isEmpty(), - 'Field should have been nullified' - ); - } - - @IsTest - static void itShouldReturnTheCreatedData() { - System.Assert.areEqual( - (Object) Schema.Account.SObjectType, - new DomainAccounts(new List()).getType(), - 'Unexpected Domain Type' - ); - System.Assert.areEqual( - Schema.Account.SObjectType, - new DomainAccounts(new List()).getSObjectType(), - 'Unexpected Domain SObjectType' - ); - } - - @IsTest - static void itShouldReturnTheDomainsType() { - fflib_Criteria criteria = new fflib_Criteria().equalTo(Account.Name, 'A'); - - DomainAccounts domain = new DomainAccounts( - new List{ - new Account( - Id = fflib_IDGenerator.generate(Account.SObjectType), - Name = 'A', - ShippingCountry = 'USA', - AnnualRevenue = 5, - BillingLatitude = 121.0 - ), - new Account( - Id = fflib_IDGenerator.generate(Account.SObjectType), - Name = 'B', - ShippingCountry = 'Ireland', - AnnualRevenue = 3 - ), - new Account( - Id = fflib_IDGenerator.generate(Account.SObjectType), - Name = 'C', - ShippingCountry = 'UK', - AnnualRevenue = 2 - ), - new Account( - Id = fflib_IDGenerator.generate(Account.SObjectType), - Name = 'D', - ShippingCountry = '', - AnnualRevenue = 1 - ), - new Account( - Id = fflib_IDGenerator.generate(Account.SObjectType), - Name = 'E' - ), - new Account( - Id = fflib_IDGenerator.generate(Account.SObjectType), - BillingLatitude = 121.0 - ) - } - ); - domain.getDateTimeFieldValues(Account.LastActivityDate); - domain.getDateTimeFieldValues(Account.CreatedDate, criteria); - domain.getFieldByField(Account.Name, Account.AnnualRevenue); - domain.getFieldsByField(Account.Id, Account.AnnualRevenue); - domain.getFieldByField(Account.Id, Account.Id); - domain.getIdFieldsByIdField(Account.Id, Account.Id); - domain.getIdFieldsByStringField(Account.Id, Account.Name); - domain.getIdFieldValues(Account.Id); - domain.getIdFieldValues(Account.Id, criteria); - domain.getDecimalFieldValues(Account.BillingLatitude, criteria); - domain.getDoubleFieldValues(Account.BillingLatitude); - domain.getDoubleFieldValues(Account.BillingLatitude, criteria); - domain.getSObjectByIdField(Account.Id); - domain.getSObjectsByIdField(Account.Id); - domain.getSObjectByStringField(Account.Name); - domain.getSObjectsByStringField(Account.Name); - domain.getStringFieldByStringField(Account.Name, Account.AccountNumber); - domain.getStringFieldValues(Account.Name, criteria); - domain.stripInaccessibleFields(); - domain.getDateFieldValues(Account.CreatedDate); - domain.getDateFieldValues(Account.CreatedDate, criteria); - domain.getIdFieldValues(Account.Id, criteria); - domain.getRecords(Account.Id, domain.getFirstSObject().Id); - domain.getRecords(Account.Name, 'A'); - domain.getRecordsIsNot(Account.Name, 'A'); - domain.getRecordsIsNot(Account.Id, domain.getFirstSObject().Id); - domain.getSObjectByIdField(Account.Id); - domain.getIdFieldValues(Account.Id, true); - // todo - add assertions - } - - @IsTest - static void itShouldReturnTheRelatedChildDomainId_deprecated() { - // GIVEN a case A & Z related to contact A related to Account, - Id caseIdA = fflib_IDGenerator.generate(Schema.Case.SObjectType); - Id caseIdZ = fflib_IDGenerator.generate(Schema.Case.SObjectType); - Id caseIdB = fflib_IDGenerator.generate(Schema.Case.SObjectType); - Id caseIdC = fflib_IDGenerator.generate(Schema.Case.SObjectType); - Id contactIdA = fflib_IDGenerator.generate(Schema.Contact.SObjectType); - Id contactIdB = fflib_IDGenerator.generate(Schema.Contact.SObjectType); - Id accountId = fflib_IDGenerator.generate(Schema.Account.SObjectType); - Account accountRecord = new Account(Id = accountId); - Contact contactRecordA = new Contact( - Id = contactIdA, - AccountId = accountId - ); - Contact contactRecordB = new Contact(Id = contactIdB); - Case caseRecordA = new Case(Id = caseIdA, ContactId = contactIdA); - Case caseRecordZ = new Case(Id = caseIdZ, ContactId = contactIdA); - Case caseRecordB = new Case(Id = caseIdB, ContactId = contactIdB); - Case caseRecordC = new Case(Id = caseIdC); - - DomainAccounts accountDomain = new DomainAccounts( - new List{ accountRecord } - ); - DomainContacts contactDomain = new DomainContacts( - new List{ contactRecordA, contactRecordB } - ); - DomainCases caseDomain = new DomainCases( - new List{ caseRecordA, caseRecordB, caseRecordC, caseRecordZ } - ); - - // WHEN we request the relation between Case and Account - System.Test.startTest(); - Map> result = accountDomain.getChildIdsById( - new List{ contactDomain, caseDomain } - ); - System.Test.stopTest(); - - // THEN it should return the AccountId By CaseId - System.Assert.areEqual(1, result.size(), 'Expected one account'); - System.Assert.isTrue( - result.containsKey(accountId), - 'Account Id should be the main key' - ); - System.Assert.areEqual( - 2, - result.get(accountId).size(), - 'Incorrect amount of related cases to the account' - ); - System.Assert.isTrue( - result.get(accountId).containsAll(new Set{ caseIdA, caseIdZ }) - ); - } - @IsTest - static void itShouldReturnTheRelatedChildDomainId() { - // GIVEN a case A & Z related to contact A related to Account, - Id caseIdA = fflib_IDGenerator.generate(Schema.Case.SObjectType); - Id caseIdZ = fflib_IDGenerator.generate(Schema.Case.SObjectType); - Id caseIdB = fflib_IDGenerator.generate(Schema.Case.SObjectType); - Id caseIdC = fflib_IDGenerator.generate(Schema.Case.SObjectType); - Id contactIdA = fflib_IDGenerator.generate(Schema.Contact.SObjectType); - Id contactIdB = fflib_IDGenerator.generate(Schema.Contact.SObjectType); - Id accountId = fflib_IDGenerator.generate(Schema.Account.SObjectType); - Account accountRecord = new Account(Id = accountId); - Contact contactRecordA = new Contact( - Id = contactIdA, - AccountId = accountId - ); - Contact contactRecordB = new Contact(Id = contactIdB); - Case caseRecordA = new Case(Id = caseIdA, ContactId = contactIdA); - Case caseRecordZ = new Case(Id = caseIdZ, ContactId = contactIdA); - Case caseRecordB = new Case(Id = caseIdB, ContactId = contactIdB); - Case caseRecordC = new Case(Id = caseIdC); - - DomainAccounts accountDomain = new DomainAccounts( - new List{ accountRecord } - ); - DomainContacts contactDomain = new DomainContacts( - new List{ contactRecordA, contactRecordB } - ); - DomainCases caseDomain = new DomainCases( - new List{ caseRecordA, caseRecordB, caseRecordC, caseRecordZ } - ); - - // WHEN we request the relation between Case and Account - System.Test.startTest(); - Map> result = accountDomain.getChildIdsById( - new Map{ - Contact.AccountId => contactDomain, - Case.ContactId => caseDomain - } - ); - System.Test.stopTest(); - - // THEN it should return the AccountId By CaseId - System.Assert.areEqual(1, result.size(), 'Expected one account'); - System.Assert.isTrue( - result.containsKey(accountId), - 'Account Id should be the main key' - ); - System.Assert.areEqual( - 2, - result.get(accountId).size(), - 'Incorrect amount of related cases to the account' - ); - System.Assert.isTrue( - result.get(accountId).containsAll(new Set{ caseIdA, caseIdZ }) - ); - } - - @IsTest - static void itShouldReturnTheRelatedParentDomainId() { - // GIVEN a case related to contact related to Account , - // a case record related to contact but not to Account, - // and a case record related to nothing. - // All encapsulated in domains. - Id caseIdA = fflib_IDGenerator.generate(Schema.Case.SObjectType); - Id caseIdB = fflib_IDGenerator.generate(Schema.Case.SObjectType); - Id caseIdC = fflib_IDGenerator.generate(Schema.Case.SObjectType); - Id contactIdA = fflib_IDGenerator.generate(Schema.Contact.SObjectType); - Id contactIdB = fflib_IDGenerator.generate(Schema.Contact.SObjectType); - Id accountId = fflib_IDGenerator.generate(Schema.Account.SObjectType); - Account accountRecord = new Account(Id = accountId); - Contact contactRecordA = new Contact( - Id = contactIdA, - AccountId = accountId - ); - Contact contactRecordB = new Contact(Id = contactIdB); - Case caseRecordA = new Case(Id = caseIdA, ContactId = contactIdA); - Case caseRecordB = new Case(Id = caseIdB, ContactId = contactIdB); - Case caseRecordC = new Case(Id = caseIdC); - - DomainAccounts accountDomain = new DomainAccounts( - new List{ accountRecord } - ); - DomainContacts contactDomain = new DomainContacts( - new List{ contactRecordA, contactRecordB } - ); - DomainCases caseDomain = new DomainCases( - new List{ caseRecordA, caseRecordB, caseRecordC } - ); - - // WHEN we request the relation between Case and Account - System.Test.startTest(); - Map result = caseDomain.getParentIdById( - new Map{ - Schema.Case.ContactId => contactDomain, - Schema.Contact.AccountId => accountDomain - } - ); - System.Test.stopTest(); - - // THEN it should return the AccountId By CaseId - System.Assert.areEqual( - 3, - result.size(), - 'Expected one related account to the case' - ); - System.Assert.isTrue(result.containsKey(caseIdA)); - System.Assert.isTrue(result.containsKey(caseIdB)); - System.Assert.isTrue(result.containsKey(caseIdC)); - System.Assert.areEqual( - accountId, - result.get(caseIdA), - 'Account Id should be related to the Case Id A' - ); - System.Assert.isNull( - result.get(caseIdB), - 'Case Id B should have no related Account Id' - ); - System.Assert.isNull( - result.get(caseIdC), - 'Case Id B should have no related Account Id' - ); - } - - /** Unit test for the deprecated method **/ - @IsTest - static void itShouldReturnTheRelatedParentDomainId_deprecated() { - // GIVEN a case related to contact related to Account , - // a case record related to contact but not to Account, - // and a case record related to nothing. - // All encapsulated in domains. - Id caseIdA = fflib_IDGenerator.generate(Schema.Case.SObjectType); - Id caseIdB = fflib_IDGenerator.generate(Schema.Case.SObjectType); - Id caseIdC = fflib_IDGenerator.generate(Schema.Case.SObjectType); - Id contactIdA = fflib_IDGenerator.generate(Schema.Contact.SObjectType); - Id contactIdB = fflib_IDGenerator.generate(Schema.Contact.SObjectType); - Id accountId = fflib_IDGenerator.generate(Schema.Account.SObjectType); - Account accountRecord = new Account(Id = accountId); - Contact contactRecordA = new Contact( - Id = contactIdA, - AccountId = accountId - ); - Contact contactRecordB = new Contact(Id = contactIdB); - Case caseRecordA = new Case(Id = caseIdA, ContactId = contactIdA); - Case caseRecordB = new Case(Id = caseIdB, ContactId = contactIdB); - Case caseRecordC = new Case(Id = caseIdC); - - DomainAccounts accountDomain = new DomainAccounts( - new List{ accountRecord } - ); - DomainContacts contactDomain = new DomainContacts( - new List{ contactRecordA, contactRecordB } - ); - DomainCases caseDomain = new DomainCases( - new List{ caseRecordA, caseRecordB, caseRecordC } - ); - - // WHEN we request the relation between Case and Account - System.Test.startTest(); - Map result = caseDomain.getGrandParentIdById( - new List{ contactDomain, accountDomain } - ); - System.Test.stopTest(); - - // THEN it should return the AccountId By CaseId - System.Assert.areEqual( - 3, - result.size(), - 'Expected one related account to the case' - ); - System.Assert.isTrue(result.containsKey(caseIdA)); - System.Assert.isTrue(result.containsKey(caseIdB)); - System.Assert.isTrue(result.containsKey(caseIdC)); - System.Assert.areEqual( - accountId, - result.get(caseIdA), - 'Account Id should be related to the Case Id A' - ); - System.Assert.isNull( - result.get(caseIdB), - 'Case Id B should have no related Account Id' - ); - System.Assert.isNull( - result.get(caseIdC), - 'Case Id B should have no related Account Id' - ); - } - - @IsTest - static void itShouldReturnDecimalById() { - final Id accountId = fflib_IDGenerator.generate(Schema.Account.SObjectType); - final Account record = new Account(Id = accountId, AnnualRevenue = 123.45); - fflib_SObjects2 domain = new fflib_SObjects2(new List{ record }); - System.Test.startTest(); - Map result = domain.getDecimalById( - Schema.Account.AnnualRevenue, - Schema.Account.Id - ); - System.Test.stopTest(); - } - - @IsTest - static void itShouldReturnStringById() { - final String accountName = 'My Account'; - final Id accountId = fflib_IDGenerator.generate(Schema.Account.SObjectType); - final Account record = new Account(Id = accountId, Name = accountName); - fflib_SObjects2 domain = new fflib_SObjects2(new List{ record }); - System.Test.startTest(); - Map nameById = domain.getIdFieldByStringField( - Schema.Account.Id, - Schema.Account.Name - ); - System.Test.stopTest(); - System.Assert.isTrue(nameById.containsKey(accountName)); - System.Assert.areEqual(accountId, nameById.get(accountName)); - } - - @IsTest - static void itShouldReturnStringFieldByIdField() { - final String accountName = 'My Account'; - final Id accountId = fflib_IDGenerator.generate(Account.SObjectType); - DomainAccounts domain = new DomainAccounts( - new List{ - new Account(Id = accountId, Name = accountName), - new Account(Name = accountName + ' 2') // This one should be ignored - } - ); - - System.Test.startTest(); - Map result = domain.getStringFieldByIdField( - Account.Name, - Account.Id - ); - System.Test.stopTest(); - - System.Assert.areEqual( - 1, - result.size(), - 'Incorrect returned amount of results' - ); - System.Assert.isTrue( - result.keySet().contains(accountId), - 'The accountId is missing from the results' - ); - System.Assert.areEqual( - accountName, - result.get(accountId), - 'Incorrect returned account name' - ); - } - - @IsTest - static void itShouldReturnDateFieldByIdField() { - final Date today = Date.today(); - final Datetime todayDatetime = Datetime.newInstance( - today.year(), - today.month(), - today.day() - ); - final String accountName = 'My Account'; - final Id accountId = fflib_IDGenerator.generate(Account.SObjectType); - DomainAccounts domain = new DomainAccounts( - new List{ - (Account) fflib_MockSObjectUtil.addFieldValue( - new Account(Id = accountId), - Account.CreatedDate, - todayDatetime - ), - new Account(Name = accountName + ' 2') // This one should be ignored - } - ); - - System.Test.startTest(); - Map result = domain.getDateFieldByIdField( - Account.CreatedDate, - Account.Id - ); - System.Test.stopTest(); - - System.Assert.areEqual( - 1, - result.size(), - 'Incorrect returned amount of results' - ); - System.Assert.istrue( - result.keySet().contains(accountId), - 'The accountId is missing from the results' - ); - System.Assert.areEqual( - today, - result.get(accountId), - 'Incorrect returned date' - ); - } - - @IsTest - static void itShouldReturnIntegerFieldValues() { - final Integer numberOfEmployees = 10; - final String accountName = 'Test Account'; - DomainAccounts domain = new DomainAccounts( - new List{ - new Account(NumberOfEmployees = numberOfEmployees), - new Account( - Name = accountName, - NumberOfEmployees = numberOfEmployees * 2 - ), - new Account() // This one should be ignored - } - ); - - System.Test.startTest(); - Set result = domain.getIntegerFieldValues( - Account.NumberOfEmployees - ) - .getIntegerSet(); - Set result2 = domain.getIntegerFieldValues( - Account.NumberOfEmployees, - new fflib_Criteria().equalTo(Schema.Account.Name, accountName) - ) - .getIntegerSet(); - System.Test.stopTest(); - - System.Assert.areEqual(2, result.size(), 'Incorrect amount of results'); - System.Assert.istrue( - result.contains(numberOfEmployees), - 'The expected numberOfEmployees was not returned' - ); - System.Assert.istrue( - result.contains(numberOfEmployees * 2), - 'The expected numberOfEmployees was not returned' - ); - - System.Assert.areEqual(1, result2.size(), 'Incorrect amount of results'); - System.Assert.istrue( - result2.contains(numberOfEmployees * 2), - 'The expected numberOfEmployees was not returned' - ); - } - - @IsTest - static void itShouldReturnLongFieldValues() { - final Integer numberOfEmployees = 10; - final String accountName = 'Test Account'; - DomainAccounts domain = new DomainAccounts( - new List{ - new Account(NumberOfEmployees = numberOfEmployees), - new Account( - Name = accountName, - NumberOfEmployees = numberOfEmployees * 2 - ), - new Account() // This one should be ignored - } - ); - - System.Test.startTest(); - Set result = domain.getLongFieldValues(Account.NumberOfEmployees) - .getLongSet(); - Set result2 = domain.getLongFieldValues( - Account.NumberOfEmployees, - new fflib_Criteria().equalTo(Schema.Account.Name, accountName) - ) - .getLongSet(); - System.Test.stopTest(); - - System.Assert.areEqual(2, result.size(), 'Incorrect amount of results'); - System.Assert.istrue( - result.contains(numberOfEmployees), - 'The expected numberOfEmployees was not returned' - ); - System.Assert.istrue( - result.contains(numberOfEmployees * 2), - 'The expected numberOfEmployees was not returned' - ); - - System.Assert.areEqual(1, result2.size(), 'Incorrect amount of results'); - System.Assert.istrue( - result2.contains(numberOfEmployees * 2), - 'The expected numberOfEmployees was not returned' - ); - } - - @IsTest - static void itShouldReturnRecordIdById() { - final Id contactId = fflib_IDGenerator.generate(Schema.Contact.SObjectType); - final Id accountId = fflib_IDGenerator.generate(Schema.Account.SObjectType); - final Contact record = new Contact(Id = contactId, AccountId = accountId); - fflib_SObjects2 domain = new fflib_SObjects2(new List{ record }); - System.Test.startTest(); - Map accountIdByContactId = domain.getIdFieldByIdField( - Schema.Contact.AccountId, - Schema.Contact.Id - ); - System.Test.stopTest(); - System.Assert.istrue(accountIdByContactId.containsKey(contactId)); - System.Assert.areEqual(accountId, accountIdByContactId.get(contactId)); - } - - @IsTest - static void itShouldReturnRecordByIds() { - SObjectType accountSObjectType = Schema.Account.SObjectType; - final Id idA = fflib_IDGenerator.generate(accountSObjectType); - final Id idB = fflib_IDGenerator.generate(accountSObjectType); - final Id idC = fflib_IDGenerator.generate(accountSObjectType); - - DomainAccounts domain = new DomainAccounts( - new List{ - new Account(Id = idA), - new Account(Id = idB), - new Account(Id = idC) - } - ); - - Set recordIds = new Set{ idA, idB, idC }; - System.Assert.istrue( - domain.getSObjectById().keySet().containsAll(recordIds), - 'The domain should return all the record Ids' - ); - } - - @IsTest - static void itShouldReturnRecordsIds() { - SObjectType accountSObjectType = Schema.Account.SObjectType; - Id idA = fflib_IDGenerator.generate(accountSObjectType); - Id idB = fflib_IDGenerator.generate(accountSObjectType); - Id idC = fflib_IDGenerator.generate(accountSObjectType); - - DomainAccounts domain = new DomainAccounts( - new List{ - new Account(Id = idA), - new Account(Id = idB), - new Account(Id = idC) - } - ); - - Set recordIds = new Set{ idA, idB, idC }; - System.Assert.istrue( - domain.getRecordIds().containsAll(recordIds), - 'The domain should return all the record Ids' - ); - } - - @IsTest - static void itShouldReturnRecords() { - DomainAccounts domain = generateDomain(); - - System.Assert.areEqual(6, domain.getRecords().size()); - } - - @IsTest - static void itShouldReturnRecordByCriteria() { - final Id idA = fflib_IDGenerator.generate(Schema.Account.SObjectType); - DomainAccounts domain = new DomainAccounts( - new List{ - new Account(Name = 'A', Id = idA), - new Account( - Name = 'B', - Id = fflib_IDGenerator.generate(Schema.Account.SObjectType) - ) - } - ); - - System.Assert.areEqual( - 'A', - domain.getRecords(new fflib_Criteria().equalTo(Schema.Account.Id, idA)) - .get(0) - .get('Name') - ); - } - - @IsTest - static void itShouldReturnRecordById() { - final Id idA = fflib_IDGenerator.generate(Schema.Account.SObjectType); - DomainAccounts domain = new DomainAccounts( - new List{ - new Account(Name = 'A', Id = idA), - new Account( - Name = 'B', - Id = fflib_IDGenerator.generate(Schema.Account.SObjectType) - ) - } - ); - - System.Assert.areEqual('A', domain.getRecord(idA).get('Name')); - } - - @IsTest - static void itShouldReturnRecordsById() { - final Id idA = fflib_IDGenerator.generate(Schema.Account.SObjectType); - final fflib_Ids ids = new fflib_Ids(new Set{ idA }); - DomainAccounts domain = new DomainAccounts( - new List{ - new Account(Name = 'A', Id = idA), - new Account( - Name = 'B', - Id = fflib_IDGenerator.generate(Schema.Account.SObjectType) - ) - } - ); - - System.Assert.areEqual('A', domain.getRecords(ids).get(0).get('Name')); - } - - @IsTest - static void itShouldReturnRecordsByIds() { - final Id idA = fflib_IDGenerator.generate(Schema.Account.SObjectType); - DomainAccounts domain = new DomainAccounts( - new List{ - new Account(Name = 'A', Id = idA), - new Account( - Name = 'B', - Id = fflib_IDGenerator.generate(Schema.Account.SObjectType) - ) - } - ); - - System.Assert.areEqual( - 'A', - domain.getRecords(new Set{ idA }).get(0).get('Name') - ); - } - - @IsTest - static void itShouldReturnRecordsWithFieldValues() { - DomainAccounts domain = generateDomain(); - - System.Assert.areEqual(1, domain.selectByShippingCountry('USA').size()); - } - - @IsTest - static void itShouldReturnRecordsWithoutFieldValues() { - DomainAccounts domain = generateDomain(); - - System.Assert.areEqual(3, domain.selectWithoutShippingCountry().size()); - } - - @IsTest - static void itShouldReturnRecordsWithoutAllFieldValues() { - DomainAccounts domain = generateDomain(); - - System.Assert.areEqual(1, domain.selectWithEmptyRecord().size()); - } - - @IsTest - static void itShouldReturnRecordsWithShippingCountry() { - DomainAccounts domain = generateDomain(); - - System.Assert.areEqual(3, domain.selectWithShippingCountry().size()); - } - - @IsTest - static void itShouldReturnRecordsWithAllFieldValues() { - DomainAccounts domain = generateDomain(); - - System.Assert.areEqual(3, domain.selectPopulatedRecords().size()); - } - - @IsTest - static void itShouldReturnFieldValues() { - DomainAccounts domain = generateDomain(); - - System.Assert.istrue( - domain.getStringFieldValues(Schema.Account.ShippingCountry) - .containsAll(new Set{ 'USA', 'Ireland', 'UK', '' }) - ); - } - - @IsTest - static void itShouldSetFieldValue() { - DomainAccounts domain = generateDomain(); - String country = 'Holland'; - domain.setShippingCountry(country); - - System.Assert.areEqual(6, domain.selectByShippingCountry(country).size()); - } - - @IsTest - static void itShouldSetFieldValueByCondition() { - DomainAccounts domain = generateDomain(); - domain.setRatingByShippingCountry( - new Map{ 'USA' => 'Hot' } - ); - - System.Assert.areEqual(1, domain.selectByRating('Hot').size()); - } - - @IsTest - static void itShouldGetTheSumOfAnnualRevenue() { - DomainAccounts domain = generateDomain(); - System.Assert.areEqual( - 11, - domain.getDecimalFieldSum(Account.AnnualRevenue) - ); - System.Assert.isTrue( - domain.getDecimalFieldValues(Account.AnnualRevenue).contains((Decimal) 5) - ); - } - - @IsTest - static void itShouldSetFieldByIdField() { - Id accountId = fflib_IDGenerator.generate(Account.SObjectType); - Account record = new Account(Id = accountId, Name = ''); - fflib_SObjects2 domain = new fflib_SObjects2(new List{ record }); - - domain.setFieldValue( - Schema.Account.Id, - Schema.Account.Name, - new Map{ accountId => 'Hello' } - ); - - System.Assert.areEqual('Hello', domain.getFirstSObject().get('Name')); - } - - @IsTest - static void itShouldSetFieldByStringField() { - Account record = new Account(Name = 'Hello', Rating = 'Cold'); - fflib_SObjects2 domain = new fflib_SObjects2(new List{ record }); - - domain.setFieldValue( - Schema.Account.Name, - Schema.Account.Rating, - new Map{ 'Hello' => 'Warm' } - ); - - System.Assert.areEqual('Warm', domain.getFirstSObject().get('Rating')); - } - - @IsTest - static void itShouldSetField() { - Account record = new Account(Name = 'Hello', Rating = 'Cold'); - fflib_SObjects2 domain = new fflib_SObjects2(new List{ record }); - - domain.setFieldValue( - Account.Name, - 'Hello World', - new fflib_Criteria().equalTo(Account.Rating, 'Cold') - ); - - System.Assert.areEqual('Hello World', domain.getFirstSObject().get('Name')); - } - - private static DomainAccounts generateDomain() { - DomainAccounts domain = new DomainAccounts( - new List{ - new Account(Name = 'A', ShippingCountry = 'USA', AnnualRevenue = 5), - new Account(Name = 'B', ShippingCountry = 'Ireland', AnnualRevenue = 3), - new Account(Name = 'C', ShippingCountry = 'UK', AnnualRevenue = 2), - new Account(Name = 'D', ShippingCountry = '', AnnualRevenue = 1), - new Account(Name = 'E'), - new Account() - } - ); - return domain; - } - - private class DomainAccounts extends fflib_SObjects2 { - public DomainAccounts(List records) { - super(records, Schema.Account.SObjectType); - } - - public List selectByShippingCountry(String country) { - return (List) getRecordsByFieldValues( - Schema.Account.ShippingCountry, - new Set{ country } - ); - } - - public List selectByRating(String rating) { - return (List) getRecordsByFieldValue( - Schema.Account.Rating, - rating - ); - } - - public List selectWithoutShippingCountry() { - return (List) getRecordsWithBlankFieldValues( - Schema.Account.ShippingCountry - ); - } - - public List selectWithShippingCountry() { - return (List) getRecordsWithNotBlankFieldValues( - Schema.Account.ShippingCountry - ); - } - - public List selectWithEmptyRecord() { - return (List) getRecordsWithAllBlankFieldValues( - new Set{ - Schema.Account.Name, - Schema.Account.ShippingCountry - } - ); - } - - public List selectPopulatedRecords() { - return (List) getRecordsWithAllNotBlankFieldValues( - new Set{ - Schema.Account.Name, - Schema.Account.ShippingCountry - } - ); - } - - public void setShippingCountry(String country) { - setFieldValue(Schema.Account.ShippingCountry, country); - } - - public void setRatingByShippingCountry( - Map ratingByCountry - ) { - setFieldValueByMap( - Schema.Account.ShippingCountry, - Schema.Account.Rating, - ratingByCountry - ); - } - - public void addNameError(String message) { - addError(Schema.Account.Name, message); - } - - public void clearShippingCountry() { - clearField(Schema.Account.ShippingCountry); - } - - protected override Map getRelatedFieldByDomainType() { - return new Map{ - Schema.Contact.SObjectType => Contact.AccountId - }; - } - } - - private class DomainContacts extends fflib_SObjects2 { - public DomainContacts(List records) { - super(records, Schema.Contact.SObjectType); - } - - protected override Map getRelatedFieldByDomainType() { - return new Map{ - Schema.Account.SObjectType => Contact.AccountId, - Schema.Case.SObjectType => Case.ContactId - }; - } - } - - private class DomainCases extends fflib_SObjects2 { - public DomainCases(List records) { - super(records, Schema.Case.SObjectType); - } - - protected override Map getRelatedFieldByDomainType() { - return new Map{ - Schema.Contact.SObjectType => Case.ContactId - }; - } - } +private class fflib_SObjects2Test +{ + @IsTest + static void itShouldAddErrorMessage() + { + SObjectType accountSObjectType = Schema.Account.SObjectType; + final Id idA = fflib_IDGenerator.generate(accountSObjectType); + final Id idB = fflib_IDGenerator.generate(accountSObjectType); + + DomainAccounts domain = new DomainAccounts( + new List + { + new Account(Id = idA), + new Account(Id = idB) + } + ); + + domain.addError(Schema.Account.Name,'Oops'); + + System.Assert.areEqual( + 2, + fflib_SObjects.Errors.getAll().size() + ); + } + + @IsTest + static void itShouldClearTheField() + { + Account record = new Account(ShippingCountry = 'Holland'); + DomainAccounts domain = new DomainAccounts(new List {record}); + System.Assert.isFalse(domain.selectByShippingCountry('Holland').isEmpty(), 'Incorrect test data'); + + domain.clearShippingCountry(); + + System.Assert.isTrue(domain.selectByShippingCountry('Holland').isEmpty(), 'Field should have been nullified'); + } + + @IsTest + static void itShouldReturnTheCreatedData() + { + System.Assert.areEqual( + (Object) Schema.Account.SObjectType, + new DomainAccounts(new List()) + .getType(), + 'Unexpected Domain Type' + ); + System.Assert.areEqual( + Schema.Account.SObjectType, + new DomainAccounts(new List()) + .getSObjectType(), + 'Unexpected Domain SObjectType' + ); + } + + @IsTest + static void itShouldReturnTheDomainsType() + { + fflib_Criteria criteria = new fflib_Criteria().equalTo(Account.Name, 'A'); + + DomainAccounts domain = new DomainAccounts( + new List + { + new Account(Id = fflib_IDGenerator.generate(Account.SObjectType), Name = 'A', ShippingCountry = 'USA', AnnualRevenue = 5, BillingLatitude = 121.0), + new Account(Id = fflib_IDGenerator.generate(Account.SObjectType), Name = 'B', ShippingCountry = 'Ireland', AnnualRevenue = 3), + new Account(Id = fflib_IDGenerator.generate(Account.SObjectType), Name = 'C', ShippingCountry = 'UK', AnnualRevenue = 2), + new Account(Id = fflib_IDGenerator.generate(Account.SObjectType), Name = 'D', ShippingCountry = '', AnnualRevenue = 1), + new Account(Id = fflib_IDGenerator.generate(Account.SObjectType), Name = 'E'), + new Account(Id = fflib_IDGenerator.generate(Account.SObjectType), BillingLatitude = 121.0 ) + } + ); + domain.getDateTimeFieldValues(Account.LastActivityDate); + domain.getDateTimeFieldValues(Account.CreatedDate, criteria); + domain.getFieldByField(Account.Name, Account.AnnualRevenue); + domain.getFieldsByField(Account.Id, Account.AnnualRevenue); + domain.getFieldByField(Account.Id, Account.Id); + domain.getIdFieldsByIdField(Account.Id, Account.Id); + domain.getIdFieldsByStringField(Account.Name, Account.Id); + domain.getIdFieldValues(Account.Id); + domain.getIdFieldValues(Account.Id, criteria); + domain.getDecimalFieldValues(Account.BillingLatitude, criteria); + domain.getDoubleFieldValues(Account.BillingLatitude); + domain.getDoubleFieldValues(Account.BillingLatitude, criteria); + domain.getSObjectByIdField(Account.Id); + domain.getSObjectsByIdField(Account.Id); + domain.getSObjectByStringField(Account.Name); + domain.getSObjectsByStringField(Account.Name); + domain.getStringFieldByStringField(Account.Name, Account.AccountNumber); + domain.getStringFieldValues(Account.Name, criteria); + domain.stri + + // todo - add assertions + } + + @IsTest + static void itShouldReturnTheRelatedChildDomainId_deprecated() + { + // GIVEN a case A & Z related to contact A related to Account, + Id caseIdA = fflib_IDGenerator.generate(Schema.Case.SObjectType); + Id caseIdZ = fflib_IDGenerator.generate(Schema.Case.SObjectType); + Id caseIdB = fflib_IDGenerator.generate(Schema.Case.SObjectType); + Id caseIdC = fflib_IDGenerator.generate(Schema.Case.SObjectType); + Id contactIdA = fflib_IDGenerator.generate(Schema.Contact.SObjectType); + Id contactIdB = fflib_IDGenerator.generate(Schema.Contact.SObjectType); + Id accountId = fflib_IDGenerator.generate(Schema.Account.SObjectType); + Account accountRecord = new Account(Id = accountId); + Contact contactRecordA = new Contact(Id = contactIdA, AccountId = accountId); + Contact contactRecordB = new Contact(Id = contactIdB); + Case caseRecordA = new Case(Id = caseIdA, ContactId = contactIdA); + Case caseRecordZ = new Case(Id = caseIdZ, ContactId = contactIdA); + Case caseRecordB = new Case(Id = caseIdB, ContactId = contactIdB); + Case caseRecordC = new Case(Id = caseIdC); + + DomainAccounts accountDomain = new DomainAccounts(new List {accountRecord}); + DomainContacts contactDomain = new DomainContacts(new List {contactRecordA, contactRecordB}); + DomainCases caseDomain = new DomainCases(new List {caseRecordA, caseRecordB, caseRecordC, caseRecordZ}); + + // WHEN we request the relation between Case and Account + System.Test.startTest(); + Map> result = accountDomain.getChildIdsById( + new List + { + contactDomain, + caseDomain + } + ); + System.Test.stopTest(); + + // THEN it should return the AccountId By CaseId + System.Assert.areEqual(1, result.size(), 'Expected one account'); + System.Assert.isTrue(result.containsKey(accountId), 'Account Id should be the main key'); + System.Assert.areEqual(2, result.get(accountId).size(), 'Incorrect amount of related cases to the account'); + System.Assert.isTrue(result.get(accountId).containsAll(new Set{ caseIdA, caseIdZ })); + } + @IsTest + static void itShouldReturnTheRelatedChildDomainId() + { + // GIVEN a case A & Z related to contact A related to Account, + Id caseIdA = fflib_IDGenerator.generate(Schema.Case.SObjectType); + Id caseIdZ = fflib_IDGenerator.generate(Schema.Case.SObjectType); + Id caseIdB = fflib_IDGenerator.generate(Schema.Case.SObjectType); + Id caseIdC = fflib_IDGenerator.generate(Schema.Case.SObjectType); + Id contactIdA = fflib_IDGenerator.generate(Schema.Contact.SObjectType); + Id contactIdB = fflib_IDGenerator.generate(Schema.Contact.SObjectType); + Id accountId = fflib_IDGenerator.generate(Schema.Account.SObjectType); + Account accountRecord = new Account(Id = accountId); + Contact contactRecordA = new Contact(Id = contactIdA, AccountId = accountId); + Contact contactRecordB = new Contact(Id = contactIdB); + Case caseRecordA = new Case(Id = caseIdA, ContactId = contactIdA); + Case caseRecordZ = new Case(Id = caseIdZ, ContactId = contactIdA); + Case caseRecordB = new Case(Id = caseIdB, ContactId = contactIdB); + Case caseRecordC = new Case(Id = caseIdC); + + DomainAccounts accountDomain = new DomainAccounts(new List {accountRecord}); + DomainContacts contactDomain = new DomainContacts(new List {contactRecordA, contactRecordB}); + DomainCases caseDomain = new DomainCases(new List {caseRecordA, caseRecordB, caseRecordC, caseRecordZ}); + + // WHEN we request the relation between Case and Account + System.Test.startTest(); + Map> result = accountDomain.getChildIdsById( + new Map + { + Contact.AccountId => contactDomain, + Case.ContactId => caseDomain + } + ); + System.Test.stopTest(); + + // THEN it should return the AccountId By CaseId + System.Assert.areEqual(1, result.size(), 'Expected one account'); + System.Assert.isTrue(result.containsKey(accountId), 'Account Id should be the main key'); + System.Assert.areEqual(2, result.get(accountId).size(), 'Incorrect amount of related cases to the account'); + System.Assert.isTrue(result.get(accountId).containsAll(new Set{ caseIdA, caseIdZ })); + } + + @IsTest + static void itShouldReturnTheRelatedParentDomainId() + { + // GIVEN a case related to contact related to Account , + // a case record related to contact but not to Account, + // and a case record related to nothing. + // All encapsulated in domains. + Id caseIdA = fflib_IDGenerator.generate(Schema.Case.SObjectType); + Id caseIdB = fflib_IDGenerator.generate(Schema.Case.SObjectType); + Id caseIdC = fflib_IDGenerator.generate(Schema.Case.SObjectType); + Id contactIdA = fflib_IDGenerator.generate(Schema.Contact.SObjectType); + Id contactIdB = fflib_IDGenerator.generate(Schema.Contact.SObjectType); + Id accountId = fflib_IDGenerator.generate(Schema.Account.SObjectType); + Account accountRecord = new Account(Id = accountId); + Contact contactRecordA = new Contact(Id = contactIdA, AccountId = accountId); + Contact contactRecordB = new Contact(Id = contactIdB); + Case caseRecordA = new Case(Id = caseIdA, ContactId = contactIdA); + Case caseRecordB = new Case(Id = caseIdB, ContactId = contactIdB); + Case caseRecordC = new Case(Id = caseIdC); + + DomainAccounts accountDomain = new DomainAccounts(new List {accountRecord}); + DomainContacts contactDomain = new DomainContacts(new List {contactRecordA, contactRecordB}); + DomainCases caseDomain = new DomainCases(new List {caseRecordA, caseRecordB, caseRecordC}); + + // WHEN we request the relation between Case and Account + System.Test.startTest(); + Map result = caseDomain.getParentIdById( + new Map + { + Schema.Case.ContactId => contactDomain, + Schema.Contact.AccountId => accountDomain + } + ); + System.Test.stopTest(); + + // THEN it should return the AccountId By CaseId + System.Assert.areEqual(3, result.size(), 'Expected one related account to the case'); + System.Assert.isTrue(result.containsKey(caseIdA)); + System.Assert.isTrue(result.containsKey(caseIdB)); + System.Assert.isTrue(result.containsKey(caseIdC)); + System.Assert.areEqual(accountId, result.get(caseIdA), 'Account Id should be related to the Case Id A'); + System.Assert.isNull(result.get(caseIdB), 'Case Id B should have no related Account Id'); + System.Assert.isNull(result.get(caseIdC), 'Case Id B should have no related Account Id'); + } + + /** Unit test for the deprecated method **/ + @IsTest + static void itShouldReturnTheRelatedParentDomainId_deprecated() + { + // GIVEN a case related to contact related to Account , + // a case record related to contact but not to Account, + // and a case record related to nothing. + // All encapsulated in domains. + Id caseIdA = fflib_IDGenerator.generate(Schema.Case.SObjectType); + Id caseIdB = fflib_IDGenerator.generate(Schema.Case.SObjectType); + Id caseIdC = fflib_IDGenerator.generate(Schema.Case.SObjectType); + Id contactIdA = fflib_IDGenerator.generate(Schema.Contact.SObjectType); + Id contactIdB = fflib_IDGenerator.generate(Schema.Contact.SObjectType); + Id accountId = fflib_IDGenerator.generate(Schema.Account.SObjectType); + Account accountRecord = new Account(Id = accountId); + Contact contactRecordA = new Contact(Id = contactIdA, AccountId = accountId); + Contact contactRecordB = new Contact(Id = contactIdB); + Case caseRecordA = new Case(Id = caseIdA, ContactId = contactIdA); + Case caseRecordB = new Case(Id = caseIdB, ContactId = contactIdB); + Case caseRecordC = new Case(Id = caseIdC); + + DomainAccounts accountDomain = new DomainAccounts(new List {accountRecord}); + DomainContacts contactDomain = new DomainContacts(new List {contactRecordA, contactRecordB}); + DomainCases caseDomain = new DomainCases(new List {caseRecordA, caseRecordB, caseRecordC}); + + // WHEN we request the relation between Case and Account + System.Test.startTest(); + Map result = caseDomain.getGrandParentIdById( + new List + { + contactDomain, + accountDomain + } + ); + System.Test.stopTest(); + + // THEN it should return the AccountId By CaseId + System.Assert.areEqual(3, result.size(), 'Expected one related account to the case'); + System.Assert.isTrue(result.containsKey(caseIdA)); + System.Assert.isTrue(result.containsKey(caseIdB)); + System.Assert.isTrue(result.containsKey(caseIdC)); + System.Assert.areEqual(accountId, result.get(caseIdA), 'Account Id should be related to the Case Id A'); + System.Assert.isNull(result.get(caseIdB), 'Case Id B should have no related Account Id'); + System.Assert.isNull(result.get(caseIdC), 'Case Id B should have no related Account Id'); + } + + @IsTest + static void itShouldReturnDecimalById() { + final Id accountId = fflib_IDGenerator.generate(Schema.Account.SObjectType); + final Account record = new Account(Id = accountId, AnnualRevenue = 123.45); + fflib_SObjects2 domain = new fflib_SObjects2(new List{ record }); + System.Test.startTest(); + Map result = domain.getDecimalById(Schema.Account.AnnualRevenue, Schema.Account.Id); + System.Test.stopTest(); + } + + @IsTest + static void itShouldReturnStringById() + { + final String accountName = 'My Account'; + final Id accountId = fflib_IDGenerator.generate(Schema.Account.SObjectType); + final Account record = new Account(Id = accountId, Name = accountName); + fflib_SObjects2 domain = new fflib_SObjects2(new List{ record }); + System.Test.startTest(); + Map nameById = domain.getIdFieldByStringField(Schema.Account.Id, Schema.Account.Name); + System.Test.stopTest(); + System.Assert.isTrue(nameById.containsKey(accountName)); + System.Assert.areEqual(accountId, nameById.get(accountName)); + } + + @IsTest + static void itShouldReturnStringFieldByIdField() + { + final String accountName = 'My Account'; + final Id accountId = fflib_IDGenerator.generate(Account.SObjectType); + DomainAccounts domain = new DomainAccounts( + new List + { + new Account(Id = accountId, Name = accountName), + new Account(Name = accountName + ' 2') // This one should be ignored + }); + + System.Test.startTest(); + Map result = domain.getStringFieldByIdField(Account.Name, Account.Id); + System.Test.stopTest(); + + System.Assert.areEqual(1, result.size(), 'Incorrect returned amount of results'); + System.Assert.isTrue(result.keySet().contains(accountId), 'The accountId is missing from the results'); + System.Assert.areEqual(accountName, result.get(accountId), 'Incorrect returned account name'); + } + + @IsTest + static void itShouldReturnDateFieldByIdField() + { + final Date today = Date.today(); + final Datetime todayDatetime = Datetime.newInstance(today.year(), today.month(), today.day()); + final String accountName = 'My Account'; + final Id accountId = fflib_IDGenerator.generate(Account.SObjectType); + DomainAccounts domain = new DomainAccounts( + new List + { + (Account) fflib_MockSObjectUtil.addFieldValue(new Account(Id = accountId), Account.CreatedDate, todayDatetime), + new Account(Name = accountName + ' 2') // This one should be ignored + }); + + System.Test.startTest(); + Map result = domain.getDateFieldByIdField(Account.CreatedDate, Account.Id); + System.Test.stopTest(); + + System.Assert.areEqual(1, result.size(), 'Incorrect returned amount of results'); + System.Assert.istrue(result.keySet().contains(accountId), 'The accountId is missing from the results'); + System.Assert.areEqual(today, result.get(accountId), 'Incorrect returned date'); + } + + @IsTest + static void itShouldReturnIntegerFieldValues() + { + final Integer numberOfEmployees = 10; + final String accountName = 'Test Account'; + DomainAccounts domain = new DomainAccounts( + new List + { + new Account(NumberOfEmployees = numberOfEmployees), + new Account(Name = accountName, NumberOfEmployees = numberOfEmployees * 2), + new Account() // This one should be ignored + }); + + System.Test.startTest(); + Set result = domain.getIntegerFieldValues(Account.NumberOfEmployees).getIntegerSet(); + Set result2 = + domain.getIntegerFieldValues( + Account.NumberOfEmployees, + new fflib_Criteria().equalTo(Schema.Account.Name, accountName) + ) + .getIntegerSet(); + System.Test.stopTest(); + + System.Assert.areEqual(2, result.size(), 'Incorrect amount of results'); + System.Assert.istrue(result.contains(numberOfEmployees), 'The expected numberOfEmployees was not returned'); + System.Assert.istrue(result.contains(numberOfEmployees * 2), 'The expected numberOfEmployees was not returned'); + + System.Assert.areEqual(1, result2.size(), 'Incorrect amount of results'); + System.Assert.istrue(result2.contains(numberOfEmployees * 2), 'The expected numberOfEmployees was not returned'); + } + + @IsTest + static void itShouldReturnLongFieldValues() + { + final Integer numberOfEmployees = 10; + final String accountName = 'Test Account'; + DomainAccounts domain = new DomainAccounts( + new List + { + new Account(NumberOfEmployees = numberOfEmployees), + new Account(Name = accountName, NumberOfEmployees = numberOfEmployees * 2), + new Account() // This one should be ignored + }); + + System.Test.startTest(); + Set result = domain.getLongFieldValues(Account.NumberOfEmployees).getLongSet(); + Set result2 = + domain.getLongFieldValues( + Account.NumberOfEmployees, + new fflib_Criteria().equalTo(Schema.Account.Name, accountName) + ) + .getLongSet(); + System.Test.stopTest(); + + System.Assert.areEqual(2, result.size(), 'Incorrect amount of results'); + System.Assert.istrue(result.contains(numberOfEmployees), 'The expected numberOfEmployees was not returned'); + System.Assert.istrue(result.contains(numberOfEmployees * 2), 'The expected numberOfEmployees was not returned'); + + System.Assert.areEqual(1, result2.size(), 'Incorrect amount of results'); + System.Assert.istrue(result2.contains(numberOfEmployees * 2), 'The expected numberOfEmployees was not returned'); + } + + @IsTest + static void itShouldReturnRecordIdById() + { + final Id contactId = fflib_IDGenerator.generate(Schema.Contact.SObjectType); + final Id accountId = fflib_IDGenerator.generate(Schema.Account.SObjectType); + final Contact record = new Contact(Id = contactId, AccountId = accountId); + fflib_SObjects2 domain = new fflib_SObjects2(new List{ record }); + System.Test.startTest(); + Map accountIdByContactId = domain.getIdFieldByIdField(Schema.Contact.AccountId, Schema.Contact.Id); + System.Test.stopTest(); + System.Assert.istrue(accountIdByContactId.containsKey(contactId)); + System.Assert.areEqual(accountId, accountIdByContactId.get(contactId)); + } + + @IsTest + static void itShouldReturnRecordByIds() + { + SObjectType accountSObjectType = Schema.Account.SObjectType; + final Id idA = fflib_IDGenerator.generate(accountSObjectType); + final Id idB = fflib_IDGenerator.generate(accountSObjectType); + final Id idC = fflib_IDGenerator.generate(accountSObjectType); + + DomainAccounts domain = new DomainAccounts( + new List + { + new Account(Id = idA), + new Account(Id = idB), + new Account(Id = idC) + } + ); + + Set recordIds = new Set {idA, idB, idC}; + System.Assert.istrue( + domain.getSObjectById().keySet().containsAll(recordIds), + 'The domain should return all the record Ids' + ); + } + + + @IsTest + static void itShouldReturnRecordsIds() + { + SObjectType accountSObjectType = Schema.Account.SObjectType; + Id idA = fflib_IDGenerator.generate(accountSObjectType); + Id idB = fflib_IDGenerator.generate(accountSObjectType); + Id idC = fflib_IDGenerator.generate(accountSObjectType); + + DomainAccounts domain = new DomainAccounts( + new List + { + new Account(Id = idA), + new Account(Id = idB), + new Account(Id = idC) + } + ); + + Set recordIds = new Set {idA, idB, idC}; + System.Assert.istrue( + domain.getRecordIds().containsAll(recordIds), + 'The domain should return all the record Ids' + ); + } + + @IsTest + static void itShouldReturnRecords() + { + DomainAccounts domain = generateDomain(); + + System.Assert.areEqual(6, domain.getRecords().size()); + } + + @IsTest + static void itShouldReturnRecordByCriteria() + { + final Id idA = fflib_IDGenerator.generate(Schema.Account.SObjectType); + DomainAccounts domain = new DomainAccounts( + new List + { + new Account(Name = 'A', Id = idA), + new Account(Name = 'B', Id = fflib_IDGenerator.generate(Schema.Account.SObjectType)) + }); + + System.Assert.areEqual( + 'A', + domain.getRecords( + new fflib_Criteria() + .equalTo(Schema.Account.Id, idA) + ) + .get(0) + .get('Name') + ); + } + + @IsTest + static void itShouldReturnRecordById() + { + final Id idA = fflib_IDGenerator.generate(Schema.Account.SObjectType); + DomainAccounts domain = new DomainAccounts( + new List + { + new Account(Name = 'A', Id = idA), + new Account(Name = 'B', Id = fflib_IDGenerator.generate(Schema.Account.SObjectType)) + }); + + System.Assert.areEqual('A', domain.getRecord(idA).get('Name')); + } + + @IsTest + static void itShouldReturnRecordsById() + { + final Id idA = fflib_IDGenerator.generate(Schema.Account.SObjectType); + final fflib_Ids ids = new fflib_Ids(new Set {idA}); + DomainAccounts domain = new DomainAccounts( + new List + { + new Account(Name = 'A', Id = idA), + new Account(Name = 'B', Id = fflib_IDGenerator.generate(Schema.Account.SObjectType)) + }); + + System.Assert.areEqual('A', domain.getRecords(ids).get(0).get('Name')); + } + + @IsTest + static void itShouldReturnRecordsByIds() + { + final Id idA = fflib_IDGenerator.generate(Schema.Account.SObjectType); + DomainAccounts domain = new DomainAccounts( + new List + { + new Account(Name = 'A', Id = idA), + new Account(Name = 'B', Id = fflib_IDGenerator.generate(Schema.Account.SObjectType)) + }); + + System.Assert.areEqual('A', domain.getRecords(new Set {idA}).get(0).get('Name')); + } + + @IsTest + static void itShouldReturnRecordsWithFieldValues() + { + DomainAccounts domain = generateDomain(); + + System.Assert.areEqual(1, domain.selectByShippingCountry('USA').size()); + } + + @IsTest + static void itShouldReturnRecordsWithoutFieldValues() + { + DomainAccounts domain = generateDomain(); + + System.Assert.areEqual(3, domain.selectWithoutShippingCountry().size()); + } + + @IsTest + static void itShouldReturnRecordsWithoutAllFieldValues() + { + DomainAccounts domain = generateDomain(); + + System.Assert.areEqual(1, domain.selectWithEmptyRecord().size()); + } + + @IsTest + static void itShouldReturnRecordsWithShippingCountry() + { + DomainAccounts domain = generateDomain(); + + System.Assert.areEqual(3, domain.selectWithShippingCountry().size()); + } + + @IsTest + static void itShouldReturnRecordsWithAllFieldValues() + { + DomainAccounts domain = generateDomain(); + + System.Assert.areEqual(3, domain.selectPopulatedRecords().size()); + } + + @IsTest + static void itShouldReturnFieldValues() + { + DomainAccounts domain = generateDomain(); + + System.Assert.istrue( + domain.getStringFieldValues(Schema.Account.ShippingCountry) + .containsAll( + new Set + { + 'USA', + 'Ireland', + 'UK', + '' + } + ) + ); + } + + @IsTest + static void itShouldSetFieldValue() + { + DomainAccounts domain = generateDomain(); + String country = 'Holland'; + domain.setShippingCountry(country); + + System.Assert.areEqual(6, domain.selectByShippingCountry(country).size()); + } + + @IsTest + static void itShouldSetFieldValueByCondition() + { + DomainAccounts domain = generateDomain(); + domain.setRatingByShippingCountry( + new Map + { + 'USA' => 'Hot' + } + ); + + System.Assert.areEqual(1, domain.selectByRating('Hot').size()); + } + + @IsTest + static void itShouldGetTheSumOfAnnualRevenue() + { + DomainAccounts domain = generateDomain(); + System.Assert.areEqual(11, domain.getDecimalFieldSum(Account.AnnualRevenue)); + System.Assert.isTrue(domain.getDecimalFieldValues(Account.AnnualRevenue).contains((Decimal) 5)); + } + + @IsTest + static void itShouldSetFieldByIdField() + { + Id accountId = fflib_IDGenerator.generate(Account.SObjectType); + Account record = new Account(Id = accountId, Name = ''); + fflib_SObjects2 domain = new fflib_SObjects2(new List{ record }); + + domain.setFieldValue( + Schema.Account.Id, + Schema.Account.Name, + new Map + { + accountId => 'Hello' + } + ); + + System.Assert.areEqual('Hello', domain.getFirstSObject().get('Name')); + } + + @IsTest + static void itShouldSetFieldByStringField() + { + Account record = new Account(Name = 'Hello', Rating = 'Cold'); + fflib_SObjects2 domain = new fflib_SObjects2(new List{ record }); + + domain.setFieldValue( + Schema.Account.Name, + Schema.Account.Rating, + new Map + { + 'Hello' => 'Warm' + } + ); + + System.Assert.areEqual('Warm', domain.getFirstSObject().get('Rating')); + } + + @IsTest + static void itShouldSetField() + { + Account record = new Account(Name = 'Hello', Rating = 'Cold'); + fflib_SObjects2 domain = new fflib_SObjects2(new List{ record }); + + domain.setFieldValue(Account.Name, 'Hello World', new fflib_Criteria().equalTo(Account.Rating, 'Cold')); + + System.Assert.areEqual('Hello World', domain.getFirstSObject().get('Name')); + } + + private static DomainAccounts generateDomain() + { + DomainAccounts domain = new DomainAccounts( + new List + { + new Account(Name = 'A', ShippingCountry = 'USA', AnnualRevenue = 5), + new Account(Name = 'B', ShippingCountry = 'Ireland', AnnualRevenue = 3), + new Account(Name = 'C', ShippingCountry = 'UK', AnnualRevenue = 2), + new Account(Name = 'D', ShippingCountry = '', AnnualRevenue = 1), + new Account(Name = 'E'), + new Account() + } + ); + return domain; + } + + + private class DomainAccounts extends fflib_SObjects2 + { + public DomainAccounts(List records) + { + super(records, Schema.Account.SObjectType); + } + + public List selectByShippingCountry(String country) + { + return (List) getRecordsByFieldValues( + Schema.Account.ShippingCountry, + new Set {country} + ); + } + + public List selectByRating(String rating) + { + return (List) getRecordsByFieldValue( + Schema.Account.Rating, + rating + ); + } + + public List selectWithoutShippingCountry() + { + return (List) getRecordsWithBlankFieldValues( + Schema.Account.ShippingCountry + ); + } + + public List selectWithShippingCountry() + { + return (List) getRecordsWithNotBlankFieldValues( + Schema.Account.ShippingCountry + ); + } + + public List selectWithEmptyRecord() + { + return (List) getRecordsWithAllBlankFieldValues( + new Set + { + Schema.Account.Name, + Schema.Account.ShippingCountry + } + ); + } + + public List selectPopulatedRecords() + { + return (List) getRecordsWithAllNotBlankFieldValues( + new Set + { + Schema.Account.Name, + Schema.Account.ShippingCountry + } + ); + } + + public void setShippingCountry(String country) + { + setFieldValue(Schema.Account.ShippingCountry, country); + } + + public void setRatingByShippingCountry(Map ratingByCountry) + { + setFieldValueByMap( + Schema.Account.ShippingCountry, + Schema.Account.Rating, + ratingByCountry); + } + + public void addNameError(String message) + { + addError(Schema.Account.Name, message); + } + + public void clearShippingCountry() + { + clearField(Schema.Account.ShippingCountry); + } + + protected override Map getRelatedFieldByDomainType() + { + return new Map + { + Schema.Contact.SObjectType => Contact.AccountId + }; + } + } + + private class DomainContacts extends fflib_SObjects2 + { + public DomainContacts(List records) + { + super(records, Schema.Contact.SObjectType); + } + + protected override Map getRelatedFieldByDomainType() + { + return new Map + { + Schema.Account.SObjectType => Contact.AccountId, + Schema.Case.SObjectType => Case.ContactId + }; + } + } + + private class DomainCases extends fflib_SObjects2 + { + public DomainCases(List records) + { + super(records, Schema.Case.SObjectType); + } + + protected override Map getRelatedFieldByDomainType() + { + return new Map + { + Schema.Contact.SObjectType => Case.ContactId + }; + } + } }