/** * File Name: fflib_SObjects2 * @description Primitive domain for the object type SObject * * @author architect ir. Wilhelmus G.J. Velzeboer * * Copyright (c), W.G.J. Velzeboer, * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above author notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the author nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * 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 { } }