From 260cfe1b01bf2aedeb5c56df3e236b2d05e87ea2 Mon Sep 17 00:00:00 2001 From: tstone Date: Thu, 1 Sep 2016 04:20:39 -0400 Subject: [PATCH 01/62] Fields that are polymorphic fail when the chosen sObjectType is not the type specified in the selector. Add the ability to set the sObjectType when validating the field exists on the object. Use the type set in the selector to determine which polymorphic type to use. Example: Lead.Owner.UserRoleID Owner is GROUP | USER Group does not contain UserRoleID and fails when the getField call sets the sObjectField token to null. --- fflib/src/classes/fflib_QueryFactory.cls | 48 +++++++++- fflib/src/classes/fflib_SObjectSelector.cls | 2 +- .../src/classes/fflib_SObjectSelectorTest.cls | 92 +++++++++++++++++++ 3 files changed, 137 insertions(+), 5 deletions(-) diff --git a/fflib/src/classes/fflib_QueryFactory.cls b/fflib/src/classes/fflib_QueryFactory.cls index adcccfc9b28..3a0fe62ab88 100644 --- a/fflib/src/classes/fflib_QueryFactory.cls +++ b/fflib/src/classes/fflib_QueryFactory.cls @@ -84,7 +84,7 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr private Schema.ChildRelationship relationship; private Map subselectQueryMap; - private QueryField getFieldToken(String fieldName){ + private QueryField getFieldToken(String fieldName, Schema.sObjectType relatedSObjectType){ QueryField result; if(!fieldName.contains('.')){ //single field Schema.SObjectField token = fflib_SObjectDescribe.getDescribe(table).getField(fieldName.toLowerCase()); @@ -103,7 +103,25 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr if (token != null && enforceFLS) fflib_SecurityUtils.checkFieldIsReadable(lastSObjectType, token); if(token != null && i.hasNext() && token.getDescribe().getSOAPType() == Schema.SOAPType.ID){ - lastSObjectType = token.getDescribe().getReferenceTo()[0]; //if it's polymorphic doesn't matter which one we get + if(relatedSObjectType == null) { + lastSObjectType = token.getDescribe().getReferenceTo()[0]; //if it's polymorphic get the first one - user did not specify the one to use. + }else{ + lastSObjectType = null; + List relatedObjs = token.getDescribe().getReferenceTo(); //if it's polymorphic, it matters which one we use - i.e. Lead.Owner is GROUP|USER and each has different fields. + if(relatedObjs.size() > 1) { + String relatedSObjectName = fflib_SObjectDescribe.getDescribe(relatedSObjectType).getDescribe().getName(); + for(Schema.sObjectType sot : relatedObjs) { + if(fflib_SObjectDescribe.getDescribe(sot).getDescribe().getName() == relatedSObjectName){ + lastSObjectType = sot; + break; + } + } + if(lastSObjectType == null) + throw new InvalidRelationshipException(fieldName, relatedSObjectType); + }else{ + lastSObjectType = relatedOjs[0]; //only one type returned, use it. + } + } fieldPath.add(token); }else if(token != null && !i.hasNext()){ fieldPath.add(token); @@ -118,6 +136,9 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr } return result; } + private QueryField getFieldToken(String fieldName) { + return this.getFieldToken(fieldName, null); + } /** * fflib_QueryFactory instances will be considered equal if they produce the same SOQL query. @@ -192,9 +213,19 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr * @param fieldName the API name of the field to add to the query's SELECT clause. **/ public fflib_QueryFactory selectField(String fieldName){ - fields.add( getFieldToken(fieldName) ); + fields.add( getFieldToken(fieldName, null) ); return this; } + /** + * Selects a single field from the SObject specified in {@link #table}. + * Selecting fields is idempotent, if this field is already selected calling this method will have no additional impact. + * @param fieldName the API name of the field to add to the query's SELECT clause. + * @param relatedSObjectType the related sObjectType to resolve polymorphic object fields. + **/ + public fflib_QueryFactory selectField(String fieldName, Schema.sOBjectType relatedObjectType){ + fields.add( getFieldToken(fieldName, relatedObjectType) ); + return this; + } /** * Selects a field, avoiding the possible ambiguitiy of String API names. * @see #selectField(String) @@ -772,7 +803,16 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr this.setMessage( 'Invalid field \''+fieldName+'\' for object \''+objectType+'\'' ); } } + public class InvalidRelationshipException extends Exception{ + private String fieldName; + private Schema.SObjectType objectType; + public InvalidRelationshipException(String fieldname, Schema.SObjectType objectType) { + this.fieldname = fieldname; + this.objectType = objectType; + this.setMessage( 'Not able to find related sObjectType for object \''+objectType+'\' denoted by field \''+field+'\'' ); + } + } public class InvalidFieldSetException extends Exception{} public class NonReferenceFieldException extends Exception{} - public class InvalidSubqueryRelationshipException extends Exception{} + public class InvalidSubqueryRelationshipException extends Exception{} } diff --git a/fflib/src/classes/fflib_SObjectSelector.cls b/fflib/src/classes/fflib_SObjectSelector.cls index 25656f34b71..403956db41a 100644 --- a/fflib/src/classes/fflib_SObjectSelector.cls +++ b/fflib/src/classes/fflib_SObjectSelector.cls @@ -330,7 +330,7 @@ public abstract with sharing class fflib_SObjectSelector { // Add fields from selector prefixing the relationship path for(SObjectField field : getSObjectFieldList()) - queryFactory.selectField(relationshipFieldPath + '.' + field.getDescribe().getName()); + queryFactory.selectField(relationshipFieldPath + '.' + field.getDescribe().getName(), this.getSObjectType()); // Automatically select the CurrencyIsoCode for MC orgs (unless the object is a known exception to the rule) if(Userinfo.isMultiCurrencyOrganization() && CURRENCY_ISO_CODE_ENABLED) queryFactory.selectField(relationshipFieldPath+'.CurrencyIsoCode'); diff --git a/fflib/src/classes/fflib_SObjectSelectorTest.cls b/fflib/src/classes/fflib_SObjectSelectorTest.cls index 92268c8101d..d5c35a46f1e 100644 --- a/fflib/src/classes/fflib_SObjectSelectorTest.cls +++ b/fflib/src/classes/fflib_SObjectSelectorTest.cls @@ -291,5 +291,97 @@ private with sharing class fflib_SObjectSelectorTest return null; } return testUser; + } + + @isTest + static void testPolyMorphicSelectWithRelatedType() + { + //Given + + Testfflib_CampaignMemberSelector cmSelector = new Testfflib_CampaignMemberSelector(); + fflib_QueryFactory qf = cmSelector.newQueryFactory(); + new Testfflib_LeadSelector().configureQueryFactoryFields(qf, 'Lead'); + new Testfflib_UserSelector().configureQueryFactoryFields(qf, 'Lead.Owner'); + + + Set expectedSelectFields = new Set{ 'Id', 'Status', 'Lead.Id', 'Lead.OwnerId', 'Lead.Owner.Id', 'Lead.Owner.UserRoleId' }; + if (UserInfo.isMultiCurrencyOrganization()) + { + expectedSelectFields.add('CurrencyIsoCode'); + } + + //When + String soql = qf.toSOQL(); + + //Then + Pattern soqlPattern = Pattern.compile('SELECT (.*) FROM CampaignMember ORDER BY CreatedDate ASC NULLS FIRST '); + Matcher soqlMatcher = soqlPattern.matcher(soql); + soqlMatcher.matches(); + + List actualSelectFields = soqlMatcher.group(1).deleteWhiteSpace().split(','); + System.assertEquals(expectedSelectFields, new Set(actualSelectFields)); + } + + private class Testfflib_CampaignMemberSelector extends fflib_SObjectSelector + { + public Testfflib_CampaignMemberSelector() + { + super(); + } + + public List getSObjectFieldList() + { + return new List { + CampaignMember.Id, + CampaignMember.Status + }; + } + + public Schema.SObjectType getSObjectType() + { + return CampaignMember.sObjectType; + } + } + + private class Testfflib_UserSelector extends fflib_SObjectSelector + { + public Testfflib_UserSelector() + { + super(); + } + + public List getSObjectFieldList() + { + return new List { + User.UserRoleId, + User.Id + }; + } + + public Schema.SObjectType getSObjectType() + { + return User.sObjectType; + } + } + + private class Testfflib_LeadSelector extends fflib_SObjectSelector + { + public Testfflib_LeadSelector() + { + super(); + } + + public List getSObjectFieldList() + { + return new List { + Lead.OwnerId, + Lead.Id + }; + } + + public Schema.SObjectType getSObjectType() + { + return Lead.sObjectType; + } } } \ No newline at end of file From 83508ffa811032764fc1c4f64bd073a840660fb7 Mon Sep 17 00:00:00 2001 From: SquattingDog Date: Tue, 5 Feb 2019 17:33:53 -0500 Subject: [PATCH 02/62] formatting changes --- fflib/src/classes/fflib_QueryFactory.cls | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/fflib/src/classes/fflib_QueryFactory.cls b/fflib/src/classes/fflib_QueryFactory.cls index ecf5a79fbf7..883b63af687 100644 --- a/fflib/src/classes/fflib_QueryFactory.cls +++ b/fflib/src/classes/fflib_QueryFactory.cls @@ -788,15 +788,19 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr this.fieldName = fieldName; this.setMessage( 'Invalid field \''+fieldName+'\' for object \''+objectType+'\'' ); } - }public class InvalidRelationshipException extends Exception{ - private String fieldName; - private Schema.SObjectType objectType; - public InvalidRelationshipException(String fieldname, Schema.SObjectType objectType) { + } + + public class InvalidRelationshipException extends Exception + { + private String fieldName; + private Schema.SObjectType objectType; + public InvalidRelationshipException(String fieldname, Schema.SObjectType objectType) { this.fieldname = fieldname; - this.objectType = objectType; - this.setMessage( 'Not able to find related sObjectType for object \''+objectType+'\' denoted by field \''+fieldname+'\'' ); + this.objectType = objectType; + this.setMessage( 'Not able to find related sObjectType for object \''+objectType+'\' denoted by field \''+fieldname+'\'' ); + } } - } + public class InvalidFieldSetException extends Exception{} public class NonReferenceFieldException extends Exception{} public class InvalidSubqueryRelationshipException extends Exception{} From 823b7722d05bd92137bb2111985b418c075bbd08 Mon Sep 17 00:00:00 2001 From: SquattingDog Date: Tue, 5 Feb 2019 17:43:45 -0500 Subject: [PATCH 03/62] additional formatting changes --- fflib/src/classes/fflib_QueryFactory.cls | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/fflib/src/classes/fflib_QueryFactory.cls b/fflib/src/classes/fflib_QueryFactory.cls index 883b63af687..2e76cc8c21d 100644 --- a/fflib/src/classes/fflib_QueryFactory.cls +++ b/fflib/src/classes/fflib_QueryFactory.cls @@ -224,17 +224,18 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr public fflib_QueryFactory selectField(String fieldName){ fields.add( getFieldPath(fieldName, null) ); return this; - } - /** - * Selects a single field from the SObject specified in {@link #table}. - * Selecting fields is idempotent, if this field is already selected calling this method will have no additional impact. - * @param fieldName the API name of the field to add to the query's SELECT clause. + } + + /** + * Selects a single field from the SObject specified in {@link #table}. + * Selecting fields is idempotent, if this field is already selected calling this method will have no additional impact. + * @param fieldName the API name of the field to add to the query's SELECT clause. * @param relatedSObjectType the related sObjectType to resolve polymorphic object fields. - **/ - public fflib_QueryFactory selectField(String fieldName, Schema.sOBjectType relatedObjectType){ - fields.add( getFieldPath(fieldName, relatedObjectType) ); - return this; - } + **/ + public fflib_QueryFactory selectField(String fieldName, Schema.sOBjectType relatedObjectType){ + fields.add( getFieldPath(fieldName, relatedObjectType) ); + return this; + } /** * Selects a field, avoiding the possible ambiguitiy of String API names. From a9fb46340f741c6cf8ec7a99431f6a9c0bff9fe4 Mon Sep 17 00:00:00 2001 From: Wim Velzeboer Date: Wed, 21 Apr 2021 14:09:13 +0100 Subject: [PATCH 04/62] Add methods and unit test coverage to fflib_SObjects domain --- .../main/classes/fflib_SObjects.cls | 98 ++++++++++++++++++- .../test/classes/fflib_SObjectsTest.cls | 96 ++++++++++++++++++ 2 files changed, 192 insertions(+), 2 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjects.cls b/sfdx-source/apex-common/main/classes/fflib_SObjects.cls index b21f69e4b82..45e99c974dc 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjects.cls +++ b/sfdx-source/apex-common/main/classes/fflib_SObjects.cls @@ -74,6 +74,57 @@ public virtual class fflib_SObjects return SObjectDescribe.getSObjectType(); } + /** + * Adds an error message to the records in the domain + * + * @param message The error message to add to each record + */ + protected void addError(String message) + { + for (SObject record : getRecords()) + { + record.addError(error(message, record)); + } + } + + /** + * Adds an error message to the a field records in the domain + * + * @param sObjectField The field where the error should be reported + * @param message The error message to add to the given field on each record + */ + protected void addError(Schema.SObjectField sObjectField, String message) + { + for (SObject record : getRecords()) + { + record.addError(sObjectField, error(message, record, sObjectField)); + } + } + + /** + * Clear the field value on all the records of the domain + * @param sObjectField The field to nullify + */ + protected void clearField(Schema.SObjectField sObjectField) + { + clearFields(new Set{ sObjectField }); + } + + /** + * Clear the field values on all the records of the domain + * @param sObjectFields The fields to nullify + */ + protected void clearFields(Set sObjectFields) + { + for (SObject record : getRecords()) + { + for (SObjectField sObjectField : sObjectFields) + { + record.put(sObjectField, null); + } + } + } + /** * Ensures logging of errors in the Domain context for later assertions in tests * @@ -96,11 +147,49 @@ public virtual class fflib_SObjects * * @return Returns the Error message **/ - protected virtual String error(String message, SObject record, SObjectField field) + protected virtual String error(String message, SObject record, Schema.SObjectField field) { return fflib_SObjects.Errors.error(this, message, record, field); } + /** + * @param sObjectField The SObjectField reference of the type Id + * + * @return Return a set with all the Id values of the given field + */ + @TestVisible + protected Set getIdFieldValues(Schema.SObjectField sObjectField) + { + Set result = new Set(); + for (SObject record : getRecords()) + { + result.add((Id) record.get(sObjectField)); + } + return result; + } + + /** + * @param sObjectField The SObjectField reference of the type String + * + * @return Return a set with all the String values of the given field + */ + @TestVisible + protected Set getStringFieldValues(Schema.SObjectField sObjectField) + { + Set result = new Set(); + for (SObject record : getRecords()) + { + result.add((String) record.get(sObjectField)); + } + return result; + } + + /** + * @param sObjectField The SObjectField reference + * + * @return Return a set with all the values of the given field + */ + @TestVisible protected virtual Set getFieldValues(Schema.SObjectField sObjectField) { Set result = new Set(); @@ -257,7 +346,12 @@ public virtual class fflib_SObjects return result; } - + /** + * Modifies a value of a field for all records in the domain + * + * @param sObjectField The reference to the SObjectField to be modified + * @param value The value to store in the given SObjectField + */ protected virtual void setFieldValue(Schema.SObjectField sObjectField, Object value) { for (SObject record : getRecords()) diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls b/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls index 8877ab78370..b5671e976be 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls @@ -28,6 +28,18 @@ private class fflib_SObjectsTest { + @IsTest + static void itShouldClearTheField() + { + Account record = new Account(ShippingCountry = 'Holland'); + DomainAccounts domain = new DomainAccounts(new List{ record }); + System.assert(!domain.selectByShippingCountry('Holland').isEmpty(), 'Incorrect test data'); + + domain.clearShippingCountry(); + + System.assert(domain.selectByShippingCountry('Holland').isEmpty(), 'Field should have been nullified'); + } + @IsTest static void itShouldReturnTheDomainsType() { @@ -45,6 +57,36 @@ private class fflib_SObjectsTest ); } + + @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( + domain.getRecordIds().containsAll(recordIds), + 'The domain should return all the record Ids' + ); + + System.assert( + domain.getIdFieldValues(Schema.Account.Id).containsAll(recordIds), + 'The domain should return all the record Ids' + ); + } + @IsTest static void itShouldReturnRecordsWithFieldValues() { @@ -85,6 +127,36 @@ private class fflib_SObjectsTest System.assert(domain.selectPopulatedRecords().size() == 3); } + @IsTest + static void itShouldReturnFieldValues() + { + DomainAccounts domain = generateDomain(); + + System.assert( + domain.getStringFieldValues(Schema.Account.ShippingCountry) + .containsAll( + new Set{ + 'USA', + 'Ireland', + 'UK', + '' + } + ) + ); + + System.assert( + domain.getFieldValues(Schema.Account.ShippingCountry) + .containsAll( + new Set{ + 'USA', + 'Ireland', + 'UK', + '' + } + ) + ); + } + @IsTest static void itShouldSetFieldValue() { @@ -110,6 +182,20 @@ private class fflib_SObjectsTest System.assert(domain.selectByRating('Hot').size() == 1); } + @IsTest + static void testDomainErrorLogging() + { + // Test static helpers for raise none domain object instance errors + final String errorMessage = 'Test Error'; + Account record = new Account(); + DomainAccounts domain = new DomainAccounts(new List{ record }); + domain.addNameError(errorMessage); + + System.assertEquals(1, fflib_SObjects.Errors.getAll().size()); + System.assertEquals(errorMessage, fflib_SObjects.Errors.getAll()[0].message); + System.assertEquals(Account.Name, ((fflib_SObjects.FieldError) fflib_SObjects.Errors.getAll()[0]).field); + } + @IsTest static void testErrorLogging() { @@ -213,5 +299,15 @@ private class fflib_SObjectsTest Schema.Account.Rating, ratingByCountry); } + + public void addNameError(String message) + { + addError(Schema.Account.Name, message); + } + + public void clearShippingCountry() + { + clearField(Schema.Account.ShippingCountry); + } } } \ No newline at end of file From d85c4a10bdcbf2da2672fca3845ec4c9cea17277 Mon Sep 17 00:00:00 2001 From: Wim Velzeboer Date: Wed, 19 May 2021 11:49:41 +0100 Subject: [PATCH 05/62] Add interface definitions for Application Factories to make it easier to replace the implementations --- .../main/classes/fflib_Application.cls | 8 ++--- .../main/classes/fflib_IDomainFactory.cls | 32 +++++++++++++++++++ .../classes/fflib_IDomainFactory.cls-meta.xml | 5 +++ .../main/classes/fflib_ISelectorFactory.cls | 31 ++++++++++++++++++ .../fflib_ISelectorFactory.cls-meta.xml | 5 +++ .../main/classes/fflib_IServiceFactory.cls | 29 +++++++++++++++++ .../fflib_IServiceFactory.cls-meta.xml | 5 +++ .../main/classes/fflib_IUnitOfWorkFactory.cls | 32 +++++++++++++++++++ .../fflib_IUnitOfWorkFactory.cls-meta.xml | 5 +++ 9 files changed, 148 insertions(+), 4 deletions(-) create mode 100644 sfdx-source/apex-common/main/classes/fflib_IDomainFactory.cls create mode 100644 sfdx-source/apex-common/main/classes/fflib_IDomainFactory.cls-meta.xml create mode 100644 sfdx-source/apex-common/main/classes/fflib_ISelectorFactory.cls create mode 100644 sfdx-source/apex-common/main/classes/fflib_ISelectorFactory.cls-meta.xml create mode 100644 sfdx-source/apex-common/main/classes/fflib_IServiceFactory.cls create mode 100644 sfdx-source/apex-common/main/classes/fflib_IServiceFactory.cls-meta.xml create mode 100644 sfdx-source/apex-common/main/classes/fflib_IUnitOfWorkFactory.cls create mode 100644 sfdx-source/apex-common/main/classes/fflib_IUnitOfWorkFactory.cls-meta.xml diff --git a/sfdx-source/apex-common/main/classes/fflib_Application.cls b/sfdx-source/apex-common/main/classes/fflib_Application.cls index 81acb1514e2..d467c5ff72f 100644 --- a/sfdx-source/apex-common/main/classes/fflib_Application.cls +++ b/sfdx-source/apex-common/main/classes/fflib_Application.cls @@ -34,7 +34,7 @@ public virtual class fflib_Application /** * Class implements a Unit of Work factory **/ - public virtual class UnitOfWorkFactory + public virtual class UnitOfWorkFactory implements fflib_IUnitOfWorkFactory { private List m_objectTypes; private fflib_ISObjectUnitOfWork m_mockUow; @@ -122,7 +122,7 @@ public virtual class fflib_Application /** * Simple Service Factory implementation **/ - public virtual class ServiceFactory + public virtual class ServiceFactory implements fflib_IServiceFactory { protected Map m_serviceInterfaceTypeByServiceImplType; @@ -178,7 +178,7 @@ public virtual class fflib_Application /** * Class implements a Selector class factory **/ - public virtual class SelectorFactory + public virtual class SelectorFactory implements fflib_ISelectorFactory { protected Map m_sObjectBySelectorType; protected Map m_sObjectByMockSelector; @@ -280,7 +280,7 @@ public virtual class fflib_Application /** * Class implements a Domain class factory **/ - public virtual class DomainFactory + public virtual class DomainFactory implements fflib_IDomainFactory { protected fflib_Application.SelectorFactory m_selectorFactory; diff --git a/sfdx-source/apex-common/main/classes/fflib_IDomainFactory.cls b/sfdx-source/apex-common/main/classes/fflib_IDomainFactory.cls new file mode 100644 index 00000000000..1e0f982d5ae --- /dev/null +++ b/sfdx-source/apex-common/main/classes/fflib_IDomainFactory.cls @@ -0,0 +1,32 @@ +/** + * Copyright (c), FinancialForce.com, inc + * 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 copyright 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 FinancialForce.com, inc 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 interface fflib_IDomainFactory +{ + fflib_IDomain newInstance(Set recordIds); + fflib_IDomain newInstance(List records); + fflib_IDomain newInstance(List objects, Object objectType); + fflib_IDomain newInstance(List records, SObjectType domainSObjectType); +} \ No newline at end of file diff --git a/sfdx-source/apex-common/main/classes/fflib_IDomainFactory.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IDomainFactory.cls-meta.xml new file mode 100644 index 00000000000..d75b0582fba --- /dev/null +++ b/sfdx-source/apex-common/main/classes/fflib_IDomainFactory.cls-meta.xml @@ -0,0 +1,5 @@ + + + 51.0 + Active + diff --git a/sfdx-source/apex-common/main/classes/fflib_ISelectorFactory.cls b/sfdx-source/apex-common/main/classes/fflib_ISelectorFactory.cls new file mode 100644 index 00000000000..a39095b289b --- /dev/null +++ b/sfdx-source/apex-common/main/classes/fflib_ISelectorFactory.cls @@ -0,0 +1,31 @@ +/** + * Copyright (c), FinancialForce.com, inc + * 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 copyright 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 FinancialForce.com, inc 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 interface fflib_ISelectorFactory +{ + fflib_ISObjectSelector newInstance(SObjectType sObjectType); + List selectById(Set recordIds); + List selectByRelationship(List relatedRecords, SObjectField relationshipField); +} \ No newline at end of file diff --git a/sfdx-source/apex-common/main/classes/fflib_ISelectorFactory.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISelectorFactory.cls-meta.xml new file mode 100644 index 00000000000..d75b0582fba --- /dev/null +++ b/sfdx-source/apex-common/main/classes/fflib_ISelectorFactory.cls-meta.xml @@ -0,0 +1,5 @@ + + + 51.0 + Active + diff --git a/sfdx-source/apex-common/main/classes/fflib_IServiceFactory.cls b/sfdx-source/apex-common/main/classes/fflib_IServiceFactory.cls new file mode 100644 index 00000000000..93fa4124cc7 --- /dev/null +++ b/sfdx-source/apex-common/main/classes/fflib_IServiceFactory.cls @@ -0,0 +1,29 @@ +/** + * Copyright (c), FinancialForce.com, inc + * 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 copyright 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 FinancialForce.com, inc 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 interface fflib_IServiceFactory +{ + Object newInstance(Type serviceInterfaceType); +} \ No newline at end of file diff --git a/sfdx-source/apex-common/main/classes/fflib_IServiceFactory.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IServiceFactory.cls-meta.xml new file mode 100644 index 00000000000..d75b0582fba --- /dev/null +++ b/sfdx-source/apex-common/main/classes/fflib_IServiceFactory.cls-meta.xml @@ -0,0 +1,5 @@ + + + 51.0 + Active + diff --git a/sfdx-source/apex-common/main/classes/fflib_IUnitOfWorkFactory.cls b/sfdx-source/apex-common/main/classes/fflib_IUnitOfWorkFactory.cls new file mode 100644 index 00000000000..371ab1ccde9 --- /dev/null +++ b/sfdx-source/apex-common/main/classes/fflib_IUnitOfWorkFactory.cls @@ -0,0 +1,32 @@ +/** + * Copyright (c), FinancialForce.com, inc + * 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 copyright 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 FinancialForce.com, inc 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 interface fflib_IUnitOfWorkFactory +{ + fflib_ISObjectUnitOfWork newInstance(); + fflib_ISObjectUnitOfWork newInstance(fflib_SObjectUnitOfWork.IDML dml); + fflib_ISObjectUnitOfWork newInstance(List objectTypes); + fflib_ISObjectUnitOfWork newInstance(List objectTypes, fflib_SObjectUnitOfWork.IDML dml); +} \ No newline at end of file diff --git a/sfdx-source/apex-common/main/classes/fflib_IUnitOfWorkFactory.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IUnitOfWorkFactory.cls-meta.xml new file mode 100644 index 00000000000..d75b0582fba --- /dev/null +++ b/sfdx-source/apex-common/main/classes/fflib_IUnitOfWorkFactory.cls-meta.xml @@ -0,0 +1,5 @@ + + + 51.0 + Active + From 1e49dd28a13909a12f08323752be81ee78057f25 Mon Sep 17 00:00:00 2001 From: Wim Velzeboer Date: Fri, 25 Jun 2021 13:01:06 +0100 Subject: [PATCH 06/62] Change private vars into projected for UnitOfWorkFactory It doesn't really make sense to have a virtual factory class an not being able to access its ObjectTypes list in the extended class. --- sfdx-source/apex-common/main/classes/fflib_Application.cls | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_Application.cls b/sfdx-source/apex-common/main/classes/fflib_Application.cls index 81acb1514e2..7b11f19179e 100644 --- a/sfdx-source/apex-common/main/classes/fflib_Application.cls +++ b/sfdx-source/apex-common/main/classes/fflib_Application.cls @@ -36,8 +36,8 @@ public virtual class fflib_Application **/ public virtual class UnitOfWorkFactory { - private List m_objectTypes; - private fflib_ISObjectUnitOfWork m_mockUow; + protected List m_objectTypes; + protected fflib_ISObjectUnitOfWork m_mockUow; /** * Constructs a Unit Of Work factory From 726464d82ae5c8b56e7c9901eb0b89590e25042c Mon Sep 17 00:00:00 2001 From: Clay Chipps Date: Mon, 3 May 2021 14:18:49 -0400 Subject: [PATCH 07/62] add extensions --- .../main/classes/fflib_Application.cls | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_Application.cls b/sfdx-source/apex-common/main/classes/fflib_Application.cls index 20ccb4c866e..aef60299c5e 100644 --- a/sfdx-source/apex-common/main/classes/fflib_Application.cls +++ b/sfdx-source/apex-common/main/classes/fflib_Application.cls @@ -39,6 +39,11 @@ public virtual class fflib_Application private List m_objectTypes; private fflib_ISObjectUnitOfWork m_mockUow; + /** + * Constructs a Unit Of Work factory + **/ + public UnitOfWorkFactory() { } + /** * Constructs a Unit Of Work factory * @@ -54,7 +59,7 @@ public virtual class fflib_Application * SObjectType list provided in the constructor, returns a Mock implementation * if set via the setMock method **/ - public fflib_ISObjectUnitOfWork newInstance() + public virtual fflib_ISObjectUnitOfWork newInstance() { // Mock? if(m_mockUow!=null) @@ -62,13 +67,12 @@ public virtual class fflib_Application return new fflib_SObjectUnitOfWork(m_objectTypes); } - /** * Returns a new fflib_SObjectUnitOfWork configured with the * SObjectType list provided in the constructor, returns a Mock implementation * if set via the setMock method **/ - public fflib_ISObjectUnitOfWork newInstance(fflib_SObjectUnitOfWork.IDML dml) + public virtual fflib_ISObjectUnitOfWork newInstance(fflib_SObjectUnitOfWork.IDML dml) { // Mock? if(m_mockUow!=null) @@ -76,7 +80,6 @@ public virtual class fflib_Application return new fflib_SObjectUnitOfWork(m_objectTypes, dml); } - /** * Returns a new fflib_SObjectUnitOfWork configured with the * SObjectType list specified, returns a Mock implementation @@ -85,7 +88,7 @@ public virtual class fflib_Application * @remark If mock is set, the list of SObjectType in the mock could be different * then the list of SObjectType specified in this method call **/ - public fflib_ISObjectUnitOfWork newInstance(List objectTypes) + public virtual fflib_ISObjectUnitOfWork newInstance(List objectTypes) { // Mock? if(m_mockUow!=null) @@ -101,7 +104,7 @@ public virtual class fflib_Application * @remark If mock is set, the list of SObjectType in the mock could be different * then the list of SObjectType specified in this method call **/ - public fflib_ISObjectUnitOfWork newInstance(List objectTypes, fflib_SObjectUnitOfWork.IDML dml) + public virtual fflib_ISObjectUnitOfWork newInstance(List objectTypes, fflib_SObjectUnitOfWork.IDML dml) { // Mock? if(m_mockUow!=null) @@ -109,9 +112,8 @@ public virtual class fflib_Application return new fflib_SObjectUnitOfWork(objectTypes, dml); } - @TestVisible - private void setMock(fflib_ISObjectUnitOfWork mockUow) + protected virtual void setMock(fflib_ISObjectUnitOfWork mockUow) { m_mockUow = mockUow; } @@ -126,6 +128,11 @@ public virtual class fflib_Application protected Map m_serviceInterfaceTypeByMockService; + /** + * Constructs a simple Service Factory + **/ + public ServiceFactory() { } + /** * Constructs a simple Service Factory, * using a Map of Apex Interfaces to Apex Classes implementing the interface @@ -162,7 +169,7 @@ public virtual class fflib_Application } @TestVisible - private virtual void setMock(Type serviceInterfaceType, Object serviceImpl) + protected virtual void setMock(Type serviceInterfaceType, Object serviceImpl) { m_serviceInterfaceTypeByMockService.put(serviceInterfaceType, serviceImpl); } @@ -176,6 +183,11 @@ public virtual class fflib_Application protected Map m_sObjectBySelectorType; protected Map m_sObjectByMockSelector; + /** + * Constructs a simple Selector Factory + **/ + public SelectorFactory() { } + /** * Consturcts a Selector Factory linking SObjectType's with Apex Classes implement the fflib_ISObjectSelector interface * Note that the factory does not check the given Apex Classes implement the interface @@ -259,7 +271,7 @@ public virtual class fflib_Application } @TestVisible - private virtual void setMock(fflib_ISObjectSelector selectorInstance) + protected virtual void setMock(fflib_ISObjectSelector selectorInstance) { m_sObjectByMockSelector.put(selectorInstance.sObjectType(), selectorInstance); } From 3a90663c5840a660393b8ccc4391a1ffd2ade80b Mon Sep 17 00:00:00 2001 From: Clay Chipps Date: Mon, 3 May 2021 14:32:49 -0400 Subject: [PATCH 08/62] add ability to extend other methods --- .../main/classes/fflib_Application.cls | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_Application.cls b/sfdx-source/apex-common/main/classes/fflib_Application.cls index aef60299c5e..81acb1514e2 100644 --- a/sfdx-source/apex-common/main/classes/fflib_Application.cls +++ b/sfdx-source/apex-common/main/classes/fflib_Application.cls @@ -230,7 +230,7 @@ public virtual class fflib_Application * @param recordIds The SObject record Ids, must be all the same SObjectType * @exception Is thrown if the record Ids are not all the same or the SObjectType is not registered **/ - public List selectById(Set recordIds) + public virtual List selectById(Set recordIds) { // No point creating an empty Domain class, nor can we determine the SObjectType anyway if(recordIds==null || recordIds.size()==0) @@ -258,7 +258,7 @@ public virtual class fflib_Application * @param relatedRecords used to extract the related record Ids, e.g. Opportunity records * @param relationshipField field in the passed records that contains the relationship records to query, e.g. Opportunity.AccountId **/ - public List selectByRelationship(List relatedRecords, SObjectField relationshipField) + public virtual List selectByRelationship(List relatedRecords, SObjectField relationshipField) { Set relatedIds = new Set(); for(SObject relatedRecord : relatedRecords) @@ -288,6 +288,11 @@ public virtual class fflib_Application protected Map mockDomainByObject; + /** + * Constructs a Domain factory + **/ + public DomainFactory() { } + /** * Constructs a Domain factory, using an instance of the Selector Factory * and a map of Apex classes implementing fflib_ISObjectDomain by SObjectType @@ -408,18 +413,18 @@ public virtual class fflib_Application } @TestVisible - private virtual void setMock(fflib_ISObjectDomain mockDomain) + protected virtual void setMock(fflib_ISObjectDomain mockDomain) { mockDomainByObject.put((Object) mockDomain.sObjectType(), (fflib_IDomain) mockDomain); } @TestVisible - private virtual void setMock(fflib_IDomain mockDomain) + protected virtual void setMock(fflib_IDomain mockDomain) { mockDomainByObject.put(mockDomain.getType(), mockDomain); } - private Map getConstructorTypeByObject(Map constructorTypeBySObjectType) + protected virtual Map getConstructorTypeByObject(Map constructorTypeBySObjectType) { Map result = new Map(); for (SObjectType sObjectType : constructorTypeBySObjectType.keySet()) From 8ee715764540129cfa8684856dd52da76002618d Mon Sep 17 00:00:00 2001 From: sskular-wonderlab Date: Mon, 17 May 2021 16:42:28 +0100 Subject: [PATCH 09/62] change buildQueryById access modifier to protected change buildQueryById to protected to allow overriding with sharing --- sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls index ccdf03c4e44..4f981bf2a3a 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls @@ -429,7 +429,7 @@ public abstract with sharing class fflib_SObjectSelector /** * Constructs the default SOQL query for this selector, see selectSObjectsById and queryLocatorById **/ - private String buildQuerySObjectById() + protected String buildQuerySObjectById() { return newQueryFactory().setCondition('id in :idSet').toSOQL(); } From 6d3554639eb5573d83bfb4795af2c945bcd9d422 Mon Sep 17 00:00:00 2001 From: Peter Lin Date: Sun, 6 Jun 2021 23:30:03 -0400 Subject: [PATCH 10/62] Change Line 226 to isNotBlank in fflib_SObjects.cls On branch change-SObjects Changes to be committed: modified: sfdx-source/apex-common/main/classes/fflib_SObjects.cls modified: sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls --- sfdx-source/apex-common/main/classes/fflib_SObjects.cls | 2 +- .../apex-common/test/classes/fflib_SObjectsTest.cls | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjects.cls b/sfdx-source/apex-common/main/classes/fflib_SObjects.cls index 45e99c974dc..cda1ecc76f0 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjects.cls +++ b/sfdx-source/apex-common/main/classes/fflib_SObjects.cls @@ -254,7 +254,7 @@ public virtual class fflib_SObjects { for (SObjectField sObjectField : sObjectFields) { - if (String.isBlank((String) record.get(sObjectField))) + if (String.isNotBlank((String) record.get(sObjectField))) { result.add(record); break; diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls b/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls index b5671e976be..253a2d32611 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls @@ -116,7 +116,7 @@ private class fflib_SObjectsTest { DomainAccounts domain = generateDomain(); - System.assert(domain.selectWithShippingCountry().size() == 3); + System.assert(domain.selectWithShippingCountry().size() == 4); } @IsTest @@ -124,7 +124,7 @@ private class fflib_SObjectsTest { DomainAccounts domain = generateDomain(); - System.assert(domain.selectPopulatedRecords().size() == 3); + System.assert(domain.selectPopulatedRecords().size() == 4); } @IsTest @@ -164,7 +164,7 @@ private class fflib_SObjectsTest String country = 'Holland'; domain.setShippingCountry(country); - System.assert(domain.selectByShippingCountry(country).size() == 6); + System.assert(domain.selectByShippingCountry(country).size() == 7); } @@ -221,7 +221,8 @@ private class fflib_SObjectsTest new Account(Name = 'C', ShippingCountry = 'UK'), new Account(Name = 'D', ShippingCountry = ''), new Account(Name = 'E'), - new Account() + new Account(), + new Account(Name = 'G', ShippingCountry = 'Canada') } ); return domain; From db26b83a9a8373f6c2bb6cbc20ee7b60fb6c48d1 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 15 Jun 2021 22:04:58 -0400 Subject: [PATCH 11/62] Update apiVersion to 52.0 (#350) On branch update-apiVersion-to-52.0 Changes to be committed: modified: sfdx-project.json modified: sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml modified: sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml modified: sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml modified: sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml modified: sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml modified: sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml modified: sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml modified: sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml modified: sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml modified: sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml modified: sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml modified: sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml modified: sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml modified: sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml modified: sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml modified: sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml modified: sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml modified: sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml modified: sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml modified: sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml modified: sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml modified: sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml modified: sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml modified: sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml modified: sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml modified: sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml modified: sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml modified: sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml --- sfdx-project.json | 2 +- .../apex-common/main/classes/fflib_Application.cls-meta.xml | 2 +- sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml | 2 +- .../main/classes/fflib_IDomainConstructor.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_IObjects.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml | 2 +- .../main/classes/fflib_ISObjectSelector.cls-meta.xml | 2 +- .../main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_ISObjects.cls-meta.xml | 2 +- sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_QueryFactory.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml | 2 +- .../main/classes/fflib_SObjectUnitOfWork.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SObjects.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_StringBuilder.cls-meta.xml | 2 +- .../apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml | 2 +- .../apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml | 2 +- .../test/classes/fflib_QueryFactoryTest.cls-meta.xml | 2 +- .../test/classes/fflib_SObjectDescribeTest.cls-meta.xml | 2 +- .../test/classes/fflib_SObjectDomainTest.cls-meta.xml | 2 +- .../test/classes/fflib_SObjectSelectorTest.cls-meta.xml | 2 +- .../test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml | 2 +- .../apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml | 2 +- .../test/classes/fflib_SecurityUtilsTest.cls-meta.xml | 2 +- .../test/classes/fflib_StringBuilderTest.cls-meta.xml | 2 +- .../test/classes/mocks/fflib_SObjectMocks.cls-meta.xml | 2 +- 29 files changed, 29 insertions(+), 29 deletions(-) diff --git a/sfdx-project.json b/sfdx-project.json index b9cb67ca139..5b0e01a844c 100644 --- a/sfdx-project.json +++ b/sfdx-project.json @@ -7,5 +7,5 @@ ], "namespace": "", "sfdcLoginUrl": "https://login.salesforce.com", - "sourceApiVersion": "51.0" + "sourceApiVersion": "52.0" } \ No newline at end of file diff --git a/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml index e86c17a0ff4..08c4dbd5cfa 100644 --- a/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml @@ -1,4 +1,4 @@ - 51.0 + 52.0 diff --git a/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active diff --git a/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml b/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml index d75b0582fba..dd61d1f917e 100644 --- a/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 52.0 Active From d4d06b49335f6a8abf1eb480932b9f10b104ab37 Mon Sep 17 00:00:00 2001 From: David Esposito Date: Mon, 23 Aug 2021 07:22:47 -0400 Subject: [PATCH 12/62] Adds workflow_dispatch to the GH workflow so that we can force a build in the UI --- .github/workflows/deploy.and.test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/deploy.and.test.yml b/.github/workflows/deploy.and.test.yml index f2a43eac2dd..394bf826646 100644 --- a/.github/workflows/deploy.and.test.yml +++ b/.github/workflows/deploy.and.test.yml @@ -3,6 +3,7 @@ name: Create a Scratch Org, Push Source and Run Apex Tests on: push: pull_request_target: + workflow_dispatch: jobs: build: From 74ee35110cc41c73701236a0bf4123b5a084308a Mon Sep 17 00:00:00 2001 From: wimvelzeboer Date: Mon, 4 Oct 2021 09:33:46 +0100 Subject: [PATCH 13/62] Add useful methods to Domain --- .../main/classes/fflib_IObjects.cls | 10 ++++++++++ .../apex-common/main/classes/fflib_Objects.cls | 12 ++++++++++++ .../main/classes/fflib_SObjects.cls | 9 ++++++--- .../test/classes/fflib_ObjectsTest.cls | 18 +++++++++++++++--- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_IObjects.cls b/sfdx-source/apex-common/main/classes/fflib_IObjects.cls index d050e104a74..d4c6242cda9 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IObjects.cls +++ b/sfdx-source/apex-common/main/classes/fflib_IObjects.cls @@ -76,4 +76,14 @@ public interface fflib_IObjects extends fflib_IDomain * @return Returns True is the domain has objects */ Boolean isNotEmpty(); + + /** + * @return Returns the first object of the domain + */ + Object getFirstObject(); + + /** + * @return Returns the amount of records contained in the domain + */ + Integer size(); } \ No newline at end of file diff --git a/sfdx-source/apex-common/main/classes/fflib_Objects.cls b/sfdx-source/apex-common/main/classes/fflib_Objects.cls index f65335edb5e..d2646ad7885 100644 --- a/sfdx-source/apex-common/main/classes/fflib_Objects.cls +++ b/sfdx-source/apex-common/main/classes/fflib_Objects.cls @@ -101,6 +101,18 @@ public virtual class fflib_Objects implements fflib_IObjects return !isEmpty(); } + public Object getFirstObject() + { + if (isEmpty()) return null; + + return getObjects().get(0); + } + + public Integer size() + { + return getObjects().size(); + } + protected void setObjects(List objects) { this.objects = objects; diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjects.cls b/sfdx-source/apex-common/main/classes/fflib_SObjects.cls index cda1ecc76f0..5f8fdb34fb7 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjects.cls +++ b/sfdx-source/apex-common/main/classes/fflib_SObjects.cls @@ -93,7 +93,8 @@ public virtual class fflib_SObjects * @param sObjectField The field where the error should be reported * @param message The error message to add to the given field on each record */ - protected void addError(Schema.SObjectField sObjectField, String message) + @TestVisible + protected virtual void addError(Schema.SObjectField sObjectField, String message) { for (SObject record : getRecords()) { @@ -105,7 +106,8 @@ public virtual class fflib_SObjects * Clear the field value on all the records of the domain * @param sObjectField The field to nullify */ - protected void clearField(Schema.SObjectField sObjectField) + @TestVisible + protected virtual void clearField(Schema.SObjectField sObjectField) { clearFields(new Set{ sObjectField }); } @@ -114,7 +116,8 @@ public virtual class fflib_SObjects * Clear the field values on all the records of the domain * @param sObjectFields The fields to nullify */ - protected void clearFields(Set sObjectFields) + @TestVisible + protected virtual void clearFields(Set sObjectFields) { for (SObject record : getRecords()) { diff --git a/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls b/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls index f565afa3ebc..ab6749c114b 100644 --- a/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls @@ -121,9 +121,9 @@ private class fflib_ObjectsTest { fflib_ObjectsTest.Domain dtoDomain = generateDomain(); System.assert(dtoDomain.isNotEmpty(), 'Domain should not be empty'); + System.assertEquals(3, dtoDomain.size(), 'Incorrect amount of records in the domain'); } - @IsTest static void itShouldContainAllTheObjects() { @@ -151,12 +151,25 @@ private class fflib_ObjectsTest ); } + @IsTest + static void itShouldGetTheFirstObject() + { + fflib_ObjectsTest.Domain dtoDomain = generateDomain(); + System.assertEquals(TRANSFER_OBJECT_A, dtoDomain.getFirstObject(), 'Incorrect object returned, expected first'); + } + + @IsTest + static void itShouldGetTheObjectType() + { + fflib_Objects domain = new fflib_Objects(new List()); + System.assertEquals(Object.class, domain.getType(), 'Incorrect returned type'); + } + private static Domain generateDomain() { return new Domain(generateDataTransferObjects()); } - private static List generateDataTransferObjects() { return new List @@ -167,7 +180,6 @@ private class fflib_ObjectsTest }; } - private class Domain extends fflib_Objects { public Domain(List objects) From 00489148bbdd5697dad5893fe247cdc0d3a0c7a1 Mon Sep 17 00:00:00 2001 From: wimvelzeboer Date: Mon, 4 Oct 2021 10:06:21 +0100 Subject: [PATCH 14/62] Add useful methods to Domain - fix failing test --- sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls b/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls index 253a2d32611..fb7f31209b2 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls @@ -100,7 +100,7 @@ private class fflib_SObjectsTest { DomainAccounts domain = generateDomain(); - System.assert(domain.selectWithoutShippingCountry().size() == 3); + System.assert(domain.selectWithoutShippingCountry().size() == 4); } @IsTest From ed9a902267d567b176a7c637ffd05be6d924d4a5 Mon Sep 17 00:00:00 2001 From: Frans Flippo Date: Sat, 25 Sep 2021 14:53:49 +0200 Subject: [PATCH 15/62] Added more test cases to fflib_SObjectSelectorTest and fflib_SObjectUnitOfWorkTest to get coverage for fflib_SObjectSelector and fflib_SObjectUnitOfWork to 75%. --- .../classes/fflib_SObjectSelectorTest.cls | 178 +++++++++++++++++- .../classes/fflib_SObjectUnitOfWorkTest.cls | 37 +++- 2 files changed, 212 insertions(+), 3 deletions(-) diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls index 0fd4c89b0ee..9b097fcd0f8 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls @@ -159,6 +159,18 @@ private with sharing class fflib_SObjectSelectorTest assertFieldListString(fieldListString, null); } + static testMethod void testSOQL_defaultSorting() + { + Testfflib_SObjectSelectorDefaultSorting selector = new Testfflib_SObjectSelectorDefaultSorting(false); + String soql = selector.newQueryFactory().toSOQL(); + Pattern p = Pattern.compile('SELECT (.*) FROM Account ORDER BY Name ASC NULLS FIRST '); + Matcher m = p.matcher(soql); + System.assert(m.matches(), 'Generated SOQL does not match expected pattern. Here is the generated SOQL: ' + soql); + System.assertEquals(1, m.groupCount(), 'Unexpected number of groups captured.'); + String fieldListString = m.group(1); + assertFieldListString(fieldListString, null); + } + static testMethod void testDefaultConfig() { Testfflib_SObjectSelector selector = new Testfflib_SObjectSelector(); @@ -239,7 +251,122 @@ private with sharing class fflib_SObjectSelectorTest Matcher soqlMatcher = soqlPattern.matcher(soql); system.assert(soqlMatcher.matches(), 'The SOQL should have that expected.'); } - + + @IsTest + static void testConfigureQueryFactoryFields() { + //Given + Testfflib_UserSObjectSelector selector = new Testfflib_UserSObjectSelector(); + fflib_QueryFactory qf = new fflib_QueryFactory(Account.SObjectType); + + Set expectedSelectFields = new Set{ 'Owner.Name', 'Owner.Id', 'Owner.Username', 'Owner.LastLoginDate' }; + if (UserInfo.isMultiCurrencyOrganization()) + { + expectedSelectFields.add('Owner.CurrencyIsoCode'); + } + + //When + selector.configureQueryFactoryFields(qf, 'Owner'); + + //Then + String soql = qf.toSOQL(); + Pattern soqlPattern = Pattern.compile('SELECT (.*) FROM Account'); + Matcher soqlMatcher = soqlPattern.matcher(soql); + System.assert(soqlMatcher.matches(), 'Generated SOQL does not match expected pattern. Here is the generated SOQL: ' + soql); + + List actualSelectFields = soqlMatcher.group(1).deleteWhiteSpace().split(','); + System.assertEquals(expectedSelectFields, new Set(actualSelectFields)); + } + + @IsTest + static void testAddQueryFactorySubselect() { + //Given + Testfflib_UserSObjectSelector selector = new Testfflib_UserSObjectSelector(); + fflib_QueryFactory qf = new fflib_QueryFactory(Account.SObjectType); + + Set expectedSelectFields = new Set{ 'Name', 'Id', 'Username', 'LastLoginDate' }; + if (UserInfo.isMultiCurrencyOrganization()) + { + expectedSelectFields.add('CurrencyIsoCode'); + } + + //When + selector.addQueryFactorySubselect(qf); + + //Then + String soql = qf.toSOQL(); + Pattern soqlPattern = Pattern.compile('SELECT Id, \\(SELECT (.*) FROM Users ORDER BY Name ASC NULLS FIRST \\) +FROM Account'); + Matcher soqlMatcher = soqlPattern.matcher(soql); + System.assert(soqlMatcher.matches(), 'Generated SOQL does not match expected pattern. Here is the generated SOQL: ' + soql); + + List actualSelectFields = soqlMatcher.group(1).deleteWhiteSpace().split(','); + System.assertEquals(expectedSelectFields, new Set(actualSelectFields)); + } + + @IsTest + static void testAddQueryFactorySubselect2() { + //Given + Testfflib_UserSObjectSelector selector = new Testfflib_UserSObjectSelector(); + fflib_QueryFactory qf = new fflib_QueryFactory(Account.SObjectType); + + Set expectedSelectFields = new Set{ 'Name', 'Id', 'Username', 'LastLoginDate' }; + if (UserInfo.isMultiCurrencyOrganization()) + { + expectedSelectFields.add('CurrencyIsoCode'); + } + + //When + selector.addQueryFactorySubselect(qf, 'Users'); + + //Then + String soql = qf.toSOQL(); + Pattern soqlPattern = Pattern.compile('SELECT Id, \\(SELECT (.*) FROM Users ORDER BY Name ASC NULLS FIRST \\) +FROM Account'); + Matcher soqlMatcher = soqlPattern.matcher(soql); + System.assert(soqlMatcher.matches(), 'Generated SOQL does not match expected pattern. Here is the generated SOQL: ' + soql); + + List actualSelectFields = soqlMatcher.group(1).deleteWhiteSpace().split(','); + System.assertEquals(expectedSelectFields, new Set(actualSelectFields)); + } + + @IsTest + static void testGetFieldListString() { + //Given + Testfflib_UserSObjectSelector selector = new Testfflib_UserSObjectSelector(); + fflib_QueryFactory qf = new fflib_QueryFactory(Account.SObjectType); + + Set expectedSelectFields = new Set{ 'Name', 'Id', 'Username', 'LastLoginDate' }; + if (UserInfo.isMultiCurrencyOrganization()) + { + expectedSelectFields.add('CurrencyIsoCode'); + } + + //When + String fieldListString = selector.getFieldListString(); + + //Then + List actualSelectFields = fieldListString.deleteWhiteSpace().split(','); + System.assertEquals(expectedSelectFields, new Set(actualSelectFields)); + } + + @IsTest + static void testGetRelatedFieldListString() { + //Given + Testfflib_UserSObjectSelector selector = new Testfflib_UserSObjectSelector(); + + Set expectedSelectFields = new Set{ 'Owner.Name', 'Owner.Id', 'Owner.Username', 'Owner.LastLoginDate' }; + if (UserInfo.isMultiCurrencyOrganization()) + { + expectedSelectFields.add('Owner.CurrencyIsoCode'); + } + + //When + String fieldListString = selector.getRelatedFieldListString('Owner'); + + //Then + List actualSelectFields = fieldListString.deleteWhiteSpace().split(','); + System.assertEquals(expectedSelectFields, new Set(actualSelectFields)); + + } + private static void assertEqualsSelectFields(String expectedSelectFields, String actualSelectFields) { Set expected = new Set(expectedSelectFields.deleteWhiteSpace().split(',')); @@ -281,6 +408,53 @@ private with sharing class fflib_SObjectSelectorTest } } + private class Testfflib_UserSObjectSelector extends fflib_SObjectSelector + { + public Testfflib_UserSObjectSelector() + { + super(); + } + + public List getSObjectFieldList() + { + return new List { + User.Name, + User.Id, + User.Username, + User.LastLoginDate + }; + } + + public Schema.SObjectType getSObjectType() + { + return User.SObjectType; + } + + } + + private class Testfflib_SObjectSelectorDefaultSorting extends fflib_SObjectSelector + { + public Testfflib_SObjectSelectorDefaultSorting(Boolean includeFieldSetFields) + { + super(includeFieldSetFields); + } + + public List getSObjectFieldList() + { + return new List { + Account.Name, + Account.Id, + Account.AccountNumber, + Account.AnnualRevenue + }; + } + + public Schema.SObjectType getSObjectType() + { + return Account.sObjectType; + } + } + /** * Create test user **/ @@ -301,4 +475,4 @@ private with sharing class fflib_SObjectSelectorTest } return testUser; } -} \ No newline at end of file +} diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls b/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls index 22081f9c968..06274a9f38f 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls @@ -121,6 +121,41 @@ private with sharing class fflib_SObjectUnitOfWorkTest System.assert(exceptionThrown); } + @IsTest + private static void testRegisterDeleted() + { + // GIVEN - two existing records + Opportunity opportunity = new Opportunity(Id = fflib_IDGenerator.generate(Schema.Opportunity.SObjectType)); + Product2 product = new Product2(Id = fflib_IDGenerator.generate(Schema.Product2.SObjectType)); + MockDML mockDML = new MockDML(); + fflib_SObjectUnitOfWork unitOfWork = new fflib_SObjectUnitOfWork(MY_SOBJECTS, mockDML); + + // WHEN - we mark the records as deleted + unitOfWork.registerDeleted(new List { opportunity, product }); + unitOfWork.commitWork(); + + // THEN - the dmlDelete action should be invoked + System.assertEquals(new List { opportunity, product }, mockDML.recordsForDelete); + } + + @IsTest + private static void testRegisterPermanentlyDeleted() + { + // GIVEN - two existing records + Opportunity opportunity = new Opportunity(Id = fflib_IDGenerator.generate(Schema.Opportunity.SObjectType)); + Product2 product = new Product2(Id = fflib_IDGenerator.generate(Schema.Product2.SObjectType)); + MockDML mockDML = new MockDML(); + fflib_SObjectUnitOfWork unitOfWork = new fflib_SObjectUnitOfWork(MY_SOBJECTS, mockDML); + + // WHEN - we mark the records as deleted + unitOfWork.registerPermanentlyDeleted(new List { opportunity, product }); + unitOfWork.commitWork(); + + // THEN - the dmlDelete and emptyRecycleBin actions should be invoked + System.assertEquals(new List { opportunity, product }, mockDML.recordsForDelete); + System.assertEquals(new List { opportunity, product }, mockDML.recordsForRecycleBin); + } + @IsTest private static void testRegisterEmptyRecycleBin() { @@ -803,4 +838,4 @@ private with sharing class fflib_SObjectUnitOfWorkTest public class DerivedUnitOfWorkException extends Exception {} public class FailDoingWorkException extends Exception {} -} \ No newline at end of file +} From 5b5b6cf88c4629c65dee1ef3ccfbd2c3723eb82b Mon Sep 17 00:00:00 2001 From: "John M. Daniel" Date: Tue, 15 Mar 2022 10:48:22 -0400 Subject: [PATCH 16/62] DEVOPS Changes made: * Updated all APIs to v54.0 --- .../apex-common/main/classes/fflib_Application.cls-meta.xml | 2 +- sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml | 2 +- .../main/classes/fflib_IDomainConstructor.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_IObjects.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml | 2 +- .../main/classes/fflib_ISObjectSelector.cls-meta.xml | 2 +- .../main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_ISObjects.cls-meta.xml | 2 +- sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_QueryFactory.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml | 2 +- .../main/classes/fflib_SObjectUnitOfWork.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SObjects.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_StringBuilder.cls-meta.xml | 2 +- .../apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml | 2 +- .../apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml | 2 +- .../test/classes/fflib_QueryFactoryTest.cls-meta.xml | 2 +- .../test/classes/fflib_SObjectDescribeTest.cls-meta.xml | 2 +- .../test/classes/fflib_SObjectDomainTest.cls-meta.xml | 2 +- .../test/classes/fflib_SObjectSelectorTest.cls-meta.xml | 2 +- .../test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml | 2 +- .../apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml | 2 +- .../test/classes/fflib_SecurityUtilsTest.cls-meta.xml | 2 +- .../test/classes/fflib_StringBuilderTest.cls-meta.xml | 2 +- .../test/classes/mocks/fflib_SObjectMocks.cls-meta.xml | 2 +- 28 files changed, 28 insertions(+), 28 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml index ecd550068a4..bd8e9205ef8 100644 --- a/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml @@ -1,4 +1,4 @@ - 53.0 + 54.0 diff --git a/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active diff --git a/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml b/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml index f928c8e56bc..40d67933d00 100644 --- a/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml @@ -1,5 +1,5 @@ - 53.0 + 54.0 Active From 571d2cc9f8f9382e6c4c67297ac4ef64a8f01d51 Mon Sep 17 00:00:00 2001 From: Scott McClung Date: Tue, 15 Mar 2022 17:59:47 -0700 Subject: [PATCH 17/62] Applying permission set to Read Only profile user --- .../apex-common/test/classes/fflib_SecurityUtilsTest.cls | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls b/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls index 3ed46bb42a9..dea962a7c67 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls @@ -80,8 +80,9 @@ private class fflib_SecurityUtilsTest { static User setupTestUser(String profileName){ Profile p; - Boolean usedMinimumAccessProfile = false; + Boolean applyReadOnlyPermissionSet = false; if (profileName == 'Read Only') { + applyReadOnlyPermissionSet = true; try { p = getProfile(profileName); } catch (QueryException ex) { @@ -89,7 +90,6 @@ private class fflib_SecurityUtilsTest { // #315 If the "Read Only" Profile is absent, then assume it's a Spring '21 org and see if there's a // "Minimum Access - Salesforce" Profile we can use instead. p = getProfile('Minimum Access - Salesforce'); - usedMinimumAccessProfile = true; } } } else { @@ -117,7 +117,7 @@ private class fflib_SecurityUtilsTest { ); insert usr; - if (usedMinimumAccessProfile) { + if (applyReadOnlyPermissionSet) { // #315 We need to assign the Perm Set to grant Account "Read" access PermissionSet accountReadPS = [SELECT Id FROM PermissionSet WHERE Name = 'ReadOnlyPermissionSet']; PermissionSetAssignment psa = new PermissionSetAssignment(AssigneeId = usr.Id, PermissionSetId = accountReadPS.Id); From 6f67e80df025e7c17375b18b356b6dca02760767 Mon Sep 17 00:00:00 2001 From: wimvelzeboer Date: Tue, 5 Apr 2022 17:15:34 +0100 Subject: [PATCH 18/62] Fix incorrect condition in getRecordsWithBlankFieldValues method --- sfdx-source/apex-common/main/classes/fflib_SObjects.cls | 9 ++++----- .../apex-common/test/classes/fflib_SObjectsTest.cls | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjects.cls b/sfdx-source/apex-common/main/classes/fflib_SObjects.cls index 329c6fd6a27..598601e2d14 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjects.cls +++ b/sfdx-source/apex-common/main/classes/fflib_SObjects.cls @@ -257,11 +257,10 @@ public virtual class fflib_SObjects { for (SObjectField sObjectField : sObjectFields) { - if (String.isNotBlank((String) record.get(sObjectField))) - { - result.add(record); - break; - } + if (String.isNotBlank((String) record.get(sObjectField))) continue; + + result.add(record); + break; } } return result; diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls b/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls index fb7f31209b2..778304dd796 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls @@ -100,7 +100,7 @@ private class fflib_SObjectsTest { DomainAccounts domain = generateDomain(); - System.assert(domain.selectWithoutShippingCountry().size() == 4); + System.assertEquals(3, domain.selectWithoutShippingCountry().size()); } @IsTest From 5220da622df730d06c49086ce0f4fff7e67e1e0a Mon Sep 17 00:00:00 2001 From: wimvelzeboer Date: Thu, 7 Apr 2022 22:18:16 +0100 Subject: [PATCH 19/62] Code comment fixes --- .../main/classes/fflib_SObjects.cls | 134 +++++++++--------- .../test/classes/fflib_SObjectsTest.cls | 32 ++--- 2 files changed, 80 insertions(+), 86 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjects.cls b/sfdx-source/apex-common/main/classes/fflib_SObjects.cls index 598601e2d14..95c48ccf017 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjects.cls +++ b/sfdx-source/apex-common/main/classes/fflib_SObjects.cls @@ -90,40 +90,40 @@ public virtual class fflib_SObjects /** * Adds an error message to the a field records in the domain * - * @param sObjectField The field where the error should be reported + * @param field The field where the error should be reported * @param message The error message to add to the given field on each record */ @TestVisible - protected virtual void addError(Schema.SObjectField sObjectField, String message) + protected virtual void addError(Schema.SObjectField field, String message) { for (SObject record : getRecords()) { - record.addError(sObjectField, error(message, record, sObjectField)); + record.addError(field, error(message, record, field)); } } /** * Clear the field value on all the records of the domain - * @param sObjectField The field to nullify + * @param field The field to nullify */ @TestVisible - protected virtual void clearField(Schema.SObjectField sObjectField) + protected virtual void clearField(Schema.SObjectField field) { - clearFields(new Set{ sObjectField }); + clearFields(new Set{ field }); } /** * Clear the field values on all the records of the domain - * @param sObjectFields The fields to nullify + * @param fields The fields to nullify */ @TestVisible - protected virtual void clearFields(Set sObjectFields) + protected virtual void clearFields(Set fields) { for (SObject record : getRecords()) { - for (SObjectField sObjectField : sObjectFields) + for (SObjectField field : fields) { - record.put(sObjectField, null); + record.put(field, null); } } } @@ -156,76 +156,76 @@ public virtual class fflib_SObjects } /** - * @param sObjectField The SObjectField reference of the type Id + * @param field The SObjectField reference of the type Id * * @return Return a set with all the Id values of the given field */ @TestVisible - protected Set getIdFieldValues(Schema.SObjectField sObjectField) + protected Set getIdFieldValues(Schema.SObjectField field) { Set result = new Set(); for (SObject record : getRecords()) { - result.add((Id) record.get(sObjectField)); + result.add((Id) record.get(field)); } return result; } /** - * @param sObjectField The SObjectField reference of the type String + * @param field The SObjectField reference of the type String * * @return Return a set with all the String values of the given field */ @TestVisible - protected Set getStringFieldValues(Schema.SObjectField sObjectField) + protected Set getStringFieldValues(Schema.SObjectField field) { Set result = new Set(); for (SObject record : getRecords()) { - result.add((String) record.get(sObjectField)); + result.add((String) record.get(field)); } return result; } /** - * @param sObjectField The SObjectField reference + * @param field The SObjectField reference * * @return Return a set with all the values of the given field */ @TestVisible - protected virtual Set getFieldValues(Schema.SObjectField sObjectField) + protected virtual Set getFieldValues(Schema.SObjectField field) { Set result = new Set(); for (SObject record : getRecords()) { - result.add(record.get(sObjectField)); + result.add(record.get(field)); } return result; } /** - * @param sObjectField The Schema.SObjectField to compare against the given value - * @param value The given value of the records sObjectField to include in the return + * @param field The Schema.SObjectField to compare against the given value + * @param value The given value of the records field to include in the return * - * @return A list with only the SObjects where the given sObjectField has the provided value + * @return A list with only the SObjects where the given field has the provided value */ - protected virtual List getRecordsByFieldValue(Schema.SObjectField sObjectField, Object value) + protected virtual List getRecordsByFieldValue(Schema.SObjectField field, Object value) { - return getRecordsByFieldValues(sObjectField, new Set{value}); + return getRecordsByFieldValues(field, new Set{value}); } /** - * @param sObjectField The Schema.SObjectField to compare against the given value - * @param values The given values of the records sObjectField to include in the return + * @param field The Schema.SObjectField to compare against the given value + * @param values The given values of the records field to include in the return * - * @return A list with only the SObjects where the given sObjectField value is part of the provided values + * @return A list with only the SObjects where the given field value is part of the provided values */ - protected virtual List getRecordsByFieldValues(Schema.SObjectField sObjectField, Set values) + protected virtual List getRecordsByFieldValues(Schema.SObjectField field, Set values) { List result = new List(); for (SObject record : getRecords()) { - if (values?.contains(record.get(sObjectField))) + if (values?.contains(record.get(field))) { result.add(record); } @@ -234,30 +234,30 @@ public virtual class fflib_SObjects } /** - * @param sObjectField The Schema.SObjectField to check its value for a Blank value + * @param field The Schema.SObjectField to check its value for a Blank value * - * @return A list with only the SObjects where the given sObjectField value is either null or '') + * @return A list with only the SObjects where the given field value is either null or '') */ - protected virtual List getRecordsWithBlankFieldValues(Schema.SObjectField sObjectField) + protected virtual List getRecordsWithBlankFieldValues(Schema.SObjectField field) { return getRecordsWithBlankFieldValues( - new Set {sObjectField} + new Set {field} ); } /** - * @param sObjectFields The Schema.SObjectFields to check their value for a Blank value + * @param fields The Schema.SObjectFields to check their value for a Blank value * - * @return A list with only the SObjects where the at least one given sObjectField value is either null or '') + * @return A list with only the SObjects where the at least one given field value is either null or '') */ - protected virtual List getRecordsWithBlankFieldValues(Set sObjectFields) + protected virtual List getRecordsWithBlankFieldValues(Set fields) { List result = new List(); for (SObject record : getRecords()) { - for (SObjectField sObjectField : sObjectFields) + for (SObjectField field : fields) { - if (String.isNotBlank((String) record.get(sObjectField))) continue; + if (String.isNotBlank((String) record.get(field))) continue; result.add(record); break; @@ -267,19 +267,19 @@ public virtual class fflib_SObjects } /** - * @param sObjectFields The Schema.SObjectFields to check their value for a Blank value + * @param fields The Schema.SObjectFields to check their value for a Blank value * - * @return A list with only the SObjects where all given sObjectField values are either null or '' + * @return A list with only the SObjects where all given field values are either null or '' */ - protected virtual List getRecordsWithAllBlankFieldValues(Set sObjectFields) + protected virtual List getRecordsWithAllBlankFieldValues(Set fields) { List result = new List(); for (SObject record : getRecords()) { Boolean allBlank = true; - for (SObjectField sObjectField : sObjectFields) + for (SObjectField field : fields) { - if (String.isNotBlank((String) record.get(sObjectField))) + if (String.isNotBlank((String) record.get(field))) { allBlank = false; break; @@ -291,30 +291,30 @@ public virtual class fflib_SObjects } /** - * @param sObjectField The Schema.SObjectField to check its value for a Non-Blank value + * @param field The Schema.SObjectField to check its value for a Non-Blank value * - * @return A list with only the SObjects where the given sObjectField value is not null or '' + * @return A list with only the SObjects where the given field value is not null or '' */ - protected virtual List getRecordsWithNotBlankFieldValues(Schema.SObjectField sObjectField) + protected virtual List getRecordsWithNotBlankFieldValues(Schema.SObjectField field) { return getRecordsWithNotBlankFieldValues( - new Set {sObjectField} + new Set {field} ); } /** - * @param sObjectFields The Schema.SObjectFields to check their value for a Non-Blank value + * @param fields The Schema.SObjectFields to check their value for a Non-Blank value * - * @return A list with only the SObjects where the at least one given sObjectField value not null or '' + * @return A list with only the SObjects where the at least one given field value not null or '' */ - protected virtual List getRecordsWithNotBlankFieldValues(Set sObjectFields) + protected virtual List getRecordsWithNotBlankFieldValues(Set fields) { List result = new List(); for (SObject record : getRecords()) { - for (SObjectField sObjectField : sObjectFields) + for (SObjectField field : fields) { - if (String.isNotBlank((String) record.get(sObjectField))) + if (String.isNotBlank((String) record.get(field))) { result.add(record); break; @@ -325,19 +325,19 @@ public virtual class fflib_SObjects } /** - * @param sObjectFields The Schema.SObjectFields to check their value for a Non-Blank value + * @param fields The Schema.SObjectFields to check their value for a Non-Blank value * - * @return A list with only the SObjects where all given sObjectField values are not null or '' + * @return A list with only the SObjects where all given field values are not null or '' */ - protected virtual List getRecordsWithAllNotBlankFieldValues(Set sObjectFields) + protected virtual List getRecordsWithAllNotBlankFieldValues(Set fields) { List result = new List(); for (SObject record : getRecords()) { Boolean allNonBlank = true; - for (SObjectField sObjectField : sObjectFields) + for (SObjectField field : fields) { - if (String.isBlank((String) record.get(sObjectField))) + if (String.isBlank((String) record.get(field))) { allNonBlank = false; break; @@ -351,33 +351,33 @@ public virtual class fflib_SObjects /** * Modifies a value of a field for all records in the domain * - * @param sObjectField The reference to the SObjectField to be modified + * @param field The reference to the SObjectField to be modified * @param value The value to store in the given SObjectField */ - protected virtual void setFieldValue(Schema.SObjectField sObjectField, Object value) + protected virtual void setFieldValue(Schema.SObjectField field, Object value) { for (SObject record : getRecords()) { - record.put(sObjectField, value); + record.put(field, value); } } /** - * @param sObjectFieldToCheck The SObjectField 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 sObjectFieldToCheck fields value + * @param fieldToCheck The SObjectField to match the key against in the provided map + * @param fieldToUpdate The SObjectField to store the mapped value when the key matches the value in the fieldToUpdate field + * @param values Map of values to store by the fieldToCheck fields value */ protected virtual void setFieldValueByMap( - Schema.SObjectField sObjectFieldToCheck, - Schema.SObjectField sObjectFieldToUpdate, + Schema.SObjectField fieldToCheck, + Schema.SObjectField fieldToUpdate, Map values) { for (SObject record : getRecords()) { - Object keyValue = record.get(sObjectFieldToCheck); + Object keyValue = record.get(fieldToCheck); if (values?.containsKey(keyValue)) { - record.put(sObjectFieldToUpdate, values.get(keyValue)); + record.put(fieldToUpdate, values.get(keyValue)); } } } diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls b/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls index 778304dd796..dd5bd13f0a0 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls @@ -77,12 +77,12 @@ private class fflib_SObjectsTest Set recordIds = new Set {idA, idB, idC}; System.assert( - domain.getRecordIds().containsAll(recordIds), + domain.getRecordIds().equals(recordIds), 'The domain should return all the record Ids' ); System.assert( - domain.getIdFieldValues(Schema.Account.Id).containsAll(recordIds), + domain.getIdFieldValues(Schema.Account.Id).equals(recordIds), 'The domain should return all the record Ids' ); } @@ -132,28 +132,22 @@ private class fflib_SObjectsTest { DomainAccounts domain = generateDomain(); + final Set expected = new Set + { + null, + '', + 'Canada', + 'Ireland', + 'UK', + 'USA' + }; System.assert( - domain.getStringFieldValues(Schema.Account.ShippingCountry) - .containsAll( - new Set{ - 'USA', - 'Ireland', - 'UK', - '' - } - ) + domain.getStringFieldValues(Schema.Account.ShippingCountry).equals(expected) ); System.assert( domain.getFieldValues(Schema.Account.ShippingCountry) - .containsAll( - new Set{ - 'USA', - 'Ireland', - 'UK', - '' - } - ) + .equals(expected) ); } From 698fa67fa5253dbf2c35136288acca76513859b7 Mon Sep 17 00:00:00 2001 From: wimvelzeboer Date: Sat, 23 Apr 2022 20:47:35 +0100 Subject: [PATCH 20/62] Remove getFirstObject method --- sfdx-source/apex-common/main/classes/fflib_IObjects.cls | 5 ----- sfdx-source/apex-common/main/classes/fflib_Objects.cls | 7 ------- sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls | 7 ------- 3 files changed, 19 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_IObjects.cls b/sfdx-source/apex-common/main/classes/fflib_IObjects.cls index d4c6242cda9..80358b22dd7 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IObjects.cls +++ b/sfdx-source/apex-common/main/classes/fflib_IObjects.cls @@ -77,11 +77,6 @@ public interface fflib_IObjects extends fflib_IDomain */ Boolean isNotEmpty(); - /** - * @return Returns the first object of the domain - */ - Object getFirstObject(); - /** * @return Returns the amount of records contained in the domain */ diff --git a/sfdx-source/apex-common/main/classes/fflib_Objects.cls b/sfdx-source/apex-common/main/classes/fflib_Objects.cls index d2646ad7885..44c4f069eaf 100644 --- a/sfdx-source/apex-common/main/classes/fflib_Objects.cls +++ b/sfdx-source/apex-common/main/classes/fflib_Objects.cls @@ -101,13 +101,6 @@ public virtual class fflib_Objects implements fflib_IObjects return !isEmpty(); } - public Object getFirstObject() - { - if (isEmpty()) return null; - - return getObjects().get(0); - } - public Integer size() { return getObjects().size(); diff --git a/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls b/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls index ab6749c114b..91454ef0c36 100644 --- a/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls @@ -151,13 +151,6 @@ private class fflib_ObjectsTest ); } - @IsTest - static void itShouldGetTheFirstObject() - { - fflib_ObjectsTest.Domain dtoDomain = generateDomain(); - System.assertEquals(TRANSFER_OBJECT_A, dtoDomain.getFirstObject(), 'Incorrect object returned, expected first'); - } - @IsTest static void itShouldGetTheObjectType() { From 0016af10c89e207d36e57a8af5238e2bdcdc6311 Mon Sep 17 00:00:00 2001 From: Daniel Wutz Date: Tue, 10 May 2022 14:59:46 +0200 Subject: [PATCH 21/62] Add method to include ALL ROWS in QueryFactory --- .../main/classes/fflib_QueryFactory.cls | 13 ++++++++++++ .../test/classes/fflib_QueryFactoryTest.cls | 21 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls index 3a9df8d0574..0f725fca4b4 100644 --- a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls +++ b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls @@ -74,6 +74,7 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr private Boolean enforceFLS; private Boolean sortSelectFields = true; + private Boolean allRows = false; /** * The relationship and subselectQueryMap variables are used to support subselect queries. Subselects can be added to @@ -662,6 +663,14 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr return setOrdering(ordr); } + /** + * @param addAllRows whether an ALL ROWS clause will be added to the resulting query. + **/ + public fflib_QueryFactory setAllRows(Boolean addAllRows){ + this.allRows = addAllRows; + return this; + } + /** * Convert the values provided to this instance into a full SOQL string for use with Database.query * Check to see if subqueries queries need to be added after the field list. @@ -703,6 +712,9 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr if(offsetCount != null) result += ' OFFSET '+offsetCount; + + if(allRows) + result += ' ALL ROWS'; return result; } @@ -716,6 +728,7 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr fflib_QueryFactory clone = new fflib_QueryFactory(this.table) .setLimit(this.limitCount) .setOffset(this.offsetCount) + .setAllRows(this.allRows) .setCondition(this.conditionExpression) .setEnforceFLS(this.enforceFLS); diff --git a/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls b/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls index 2e4ce67540e..91b2d611a9f 100644 --- a/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls @@ -564,6 +564,7 @@ private class fflib_QueryFactoryTest { .selectField('Description') .addOrdering(new fflib_QueryFactory.Ordering('Contact','name',fflib_QueryFactory.SortOrder.ASCENDING) ) .addOrdering( new fflib_QueryFactory.Ordering('Contact','CreatedDATE',fflib_QueryFactory.SortOrder.DESCENDING)) + .setAllRows(true) .setEnforceFLS(true); fflib_QueryFactory qf2 = qf.deepClone(); @@ -584,6 +585,7 @@ private class fflib_QueryFactoryTest { .selectField('Description') .addOrdering(new fflib_QueryFactory.Ordering('Account','Name',fflib_QueryFactory.SortOrder.ASCENDING) ) .addOrdering( new fflib_QueryFactory.Ordering('Account','Description',fflib_QueryFactory.SortOrder.DESCENDING)) + .setAllRows(true) .setEnforceFLS(true); qf.subselectQuery('Contacts', true); @@ -607,6 +609,7 @@ private class fflib_QueryFactoryTest { .selectField('Description') .addOrdering(new fflib_QueryFactory.Ordering('Contact','name',fflib_QueryFactory.SortOrder.ASCENDING) ) .addOrdering( new fflib_QueryFactory.Ordering('Contact','CreatedDATE',fflib_QueryFactory.SortOrder.DESCENDING)) + .setAllRows(true) .setEnforceFLS(true); @@ -693,6 +696,24 @@ private class fflib_QueryFactoryTest { System.assertNotEquals(orderedQuery, actualSoql); } + @isTest + static void testSoql_allRows(){ + //Given + fflib_QueryFactory qf = new fflib_QueryFactory(User.SObjectType); + qf.selectField('Id'); + qf.setAllRows(true); + + String allRowsQuery = + 'SELECT Id ' + +'FROM User ' + +'ALL ROWS'; + + //When + String actualSoql = qf.toSOQL(); + + //Then + System.assertEquals(allRowsQuery, actualSoql); + } public static User createTestUser_noAccess(){ User usr; From a56f0f13cc126e6a9693bd53e9d2f17092efb5c0 Mon Sep 17 00:00:00 2001 From: "John M. Daniel" Date: Sun, 15 May 2022 15:38:52 -0400 Subject: [PATCH 22/62] Update .gitignore Adding new ".sf/" folder to gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6e467fe0109..02ee6d0afa9 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ IlluminatedCloud/ # SFDX Related .sfdx/ +.sf/ sfdx-source/common-base/main/default/ sfdx-source/untracked/ .execanon @@ -48,4 +49,4 @@ package-lock.json sfdx-source/group* -research/ \ No newline at end of file +research/ From ede2c242a503fe80b5864a1ef94aa620b9a094c4 Mon Sep 17 00:00:00 2001 From: Daniel Wutz Date: Wed, 25 May 2022 13:08:26 +0200 Subject: [PATCH 23/62] Changes allRows method to no parameters, adds curly braces --- .../apex-common/main/classes/fflib_QueryFactory.cls | 8 ++++---- .../apex-common/test/classes/fflib_QueryFactoryTest.cls | 5 +---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls index 0f725fca4b4..882bde7d9da 100644 --- a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls +++ b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls @@ -666,8 +666,8 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr /** * @param addAllRows whether an ALL ROWS clause will be added to the resulting query. **/ - public fflib_QueryFactory setAllRows(Boolean addAllRows){ - this.allRows = addAllRows; + public fflib_QueryFactory setAllRows(){ + this.allRows = true; return this; } @@ -713,8 +713,9 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr if(offsetCount != null) result += ' OFFSET '+offsetCount; - if(allRows) + if(allRows) { result += ' ALL ROWS'; + } return result; } @@ -728,7 +729,6 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr fflib_QueryFactory clone = new fflib_QueryFactory(this.table) .setLimit(this.limitCount) .setOffset(this.offsetCount) - .setAllRows(this.allRows) .setCondition(this.conditionExpression) .setEnforceFLS(this.enforceFLS); diff --git a/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls b/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls index 91b2d611a9f..3eec7a8237e 100644 --- a/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls @@ -564,7 +564,6 @@ private class fflib_QueryFactoryTest { .selectField('Description') .addOrdering(new fflib_QueryFactory.Ordering('Contact','name',fflib_QueryFactory.SortOrder.ASCENDING) ) .addOrdering( new fflib_QueryFactory.Ordering('Contact','CreatedDATE',fflib_QueryFactory.SortOrder.DESCENDING)) - .setAllRows(true) .setEnforceFLS(true); fflib_QueryFactory qf2 = qf.deepClone(); @@ -585,7 +584,6 @@ private class fflib_QueryFactoryTest { .selectField('Description') .addOrdering(new fflib_QueryFactory.Ordering('Account','Name',fflib_QueryFactory.SortOrder.ASCENDING) ) .addOrdering( new fflib_QueryFactory.Ordering('Account','Description',fflib_QueryFactory.SortOrder.DESCENDING)) - .setAllRows(true) .setEnforceFLS(true); qf.subselectQuery('Contacts', true); @@ -609,7 +607,6 @@ private class fflib_QueryFactoryTest { .selectField('Description') .addOrdering(new fflib_QueryFactory.Ordering('Contact','name',fflib_QueryFactory.SortOrder.ASCENDING) ) .addOrdering( new fflib_QueryFactory.Ordering('Contact','CreatedDATE',fflib_QueryFactory.SortOrder.DESCENDING)) - .setAllRows(true) .setEnforceFLS(true); @@ -701,7 +698,7 @@ private class fflib_QueryFactoryTest { //Given fflib_QueryFactory qf = new fflib_QueryFactory(User.SObjectType); qf.selectField('Id'); - qf.setAllRows(true); + qf.setAllRows(); String allRowsQuery = 'SELECT Id ' From 2e96765173496e800a9c330d6d3c8480914b8bd0 Mon Sep 17 00:00:00 2001 From: Daniel Wutz Date: Wed, 25 May 2022 13:10:12 +0200 Subject: [PATCH 24/62] Change method documentation --- sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls index 882bde7d9da..3cd29f06f22 100644 --- a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls +++ b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls @@ -664,7 +664,7 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr } /** - * @param addAllRows whether an ALL ROWS clause will be added to the resulting query. + * whether an ALL ROWS clause will be added to the resulting query **/ public fflib_QueryFactory setAllRows(){ this.allRows = true; From 3cf078803a27a4d9198bb4f09c9efe1fccffc6ba Mon Sep 17 00:00:00 2001 From: David Esposito Date: Wed, 13 Jul 2022 17:13:29 -0400 Subject: [PATCH 25/62] #419 - implements a proposal for supporting native User Mode Database Operations introduced in Summer '22 --- .../main/classes/fflib_QueryFactory.cls | 76 +++++++++++++------ .../main/classes/fflib_SObjectSelector.cls | 75 +++++++++++++++--- .../main/classes/fflib_SObjectUnitOfWork.cls | 14 ++++ 3 files changed, 132 insertions(+), 33 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls index 3cd29f06f22..547f069c3a6 100644 --- a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls +++ b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls @@ -54,6 +54,7 @@ **/ public class fflib_QueryFactory { //No explicit sharing declaration - inherit from caller public enum SortOrder {ASCENDING, DESCENDING} + public enum FLSEnforcement{NONE, LEGACY, USER_MODE} /** * This property is read-only and may not be set after instantiation. @@ -71,8 +72,8 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr * This can optionally be enforced (or not) by calling the setEnforceFLS method prior to calling * one of the selectField or selectFieldset methods. **/ - private Boolean enforceFLS; - + private FLSEnforcement mFlsEnforcement; + private Boolean sortSelectFields = true; private Boolean allRows = false; @@ -86,12 +87,25 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr private Map subselectQueryMap; private String getFieldPath(String fieldName, Schema.sObjectType relatedSObjectType){ + + //Enforcing FLS using the legacy heuristic requires resolving the full field path to its respective + //Describe result to test for isAccessible on the DescribeFieldResult + //This is computationally expensive and should be bypassed if the QueryFactory instance is not + //enforcing FLS + //Starting in Summer '22, Apex can natively enforce CRUD and FLS with User Mode Operations + //Someday, the LEGACY FLSEnforcement heuristic will be removed + if(mFlsEnforcement != FLSEnforcement.LEGACY){ + return fieldName; + } + if(!fieldName.contains('.')){ //single field Schema.SObjectField token = fflib_SObjectDescribe.getDescribe(table).getField(fieldName.toLowerCase()); - if(token == null) - throw new InvalidFieldException(fieldName,this.table); - if (enforceFLS) - fflib_SecurityUtils.checkFieldIsReadable(this.table, token); + if(token == null) { + throw new InvalidFieldException(fieldName, this.table); + } + + fflib_SecurityUtils.checkFieldIsReadable(this.table, token); + return token.getDescribe().getName(); } @@ -104,7 +118,7 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr Schema.SObjectField token = fflib_SObjectDescribe.getDescribe(lastSObjectType).getField(field.toLowerCase()); DescribeFieldResult tokenDescribe = token != null ? token.getDescribe() : null; - if (token != null && enforceFLS) { + if (token != null) { fflib_SecurityUtils.checkFieldIsReadable(lastSObjectType, token); } @@ -170,7 +184,7 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr this.table = table; fields = new Set(); order = new List(); - enforceFLS = false; + mFlsEnforcement = FLSEnforcement.NONE; } /** @@ -199,12 +213,18 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr * permission enforced. If this method is not called, the default behavior * is that FLS read permission will not be checked. * @param enforce whether to enforce field level security (read) + * @deprecated - use the setEnforceFLS overload that specifies Legacy or Native FLS enforcement **/ public fflib_QueryFactory setEnforceFLS(Boolean enforce){ - this.enforceFLS = enforce; + return setEnforceFLS(enforce ? FLSEnforcement.LEGACY : FLSEnforcement.NONE); + } + + public fflib_QueryFactory setEnforceFLS(FLSEnforcement enforcement){ + this.mFlsEnforcement = enforcement; return this; } + /** * Sets a flag to indicate that this query should have ordered * query fields in the select statement (this at a small cost to performance). @@ -243,10 +263,12 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr * @exception InvalidFieldException If the field is null {@code field}. **/ public fflib_QueryFactory selectField(Schema.SObjectField field){ - if(field == null) - throw new InvalidFieldException(null,this.table); - if (enforceFLS) + if(field == null) { + throw new InvalidFieldException(null, this.table); + } + if (mFlsEnforcement == FLSEnforcement.LEGACY) { fflib_SecurityUtils.checkFieldIsReadable(table, field); + } fields.add( getFieldTokenPath(field) ); return this; } @@ -276,10 +298,12 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr **/ public fflib_QueryFactory selectFields(Set fields){ for(Schema.SObjectField token:fields){ - if(token == null) - throw new InvalidFieldException(); - if (enforceFLS) - fflib_SecurityUtils.checkFieldIsReadable(table, token); + if(token == null) { + throw new InvalidFieldException(); + } + if (mFlsEnforcement == FLSEnforcement.LEGACY) { + fflib_SecurityUtils.checkFieldIsReadable(table, token); + } this.fields.add( getFieldTokenPath(token) ); } return this; @@ -290,11 +314,13 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr * @exception InvalidFieldException if the fields are null {@code fields}. **/ public fflib_QueryFactory selectFields(List fields){ - for(Schema.SObjectField token:fields){ - if(token == null) + for(Schema.SObjectField token : fields){ + if(token == null) { throw new InvalidFieldException(); - if (enforceFLS) - fflib_SecurityUtils.checkFieldIsReadable(table, token); + } + if (mFlsEnforcement == FLSEnforcement.LEGACY) { + fflib_SecurityUtils.checkFieldIsReadable(table, token); + } this.fields.add( getFieldTokenPath(token) ); } return this; @@ -679,7 +705,9 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr String result = 'SELECT '; //if no fields have been added, just add the Id field so that the query or subquery will not just fail if (fields.size() == 0){ - if (enforceFLS) fflib_SecurityUtils.checkFieldIsReadable(table, 'Id'); + if (mFlsEnforcement == FLSEnforcement.LEGACY){ + fflib_SecurityUtils.checkFieldIsReadable(table, 'Id'); + } result += 'Id'; }else { List fieldsToQuery = new List(fields); @@ -717,6 +745,10 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr result += ' ALL ROWS'; } + if(mFlsEnforcement == FLSEnforcement.USER_MODE){ + result += ' WITH USER_MODE'; + } + return result; } @@ -730,7 +762,7 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr .setLimit(this.limitCount) .setOffset(this.offsetCount) .setCondition(this.conditionExpression) - .setEnforceFLS(this.enforceFLS); + .setEnforceFLS(this.mFlsEnforcement); Map subqueries = this.subselectQueryMap; if(subqueries != null) { diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls index 20a56f7a883..96480172ffd 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls @@ -64,6 +64,8 @@ public abstract with sharing class fflib_SObjectSelector **/ private String m_orderBy; + private Boolean m_userMode = false; + /** * Sort the query fields in the select statement (defaults to true, at the expense of performance). * Switch this off if you need more performant queries. @@ -111,11 +113,17 @@ public abstract with sharing class fflib_SObjectSelector { this(includeFieldSetFields, true, false); } - + + public fflib_SObjectSelector(Boolean includeFieldSetFields, Boolean userMode) + { + this(includeFieldSetFields, false, false, false, true); + } + /** * Constructs the Selector * - * @param includeFieldSetFields Set to true if the Selector queries are to include Fieldset fields as well + * @param includeFieldSetFields Set to true if the Selector queries are to include Fieldset fields as well + * @deprecated - consider using userMode for native platform enforcement of CRUD and FLS **/ public fflib_SObjectSelector(Boolean includeFieldSetFields, Boolean enforceCRUD, Boolean enforceFLS) { @@ -129,15 +137,23 @@ public abstract with sharing class fflib_SObjectSelector * @param enforceCRUD Enforce CRUD security * @param enforceFLS Enforce Field Level Security * @param sortSelectFields Set to false if selecting many columns to skip sorting select fields and improve performance + * @deprecated - consider using userMode for native platform enforcement of CRUD and FLS **/ public fflib_SObjectSelector(Boolean includeFieldSetFields, Boolean enforceCRUD, Boolean enforceFLS, Boolean sortSelectFields) + { + this(includeFieldSetFields,enforceCRUD,enforceFLS,sortSelectFields,false); + } + + private fflib_SObjectSelector(Boolean includeFieldSetFields, Boolean enforceCRUD, Boolean enforceFLS, Boolean sortSelectFields, Boolean userMode) { m_includeFieldSetFields = includeFieldSetFields; m_enforceCRUD = enforceCRUD; m_enforceFLS = enforceFLS; m_sortSelectFields = sortSelectFields; + m_userMode = userMode; } + /** * Override this method to provide a list of Fieldsets that can optionally drive inclusion of additional fields in the base queries **/ @@ -179,6 +195,7 @@ public abstract with sharing class fflib_SObjectSelector /** * @description Set the selector to enforce FLS Security + * @deprecated -- consider using setUserMode to enforce native Apex User Mode Operations instead **/ public fflib_SObjectSelector enforceFLS() { @@ -211,6 +228,11 @@ public abstract with sharing class fflib_SObjectSelector return this; } + public fflib_SObjectSelector setUserMode(Boolean userMode){ + this.m_userMode = userMode; + return this; + } + /** * Returns True if this Selector instance has been instructed by the caller to include Field Set fields **/ @@ -235,6 +257,10 @@ public abstract with sharing class fflib_SObjectSelector return m_enforceCRUD; } + public Boolean isUserMode(){ + return m_userMode; + } + /** * Provides access to the builder containing the list of fields base queries are using, this is demand * created if one has not already been defined via setFieldListBuilder @@ -349,7 +375,7 @@ public abstract with sharing class fflib_SObjectSelector **/ public fflib_QueryFactory newQueryFactory() { - return newQueryFactory(m_enforceCRUD, m_enforceFLS, true); + return newQueryFactory(m_enforceCRUD, m_enforceFLS, true, m_userMode); } /** @@ -357,7 +383,7 @@ public abstract with sharing class fflib_SObjectSelector **/ public fflib_QueryFactory newQueryFactory(Boolean includeSelectorFields) { - return newQueryFactory(m_enforceCRUD, m_enforceFLS, includeSelectorFields); + return newQueryFactory(m_enforceCRUD, m_enforceFLS, includeSelectorFields, m_userMode); } /** @@ -367,9 +393,22 @@ public abstract with sharing class fflib_SObjectSelector public fflib_QueryFactory newQueryFactory(Boolean assertCRUD, Boolean enforceFLS, Boolean includeSelectorFields) { // Construct QueryFactory around the given SObject + return newQueryFactory( + assertCRUD, + enforceFLS, + includeSelectorFields, + false); + } + + public fflib_QueryFactory newQueryFactory(Boolean assertCRUD, Boolean enforceFLS, Boolean includeSelectorFields, Boolean userMode) + { + // Construct QueryFactory around the given SObject return configureQueryFactory( - new fflib_QueryFactory(getSObjectType2()), - assertCRUD, enforceFLS, includeSelectorFields); + new fflib_QueryFactory(getSObjectType2()), + assertCRUD, + enforceFLS, + includeSelectorFields, + userMode); } /** @@ -408,7 +447,8 @@ public abstract with sharing class fflib_SObjectSelector subSelectQueryFactory, m_enforceCRUD, m_enforceFLS, - includeSelectorFields); + includeSelectorFields, + m_userMode); } /** @@ -424,8 +464,8 @@ public abstract with sharing class fflib_SObjectSelector **/ public fflib_QueryFactory addQueryFactorySubselect(fflib_QueryFactory parentQueryFactory, String relationshipName, Boolean includeSelectorFields) { - fflib_QueryFactory subSelectQueryFactory = parentQueryFactory.subselectQuery(relationshipName); - return configureQueryFactory(subSelectQueryFactory, m_enforceCRUD, m_enforceFLS, includeSelectorFields); + fflib_QueryFactory subSelectQueryFactory = parentQueryFactory.subselectQuery(relationshipName); + return configureQueryFactory(subSelectQueryFactory, m_enforceCRUD, m_enforceFLS, includeSelectorFields, m_userMode); } /** @@ -439,7 +479,11 @@ public abstract with sharing class fflib_SObjectSelector /** * Configures a QueryFactory instance according to the configuration of this selector **/ - private fflib_QueryFactory configureQueryFactory(fflib_QueryFactory queryFactory, Boolean assertCRUD, Boolean enforceFLS, Boolean includeSelectorFields) + private fflib_QueryFactory configureQueryFactory(fflib_QueryFactory queryFactory, + Boolean assertCRUD, + Boolean enforceFLS, + Boolean includeSelectorFields, + Boolean userMode) { // CRUD and FLS security required? if (assertCRUD) @@ -453,7 +497,16 @@ public abstract with sharing class fflib_SObjectSelector 'Permission to access an ' + getSObjectType().getDescribe().getName() + ' denied.'); } } - queryFactory.setEnforceFLS(enforceFLS); + + fflib_QueryFactory.FLSEnforcement fls = fflib_QueryFactory.FLSEnforcement.NONE; + if(userMode){ + fls = fflib_QueryFactory.FLSEnforcement.USER_MODE; + } + else if(enforceFLS){ + fls = fflib_QueryFactory.FLSEnforcement.LEGACY; + } + + queryFactory.setEnforceFLS(fls); // Configure the QueryFactory with the Selector fields? if(includeSelectorFields) diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls b/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls index 324265def06..7beef0dd9a9 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls @@ -121,6 +121,20 @@ public virtual class fflib_SObjectUnitOfWork Database.emptyRecycleBin(objList); } } + + public virtual class UserModeDML extends SimpleDML{ + public virtual override void dmlInsert(List objList){ + Database.insert(objList,AccessLevel.USER_MODE); + } + public virtual override void dmlUpdate(List objList){ + Database.update(objList,AccessLevel.USER_MODE); + } + public virtual override void dmlDelete(List objList){ + Database.delete(objList,AccessLevel.USER_MODE); + } + } + + /** * Constructs a new UnitOfWork to support work against the given object list * From f772747037af2d63eb3df1eb15ba3a71efd4d2d3 Mon Sep 17 00:00:00 2001 From: "John M. Daniel" Date: Thu, 14 Jul 2022 16:17:36 -0400 Subject: [PATCH 26/62] bump API version to v55.0 --- .../apex-common/main/classes/fflib_Application.cls-meta.xml | 2 +- sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml | 2 +- .../main/classes/fflib_IDomainConstructor.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_IObjects.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml | 2 +- .../main/classes/fflib_ISObjectSelector.cls-meta.xml | 2 +- .../main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_ISObjects.cls-meta.xml | 2 +- sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_QueryFactory.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml | 2 +- .../main/classes/fflib_SObjectUnitOfWork.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SObjects.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_StringBuilder.cls-meta.xml | 2 +- .../apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml | 2 +- .../apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml | 2 +- .../test/classes/fflib_QueryFactoryTest.cls-meta.xml | 2 +- .../test/classes/fflib_SObjectDescribeTest.cls-meta.xml | 2 +- .../test/classes/fflib_SObjectDomainTest.cls-meta.xml | 2 +- .../test/classes/fflib_SObjectSelectorTest.cls-meta.xml | 2 +- .../test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml | 2 +- .../apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml | 2 +- .../test/classes/fflib_SecurityUtilsTest.cls-meta.xml | 2 +- .../test/classes/fflib_StringBuilderTest.cls-meta.xml | 2 +- .../test/classes/mocks/fflib_SObjectMocks.cls-meta.xml | 2 +- 28 files changed, 28 insertions(+), 28 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml index bd8e9205ef8..3b90cb4bda0 100644 --- a/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml @@ -1,4 +1,4 @@ - 54.0 + 55.0 diff --git a/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active diff --git a/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml b/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml index 40d67933d00..4b0bc9f3879 100644 --- a/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml @@ -1,5 +1,5 @@ - 54.0 + 55.0 Active From a02e8c2b455ebf16b3d4f4abed2859e846d8f694 Mon Sep 17 00:00:00 2001 From: "John M. Daniel" Date: Thu, 14 Jul 2022 16:40:26 -0400 Subject: [PATCH 27/62] bumped to API version 55.0 --- sfdx-project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sfdx-project.json b/sfdx-project.json index 6cfb92e19b7..fc789c2d464 100644 --- a/sfdx-project.json +++ b/sfdx-project.json @@ -7,5 +7,5 @@ ], "namespace": "", "sfdcLoginUrl": "https://login.salesforce.com", - "sourceApiVersion": "53.0" + "sourceApiVersion": "55.0" } \ No newline at end of file From 8cb7b0538bab827c63f962e95ddc186f6ec714e5 Mon Sep 17 00:00:00 2001 From: David Esposito Date: Tue, 25 Oct 2022 15:48:55 -0400 Subject: [PATCH 28/62] #419 -- we should continue to enforce legacy behavior both for the LEGACY option and the NONE option in order to preserve th expected behavior with regard to the normalization of the generated SOQL --- sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls index 547f069c3a6..8c63409d708 100644 --- a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls +++ b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls @@ -94,8 +94,8 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr //enforcing FLS //Starting in Summer '22, Apex can natively enforce CRUD and FLS with User Mode Operations //Someday, the LEGACY FLSEnforcement heuristic will be removed - if(mFlsEnforcement != FLSEnforcement.LEGACY){ - return fieldName; + if(mFlsEnforcement == FLSEnforcement.USER_MODE){ + return fieldName.toLowerCase(); } if(!fieldName.contains('.')){ //single field From 899c3257ac42eb1b4029950568eaa0dfc5082eef Mon Sep 17 00:00:00 2001 From: David Esposito Date: Tue, 25 Oct 2022 16:06:47 -0400 Subject: [PATCH 29/62] #419 - wasn't properly passing the passed in argument to the overload; Also, reintroduces the check for LEGACY FLS enforcement before actually asserting FLS isAccessible() (was removed in the prior commit on this feature) --- sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls | 5 +++-- .../apex-common/main/classes/fflib_SObjectSelector.cls | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls index 8c63409d708..a1df2d66538 100644 --- a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls +++ b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls @@ -103,8 +103,9 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr if(token == null) { throw new InvalidFieldException(fieldName, this.table); } - - fflib_SecurityUtils.checkFieldIsReadable(this.table, token); + if(mFlsEnforcement == FLSEnforcement.LEGACY) { + fflib_SecurityUtils.checkFieldIsReadable(this.table, token); + } return token.getDescribe().getName(); } diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls index 96480172ffd..f810b11174e 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls @@ -116,7 +116,7 @@ public abstract with sharing class fflib_SObjectSelector public fflib_SObjectSelector(Boolean includeFieldSetFields, Boolean userMode) { - this(includeFieldSetFields, false, false, false, true); + this(includeFieldSetFields, false, false, false, userMode); } /** From 8c30693581c591a696b7ad3bcf35585fd12bc651 Mon Sep 17 00:00:00 2001 From: David Esposito Date: Wed, 26 Oct 2022 11:22:48 -0400 Subject: [PATCH 30/62] #419 - adds some rudimentary unit tests to cover User Mode and System Mode (both CRUD and FLS) simple Selector use cases -- also introduces a formal SYSTEM_MODE which is subtly different than the legacy behavior in that Sharing is not enforced in SYSTEM_MODE regardless of the class declaration --- .../main/classes/fflib_QueryFactory.cls | 23 ++-- .../main/classes/fflib_SObjectSelector.cls | 56 +++++--- .../classes/fflib_SObjectSelectorTest.cls | 126 +++++++++++++++++- .../test/classes/fflib_SecurityUtilsTest.cls | 5 +- 4 files changed, 171 insertions(+), 39 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls index a1df2d66538..4748a4a9092 100644 --- a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls +++ b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls @@ -54,7 +54,7 @@ **/ public class fflib_QueryFactory { //No explicit sharing declaration - inherit from caller public enum SortOrder {ASCENDING, DESCENDING} - public enum FLSEnforcement{NONE, LEGACY, USER_MODE} + public enum FLSEnforcement{NONE, LEGACY, USER_MODE, SYSTEM_MODE} /** * This property is read-only and may not be set after instantiation. @@ -94,7 +94,7 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr //enforcing FLS //Starting in Summer '22, Apex can natively enforce CRUD and FLS with User Mode Operations //Someday, the LEGACY FLSEnforcement heuristic will be removed - if(mFlsEnforcement == FLSEnforcement.USER_MODE){ + if(mFlsEnforcement == FLSEnforcement.USER_MODE || mFlsEnforcement == FLSEnforcement.SYSTEM_MODE){ return fieldName.toLowerCase(); } @@ -119,7 +119,7 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr Schema.SObjectField token = fflib_SObjectDescribe.getDescribe(lastSObjectType).getField(field.toLowerCase()); DescribeFieldResult tokenDescribe = token != null ? token.getDescribe() : null; - if (token != null) { + if (token != null && mFlsEnforcement == FLSEnforcement.LEGACY) { fflib_SecurityUtils.checkFieldIsReadable(lastSObjectType, token); } @@ -726,8 +726,17 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr } } result += ' FROM ' + (relationship != null ? relationship.getRelationshipName() : table.getDescribe().getName()); - if(conditionExpression != null) - result += ' WHERE '+conditionExpression; + + if(conditionExpression != null) { + result += ' WHERE ' + conditionExpression; + } + + if(mFlsEnforcement == FLSEnforcement.USER_MODE){ + result += ' WITH USER_MODE'; + } + else if(mFlsEnforcement == FLSEnforcement.SYSTEM_MODE){ + result += ' WITH SYSTEM_MODE'; + } if(order.size() > 0){ result += ' ORDER BY '; @@ -746,10 +755,6 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr result += ' ALL ROWS'; } - if(mFlsEnforcement == FLSEnforcement.USER_MODE){ - result += ' WITH USER_MODE'; - } - return result; } diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls index f810b11174e..d6cd19c7e13 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls @@ -30,6 +30,8 @@ public abstract with sharing class fflib_SObjectSelector implements fflib_ISObjectSelector { + public enum DataAccess{LEGACY, USER_MODE, SYSTEM_MODE} + /** * Indicates whether the sObject has the currency ISO code field for organisations which have multi-currency * enabled. @@ -64,7 +66,7 @@ public abstract with sharing class fflib_SObjectSelector **/ private String m_orderBy; - private Boolean m_userMode = false; + private DataAccess m_dataAccess = DataAccess.LEGACY; /** * Sort the query fields in the select statement (defaults to true, at the expense of performance). @@ -114,9 +116,9 @@ public abstract with sharing class fflib_SObjectSelector this(includeFieldSetFields, true, false); } - public fflib_SObjectSelector(Boolean includeFieldSetFields, Boolean userMode) + public fflib_SObjectSelector(Boolean includeFieldSetFields, DataAccess dataAccess) { - this(includeFieldSetFields, false, false, false, userMode); + this(includeFieldSetFields, false, false, false, dataAccess); } /** @@ -137,20 +139,20 @@ public abstract with sharing class fflib_SObjectSelector * @param enforceCRUD Enforce CRUD security * @param enforceFLS Enforce Field Level Security * @param sortSelectFields Set to false if selecting many columns to skip sorting select fields and improve performance - * @deprecated - consider using userMode for native platform enforcement of CRUD and FLS + * @deprecated - consider using dataAccess for native platform enforcement of CRUD and FLS **/ public fflib_SObjectSelector(Boolean includeFieldSetFields, Boolean enforceCRUD, Boolean enforceFLS, Boolean sortSelectFields) { - this(includeFieldSetFields,enforceCRUD,enforceFLS,sortSelectFields,false); + this(includeFieldSetFields,enforceCRUD,enforceFLS,sortSelectFields,DataAccess.LEGACY); } - private fflib_SObjectSelector(Boolean includeFieldSetFields, Boolean enforceCRUD, Boolean enforceFLS, Boolean sortSelectFields, Boolean userMode) + private fflib_SObjectSelector(Boolean includeFieldSetFields, Boolean enforceCRUD, Boolean enforceFLS, Boolean sortSelectFields, DataAccess dataAccess) { m_includeFieldSetFields = includeFieldSetFields; m_enforceCRUD = enforceCRUD; m_enforceFLS = enforceFLS; m_sortSelectFields = sortSelectFields; - m_userMode = userMode; + m_DataAccess = dataAccess; } @@ -195,7 +197,7 @@ public abstract with sharing class fflib_SObjectSelector /** * @description Set the selector to enforce FLS Security - * @deprecated -- consider using setUserMode to enforce native Apex User Mode Operations instead + * @deprecated -- consider using setDataAccess to enforce native Apex User Mode Operations instead **/ public fflib_SObjectSelector enforceFLS() { @@ -228,8 +230,15 @@ public abstract with sharing class fflib_SObjectSelector return this; } - public fflib_SObjectSelector setUserMode(Boolean userMode){ - this.m_userMode = userMode; + public fflib_SObjectSelector setDataAccess(DataAccess access){ + this.m_dataAccess = access; + + //You can't mix and match the legacy enforceFls and assertCRUD with the SYSTEM_MODE or USER_MODE + if(this.m_dataAccess != DataAccess.LEGACY){ + ignoreCRUD(); + m_enforceFLS = false; + } + return this; } @@ -257,8 +266,8 @@ public abstract with sharing class fflib_SObjectSelector return m_enforceCRUD; } - public Boolean isUserMode(){ - return m_userMode; + public DataAccess getDataAccess(){ + return m_dataAccess; } /** @@ -375,7 +384,7 @@ public abstract with sharing class fflib_SObjectSelector **/ public fflib_QueryFactory newQueryFactory() { - return newQueryFactory(m_enforceCRUD, m_enforceFLS, true, m_userMode); + return newQueryFactory(m_enforceCRUD, m_enforceFLS, true, m_DataAccess); } /** @@ -383,7 +392,7 @@ public abstract with sharing class fflib_SObjectSelector **/ public fflib_QueryFactory newQueryFactory(Boolean includeSelectorFields) { - return newQueryFactory(m_enforceCRUD, m_enforceFLS, includeSelectorFields, m_userMode); + return newQueryFactory(m_enforceCRUD, m_enforceFLS, includeSelectorFields, m_DataAccess); } /** @@ -397,10 +406,10 @@ public abstract with sharing class fflib_SObjectSelector assertCRUD, enforceFLS, includeSelectorFields, - false); + DataAccess.LEGACY); } - public fflib_QueryFactory newQueryFactory(Boolean assertCRUD, Boolean enforceFLS, Boolean includeSelectorFields, Boolean userMode) + private fflib_QueryFactory newQueryFactory(Boolean assertCRUD, Boolean enforceFLS, Boolean includeSelectorFields, DataAccess dataAccess) { // Construct QueryFactory around the given SObject return configureQueryFactory( @@ -408,7 +417,7 @@ public abstract with sharing class fflib_SObjectSelector assertCRUD, enforceFLS, includeSelectorFields, - userMode); + dataAccess); } /** @@ -448,7 +457,7 @@ public abstract with sharing class fflib_SObjectSelector m_enforceCRUD, m_enforceFLS, includeSelectorFields, - m_userMode); + m_dataAccess); } /** @@ -465,7 +474,7 @@ public abstract with sharing class fflib_SObjectSelector public fflib_QueryFactory addQueryFactorySubselect(fflib_QueryFactory parentQueryFactory, String relationshipName, Boolean includeSelectorFields) { fflib_QueryFactory subSelectQueryFactory = parentQueryFactory.subselectQuery(relationshipName); - return configureQueryFactory(subSelectQueryFactory, m_enforceCRUD, m_enforceFLS, includeSelectorFields, m_userMode); + return configureQueryFactory(subSelectQueryFactory, m_enforceCRUD, m_enforceFLS, includeSelectorFields, m_dataAccess); } /** @@ -483,9 +492,9 @@ public abstract with sharing class fflib_SObjectSelector Boolean assertCRUD, Boolean enforceFLS, Boolean includeSelectorFields, - Boolean userMode) + DataAccess access) { - // CRUD and FLS security required? + // Legacy CRUD enforcement required? if (assertCRUD) { try { @@ -499,9 +508,12 @@ public abstract with sharing class fflib_SObjectSelector } fflib_QueryFactory.FLSEnforcement fls = fflib_QueryFactory.FLSEnforcement.NONE; - if(userMode){ + if(access == DataAccess.USER_MODE){ fls = fflib_QueryFactory.FLSEnforcement.USER_MODE; } + else if(access == DataAccess.SYSTEM_MODE){ + fls = fflib_QueryFactory.FLSEnforcement.SYSTEM_MODE; + } else if(enforceFLS){ fls = fflib_QueryFactory.FLSEnforcement.LEGACY; } diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls index c982d9144d4..8f50eda40b0 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls @@ -27,6 +27,10 @@ @IsTest private with sharing class fflib_SObjectSelectorTest { + @TestSetup + static void testSetup(){ + fflib_SecurityUtilsTest.testSetup(); + } static testMethod void testGetSObjectName() { @@ -177,6 +181,7 @@ private with sharing class fflib_SObjectSelectorTest System.assertEquals(false, selector.isEnforcingFLS()); System.assertEquals(true, selector.isEnforcingCRUD()); System.assertEquals(false, selector.isIncludeFieldSetFields()); + System.assertEquals(fflib_SObjectSelector.DataAccess.LEGACY, selector.getDataAccess()); System.assertEquals('Account', selector.getSObjectName()); System.assertEquals(Account.SObjectType, selector.getSObjectType2()); @@ -367,14 +372,72 @@ private with sharing class fflib_SObjectSelectorTest } - private static void assertEqualsSelectFields(String expectedSelectFields, String actualSelectFields) - { - Set expected = new Set(expectedSelectFields.deleteWhiteSpace().split(',')); - Set actual = new Set(actualSelectFields.deleteWhiteSpace().split(',')); + @IsTest + static void toSoql_When_UserModeAndUserCannnotReadObject_Expect_QueryException(){ + AccessLevelOpportunitySelector sel = new AccessLevelOpportunitySelector(); + + User u = getLimitedReadOnlyUser(); + System.runAs(u){ + try{ + System.debug(sel.newQueryFactory().toSOQL()); + sel.selectSObjectsById(new Set{fflib_IDGenerator.generate(Opportunity.SObjectType)}); + Assert.fail('Expected a QueryException due to read only user not having access to Opportunity'); + } + catch(QueryException qe){ + //If you don't have Read access to the Lead object, the Name field is inaccessible -- so that's what we're verifying + Assert.isNotNull(qe.getInaccessibleFields(),'Expected a Map of inaccessible objects; got null'); + Set inaccessibleFields = qe.getInaccessibleFields().get('Opportunity'); + Assert.isNotNull(inaccessibleFields,'Expected a Set of inaccessible fields on the Opportunity object; got null'); + Assert.isTrue(inaccessibleFields.contains('Name'),'Expected Name to be an inaccessible field on Opportunity'); + } + } + } - System.assertEquals(expected, actual); + @IsTest + static void toSoql_When_SystemModeAndUserCannnotReadObject_Expect_Success(){ + AccessLevelOpportunitySelector sel = new AccessLevelOpportunitySelector(fflib_SObjectSelector.DataAccess.SYSTEM_MODE); + + User u = getLimitedReadOnlyUser(); + System.runAs(u){ + sel.selectSObjectsById(new Set{fflib_IDGenerator.generate(Opportunity.SObjectType)}); + } } - + + @IsTest + static void toSoql_When_UserModeAndUserCannnotReadField_Expect_QueryException(){ + AccessLevelAccountSelector sel = new AccessLevelAccountSelector(); + + //Account has Read access by the limited read only user but no FLS access + User u = getLimitedReadOnlyUser(); + System.runAs(u){ + try{ + System.debug(sel.newQueryFactory().toSOQL()); + sel.selectSObjectsById(new Set{fflib_IDGenerator.generate(Account.SObjectType)}); + Assert.fail('Expected a QueryException due to read only user not having access to AnnualRevenue'); + } + catch(QueryException qe){ + //If you don't have Read access to the Lead object, the Name field is inaccessible -- so that's what we're verifying + Assert.isNotNull(qe.getInaccessibleFields(),'Expected a Map of inaccessible objects; got null'); + Set inaccessibleFields = qe.getInaccessibleFields().get('Account'); + Assert.isNotNull(inaccessibleFields,'Expected a Set of inaccessible fields on the Account object; got null'); + Assert.isFalse(inaccessibleFields.contains('Name'),'Expected Name to be an accessible field on Account'); + Assert.isTrue(inaccessibleFields.contains('AnnualRevenue'),'Expected AnnualRevenue to be an inaccessible field on Account'); + } + } + } + + @IsTest + static void toSoql_When_SystemModeAndUserCannnotReadField_Expect_Success(){ + AccessLevelAccountSelector sel = new AccessLevelAccountSelector(fflib_SObjectSelector.DataAccess.SYSTEM_MODE); + + //Account has Read access by the limited read only user but no FLS access + User u = getLimitedReadOnlyUser(); + System.runAs(u){ + sel.selectSObjectsById(new Set{fflib_IDGenerator.generate(Account.SObjectType)}); + } + } + + private class Testfflib_SObjectSelector extends fflib_SObjectSelector { public Testfflib_SObjectSelector() @@ -455,6 +518,53 @@ private with sharing class fflib_SObjectSelectorTest } } + private class AccessLevelOpportunitySelector extends fflib_SObjectSelector{ + public AccessLevelOpportunitySelector(){ + this(DataAccess.USER_MODE); + } + + public AccessLevelOpportunitySelector(DataAccess access){ + super(false, access); + } + + public Schema.SObjectType getSObjectType(){ + return Opportunity.sObjectType; + } + + public List getSObjectFieldList(){ + return new List { + Opportunity.Name, + Opportunity.Id, + Opportunity.Amount, + Opportunity.CloseDate + }; + } + } + + private class AccessLevelAccountSelector extends fflib_SObjectSelector{ + public AccessLevelAccountSelector(){ + this(DataAccess.USER_MODE); + } + + public AccessLevelAccountSelector(DataAccess access){ + super(false, access); + } + + public Schema.SObjectType getSObjectType(){ + return Account.sObjectType; + } + + public List getSObjectFieldList(){ + return new List { + Account.Name, + Account.Id, + Account.AnnualRevenue, + Account.AccountNumber + }; + } + } + + /** * Create test user **/ @@ -476,6 +586,10 @@ private with sharing class fflib_SObjectSelectorTest return testUser; } + private static User getLimitedReadOnlyUser(){ + return fflib_SecurityUtilsTest.setupTestUser('Read Only'); + } + @isTest static void testPolymorphicSelectWithRelatedType() { //Given diff --git a/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls b/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls index dea962a7c67..3e7e4c93a15 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls @@ -24,10 +24,10 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **/ -@isTest +@isTest @TestVisible private class fflib_SecurityUtilsTest { - @TestSetup + @TestSetup @TestVisible static void testSetup() { // #315 Create a Permission Set that grants "Read" access to Account, Contact and Lead. We will use this in // Spring '21 orgs that lack the "Read Only" Profile. See: @@ -78,6 +78,7 @@ private class fflib_SecurityUtilsTest { ); } + @TestVisible static User setupTestUser(String profileName){ Profile p; Boolean applyReadOnlyPermissionSet = false; From bd945a37e9d7cf52ce7543d1714b7d88eda0c784 Mon Sep 17 00:00:00 2001 From: David Esposito Date: Wed, 26 Oct 2022 12:45:45 -0400 Subject: [PATCH 31/62] #427 - deploys sample code and runs tests after the initial test run succeeds --- .github/workflows/deploy.and.test.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/deploy.and.test.yml b/.github/workflows/deploy.and.test.yml index 394bf826646..c0ca0cce2c9 100644 --- a/.github/workflows/deploy.and.test.yml +++ b/.github/workflows/deploy.and.test.yml @@ -25,6 +25,10 @@ jobs: - run: sfdx shane:github:src:install -c -g apex-enterprise-patterns -r fflib-apex-mocks -p sfdx-source/apex-mocks - run: sfdx force:source:push - run: sfdx force:apex:test:run -w 5 + #Intentionally install the Sample Code after the core AEP Commons test pass succeeds so that we don't deploy anything in Sample Code + #that could mask a test failure. A much more involved solution would've been to do a workflow_dispatch to the samplecode project. + - run: sfdx shane:github:src:install -c -g apex-enterprise-patterns -r fflib-apex-mocks-samplecode -p sfdx-source/apex-common-samplecode + - run: sfdx force:apex:test:run -w 5 - name: Destroy scratch org run: sfdx force:org:delete -p if: always() From 3d6fc564fff70979cab82fe4f6db0b961149c74b Mon Sep 17 00:00:00 2001 From: David Esposito Date: Wed, 26 Oct 2022 12:48:46 -0400 Subject: [PATCH 32/62] #427 - deploys sample code and runs tests after the initial test run succeeds --- .github/workflows/deploy.and.test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.and.test.yml b/.github/workflows/deploy.and.test.yml index c0ca0cce2c9..6ee5551ad39 100644 --- a/.github/workflows/deploy.and.test.yml +++ b/.github/workflows/deploy.and.test.yml @@ -27,7 +27,7 @@ jobs: - run: sfdx force:apex:test:run -w 5 #Intentionally install the Sample Code after the core AEP Commons test pass succeeds so that we don't deploy anything in Sample Code #that could mask a test failure. A much more involved solution would've been to do a workflow_dispatch to the samplecode project. - - run: sfdx shane:github:src:install -c -g apex-enterprise-patterns -r fflib-apex-mocks-samplecode -p sfdx-source/apex-common-samplecode + - run: sfdx shane:github:src:install -c -g apex-enterprise-patterns -r fflib-apex-samplecode -p sfdx-source/apex-common-samplecode - run: sfdx force:apex:test:run -w 5 - name: Destroy scratch org run: sfdx force:org:delete -p From 332c50e5b38c925283451e5eb3e3a84d8a559678 Mon Sep 17 00:00:00 2001 From: David Esposito Date: Wed, 26 Oct 2022 12:49:34 -0400 Subject: [PATCH 33/62] #427 - deploys sample code and runs tests after the initial test run succeeds --- .github/workflows/deploy.and.test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.and.test.yml b/.github/workflows/deploy.and.test.yml index 6ee5551ad39..9372c5f5a25 100644 --- a/.github/workflows/deploy.and.test.yml +++ b/.github/workflows/deploy.and.test.yml @@ -27,7 +27,7 @@ jobs: - run: sfdx force:apex:test:run -w 5 #Intentionally install the Sample Code after the core AEP Commons test pass succeeds so that we don't deploy anything in Sample Code #that could mask a test failure. A much more involved solution would've been to do a workflow_dispatch to the samplecode project. - - run: sfdx shane:github:src:install -c -g apex-enterprise-patterns -r fflib-apex-samplecode -p sfdx-source/apex-common-samplecode + - run: sfdx shane:github:src:install -c -g apex-enterprise-patterns -r fflib-apex-common-samplecode -p sfdx-source/apex-common-samplecode - run: sfdx force:apex:test:run -w 5 - name: Destroy scratch org run: sfdx force:org:delete -p From fbe6df4ac670c914a6d43481bdb465276acfabdf Mon Sep 17 00:00:00 2001 From: "John M. Daniel" Date: Tue, 29 Nov 2022 09:41:09 -0500 Subject: [PATCH 34/62] updated Deploy To Salesforce Link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2c06119f3f1..557cec504df 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ FFLib Apex Common **Dependencies:** Must deploy [ApexMocks](https://github.com/apex-enterprise-patterns/fflib-apex-mocks) before deploying this library - + Deploy to Salesforce From 13414810a34f6c2d3ffb0044e7a8c73091cf74ff Mon Sep 17 00:00:00 2001 From: David Esposito Date: Wed, 30 Nov 2022 15:20:24 -0500 Subject: [PATCH 35/62] #419 - fixes bug with generation of SOQL when creating Selectors with Child Queries; fixes bug with (lack of) field deduplication when mixing SObjectField tokens and String field paths by normalizing the list of fields as downcased field paths; DRYed up the manipulation of the fields collection and looping over collections due to the dual overloads for both Set and List argument types; added test coverage for all of these changes --- .../main/classes/fflib_QueryFactory.cls | 84 +++++++++++-------- .../classes/fflib_SObjectSelectorTest.cls | 61 ++++++++++++++ 2 files changed, 108 insertions(+), 37 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls index 4748a4a9092..3ab71b09401 100644 --- a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls +++ b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls @@ -95,7 +95,7 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr //Starting in Summer '22, Apex can natively enforce CRUD and FLS with User Mode Operations //Someday, the LEGACY FLSEnforcement heuristic will be removed if(mFlsEnforcement == FLSEnforcement.USER_MODE || mFlsEnforcement == FLSEnforcement.SYSTEM_MODE){ - return fieldName.toLowerCase(); + return fieldName; } if(!fieldName.contains('.')){ //single field @@ -161,7 +161,7 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr if(field == null){ throw new InvalidFieldException('Invalid field: null'); } - return field.getDescribe().getName(); + return field.getDescribe().getLocalName(); } /** @@ -241,9 +241,8 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr * Selecting fields is idempotent, if this field is already selected calling this method will have no additional impact. * @param fieldName the API name of the field to add to the query's SELECT clause. **/ - public fflib_QueryFactory selectField(String fieldName){ - fields.add( getFieldPath(fieldName, null) ); - return this; + public fflib_QueryFactory selectField(String fieldName){ + return selectFields(new Set{fieldName}); } /** @@ -252,8 +251,8 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr * @param fieldName the API name of the field to add to the query's SELECT clause. * @param relatedSObjectType the related sObjectType to resolve polymorphic object fields. **/ - public fflib_QueryFactory selectField(String fieldName, Schema.sOBjectType relatedObjectType) { - fields.add(getFieldPath(fieldName, relatedObjectType)); + public fflib_QueryFactory selectField(String fieldName, Schema.sObjectType relatedObjectType) { + addField(getFieldPath(fieldName, relatedObjectType)); return this; } @@ -264,65 +263,59 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr * @exception InvalidFieldException If the field is null {@code field}. **/ public fflib_QueryFactory selectField(Schema.SObjectField field){ - if(field == null) { - throw new InvalidFieldException(null, this.table); - } - if (mFlsEnforcement == FLSEnforcement.LEGACY) { - fflib_SecurityUtils.checkFieldIsReadable(table, field); - } - fields.add( getFieldTokenPath(field) ); - return this; + return selectFields(new Set{field}); } /** * Selects multiple fields. This acts the same as calling {@link #selectField(String)} multiple times. * @param fieldNames the Set of field API names to select. **/ public fflib_QueryFactory selectFields(Set fieldNames){ - for(String fieldName:fieldNames){ - fields.add( getFieldPath(fieldName) ); - } - return this; + return selectStringField(fieldNames.iterator()); } /** * Selects multiple fields. This acts the same as calling {@link #selectField(String)} multiple times. * @param fieldNames the List of field API names to select. **/ public fflib_QueryFactory selectFields(List fieldNames){ - for(String fieldName:fieldNames) - fields.add( getFieldPath(fieldName) ); + return selectStringField(fieldNames.iterator()); + } + + private fflib_QueryFactory selectStringField(Iterator iter){ + while( iter.hasNext() ) { + addField(getFieldPath(iter.next())); + } return this; } + /** * Selects multiple fields. This acts the same as calling {@link #selectField(Schema.SObjectField)} multiple times. * @param fields the set of {@link Schema.SObjectField}s to select. * @exception InvalidFieldException if the fields are null {@code fields}. **/ public fflib_QueryFactory selectFields(Set fields){ - for(Schema.SObjectField token:fields){ - if(token == null) { - throw new InvalidFieldException(); - } - if (mFlsEnforcement == FLSEnforcement.LEGACY) { - fflib_SecurityUtils.checkFieldIsReadable(table, token); - } - this.fields.add( getFieldTokenPath(token) ); - } - return this; + return selectSObjectField(fields.iterator()); } + /** * Selects multiple fields. This acts the same as calling {@link #selectField(Schema.SObjectField)} multiple times. * @param fields the set of {@link Schema.SObjectField}s to select. * @exception InvalidFieldException if the fields are null {@code fields}. **/ - public fflib_QueryFactory selectFields(List fields){ - for(Schema.SObjectField token : fields){ + public fflib_QueryFactory selectFields(List fields) { + return selectSObjectField(fields.iterator()); + } + + private fflib_QueryFactory selectSObjectField(Iterator iter){ + + while( iter.hasNext() ){ + Schema.SObjectField token = iter.next(); if(token == null) { throw new InvalidFieldException(); } if (mFlsEnforcement == FLSEnforcement.LEGACY) { fflib_SecurityUtils.checkFieldIsReadable(table, token); } - this.fields.add( getFieldTokenPath(token) ); + addField( getFieldTokenPath(token) ); } return this; } @@ -344,10 +337,26 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr for(Schema.FieldSetMember field: fieldSet.getFields()){ if(!allowCrossObject && field.getFieldPath().contains('.')) throw new InvalidFieldSetException('Cross-object fields not allowed and field "'+field.getFieldPath()+'"" is a cross-object field.'); - fields.add( getFieldPath(field.getFieldPath()) ); + addField( getFieldPath(field.getFieldPath()) ); } return this; } + + private void addField(String fieldPath){ + /** With the introduction of SYSTEM_MODE and USER_MODE, it no longer became necessary to + * use DescribeFieldResult methods to resolve a selected field back to its canonical case-preserving + * field definition. The consequence is that duplicate fields could be introduced into the SELECT + * clause if, for instance, the Apex code called "selectField('annualrevenue')" but that same AnnualRevenue + * field were included via a Field Set and the FieldSetMember.getFieldPath() returns "AnnualRevenue" + * So, in the cases where we're using USER_MODE or SYSTEM_MODE, we need to downcase all of the fields in the Set + */ + if(mFlsEnforcement == FLSEnforcement.SYSTEM_MODE || mFlsEnforcement == FLSEnforcement.USER_MODE){ + fieldPath = fieldPath.toLowerCase(); + } + + this.fields.add(fieldPath); + } + /** * @param conditionExpression Sets the WHERE clause to the string provided. Do not include the "WHERE". **/ @@ -731,10 +740,11 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr result += ' WHERE ' + conditionExpression; } - if(mFlsEnforcement == FLSEnforcement.USER_MODE){ + //Subselects can't specify USER_MODE or SYSTEM_MODE -- only the top-level query can do so + if(relationship == null && mFlsEnforcement == FLSEnforcement.USER_MODE){ result += ' WITH USER_MODE'; } - else if(mFlsEnforcement == FLSEnforcement.SYSTEM_MODE){ + else if(relationship == null && mFlsEnforcement == FLSEnforcement.SYSTEM_MODE){ result += ' WITH SYSTEM_MODE'; } diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls index 8f50eda40b0..6c9a660a1d8 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls @@ -437,6 +437,30 @@ private with sharing class fflib_SObjectSelectorTest } } + @IsTest + static void toSoql_When_SystemModeAndParentRelationshipAndDuplicateFields_Expect_WellFormedSOQL(){ + AccessLevelOpportunitySelector sel = new AccessLevelOpportunitySelector(fflib_SObjectSelector.DataAccess.SYSTEM_MODE); + + String soql = sel.createSelectAllWithAccountSOQL(); + + String expected = 'SELECT name, id, amount, closedate, account\\.name, account\\.billingpostalcode(.*)FROM Opportunity WITH SYSTEM_MODE ORDER BY Name ASC NULLS FIRST '; + Pattern soqlPattern = Pattern.compile(expected); + Matcher soqlMatcher = soqlPattern.matcher(soql); + System.assert(soqlMatcher.matches(),'Expected: ' + expected + ' Actual:' + soql); + } + + @IsTest + static void toSoql_When_SystemModeAndChildRelationship_Expect_WellFormedSOQL(){ + AccessLevelAccountSelector sel = new AccessLevelAccountSelector(fflib_SObjectSelector.DataAccess.SYSTEM_MODE); + + String soql = sel.createSelectAccountWithOpportunitiesSOQL(); + + String expected = 'SELECT name, id, annualrevenue, accountnumber,(.*)\\(SELECT name, id, amount, closedate FROM Opportunities ORDER BY Name ASC NULLS FIRST \\) FROM Account WITH SYSTEM_MODE ORDER BY Name ASC NULLS FIRST '; + Pattern soqlPattern = Pattern.compile(expected); + Matcher soqlMatcher = soqlPattern.matcher(soql); + System.assert(soqlMatcher.matches(),'Expected: ' + expected + ' Actual:' + soql); + } + private class Testfflib_SObjectSelector extends fflib_SObjectSelector { @@ -539,6 +563,28 @@ private with sharing class fflib_SObjectSelectorTest Opportunity.CloseDate }; } + + @TestVisible + private String createSelectAllWithAccountSOQL(){ + fflib_QueryFactory qf = newQueryFactory(); + + qf.selectField('AMOUNT'); //Duplicate (as String) + qf.selectField('amount'); //Duplicate (as String) + qf.selectField(Opportunity.Amount); //Duplicate (as SObjectField) + + //Parent Relationship + qf.selectFields(new Set{ + 'Account.Name', + 'Account.BillingPostalCode' + }); + qf.selectField('Account.BILLINGPOSTALCODE'); //Duplicate field (as String) + + return qf.toSOQL(); + } + + public List selectAllWithAccount(){ + return Database.query(createSelectAllWithAccountSOQL()); + } } private class AccessLevelAccountSelector extends fflib_SObjectSelector{ @@ -562,6 +608,21 @@ private with sharing class fflib_SObjectSelectorTest Account.AccountNumber }; } + + @TestVisible + private String createSelectAccountWithOpportunitiesSOQL(){ + AccessLevelOpportunitySelector oSel = new AccessLevelOpportunitySelector(getDataAccess()); + + fflib_QueryFactory qf = newQueryFactory(); + + oSel.addQueryFactorySubselect(qf); + + return qf.toSOQL(); + } + + public List selectAccountWithOpportunities(){ + return Database.query(createSelectAccountWithOpportunitiesSOQL()); + } } From e411f7c4e4c5ad5b3dbaf649102be65524bd8151 Mon Sep 17 00:00:00 2001 From: David Esposito Date: Tue, 20 Dec 2022 08:59:46 -0500 Subject: [PATCH 36/62] #419 - whitespace and test method naming convention tchanges per requests on the PR --- .../main/classes/fflib_QueryFactory.cls | 10 +++++----- .../main/classes/fflib_SObjectSelector.cls | 14 +++++++------- .../test/classes/fflib_SObjectSelectorTest.cls | 12 ++++++------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls index 3ab71b09401..5d9b5db087d 100644 --- a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls +++ b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls @@ -289,23 +289,23 @@ public class fflib_QueryFactory { //No explicit sharing declaration - inherit fr /** * Selects multiple fields. This acts the same as calling {@link #selectField(Schema.SObjectField)} multiple times. - * @param fields the set of {@link Schema.SObjectField}s to select. + * @param fields the Set of {@link Schema.SObjectField}s to select. * @exception InvalidFieldException if the fields are null {@code fields}. **/ public fflib_QueryFactory selectFields(Set fields){ - return selectSObjectField(fields.iterator()); + return selectSObjectFields(fields.iterator()); } /** * Selects multiple fields. This acts the same as calling {@link #selectField(Schema.SObjectField)} multiple times. - * @param fields the set of {@link Schema.SObjectField}s to select. + * @param fields the List of {@link Schema.SObjectField}s to select. * @exception InvalidFieldException if the fields are null {@code fields}. **/ public fflib_QueryFactory selectFields(List fields) { - return selectSObjectField(fields.iterator()); + return selectSObjectFields(fields.iterator()); } - private fflib_QueryFactory selectSObjectField(Iterator iter){ + private fflib_QueryFactory selectSObjectFields(Iterator iter){ while( iter.hasNext() ){ Schema.SObjectField token = iter.next(); diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls index d6cd19c7e13..b20011a0507 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls @@ -401,9 +401,9 @@ public abstract with sharing class fflib_SObjectSelector **/ public fflib_QueryFactory newQueryFactory(Boolean assertCRUD, Boolean enforceFLS, Boolean includeSelectorFields) { - // Construct QueryFactory around the given SObject + // Construct QueryFactory around the given SObject return newQueryFactory( - assertCRUD, + assertCRUD, enforceFLS, includeSelectorFields, DataAccess.LEGACY); @@ -449,15 +449,15 @@ public abstract with sharing class fflib_SObjectSelector * Adds a subselect QueryFactory based on this selector to the given QueryFactor **/ public fflib_QueryFactory addQueryFactorySubselect(fflib_QueryFactory parentQueryFactory, Boolean includeSelectorFields) - { - fflib_QueryFactory subSelectQueryFactory = + { + fflib_QueryFactory subSelectQueryFactory = parentQueryFactory.subselectQuery(getSObjectType2()); return configureQueryFactory( - subSelectQueryFactory, - m_enforceCRUD, + subSelectQueryFactory, + m_enforceCRUD, m_enforceFLS, includeSelectorFields, - m_dataAccess); + m_dataAccess); } /** diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls index 6c9a660a1d8..f00c0818764 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls @@ -373,7 +373,7 @@ private with sharing class fflib_SObjectSelectorTest } @IsTest - static void toSoql_When_UserModeAndUserCannnotReadObject_Expect_QueryException(){ + static void toSOQL_When_UserModeAndUserCannnotReadObject_Expect_QueryException(){ AccessLevelOpportunitySelector sel = new AccessLevelOpportunitySelector(); User u = getLimitedReadOnlyUser(); @@ -394,7 +394,7 @@ private with sharing class fflib_SObjectSelectorTest } @IsTest - static void toSoql_When_SystemModeAndUserCannnotReadObject_Expect_Success(){ + static void toSOQL_When_SystemModeAndUserCannnotReadObject_Expect_Success(){ AccessLevelOpportunitySelector sel = new AccessLevelOpportunitySelector(fflib_SObjectSelector.DataAccess.SYSTEM_MODE); User u = getLimitedReadOnlyUser(); @@ -404,7 +404,7 @@ private with sharing class fflib_SObjectSelectorTest } @IsTest - static void toSoql_When_UserModeAndUserCannnotReadField_Expect_QueryException(){ + static void toSOQL_When_UserModeAndUserCannnotReadField_Expect_QueryException(){ AccessLevelAccountSelector sel = new AccessLevelAccountSelector(); //Account has Read access by the limited read only user but no FLS access @@ -427,7 +427,7 @@ private with sharing class fflib_SObjectSelectorTest } @IsTest - static void toSoql_When_SystemModeAndUserCannnotReadField_Expect_Success(){ + static void toSOQL_When_SystemModeAndUserCannnotReadField_Expect_Success(){ AccessLevelAccountSelector sel = new AccessLevelAccountSelector(fflib_SObjectSelector.DataAccess.SYSTEM_MODE); //Account has Read access by the limited read only user but no FLS access @@ -438,7 +438,7 @@ private with sharing class fflib_SObjectSelectorTest } @IsTest - static void toSoql_When_SystemModeAndParentRelationshipAndDuplicateFields_Expect_WellFormedSOQL(){ + static void toSOQL_When_SystemModeAndParentRelationshipAndDuplicateFields_Expect_WellFormedSOQL(){ AccessLevelOpportunitySelector sel = new AccessLevelOpportunitySelector(fflib_SObjectSelector.DataAccess.SYSTEM_MODE); String soql = sel.createSelectAllWithAccountSOQL(); @@ -450,7 +450,7 @@ private with sharing class fflib_SObjectSelectorTest } @IsTest - static void toSoql_When_SystemModeAndChildRelationship_Expect_WellFormedSOQL(){ + static void toSOQL_When_SystemModeAndChildRelationship_Expect_WellFormedSOQL(){ AccessLevelAccountSelector sel = new AccessLevelAccountSelector(fflib_SObjectSelector.DataAccess.SYSTEM_MODE); String soql = sel.createSelectAccountWithOpportunitiesSOQL(); From 081a0144ca0b58e685ae25079e43c7cc3f5e5b92 Mon Sep 17 00:00:00 2001 From: David Esposito Date: Tue, 20 Dec 2022 09:50:22 -0500 Subject: [PATCH 37/62] #419 - updates README to announce new feature and adds an overload of the polymorphic Selector test to make sure it still produces valid SOQL in SYSTEM_MODE --- README.md | 2 +- .../classes/fflib_SObjectSelectorTest.cls | 34 ++++++++++++++++--- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2c06119f3f1..337cd8a9736 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,11 @@ FFLib Apex Common Updates ======= +- **December 2022**, **IMPORTANT CHANGE** - Support for native Apex User Mode was added to the library per the discussion over on #419. For new projects, the old "enforceCRUD" and "enforceFLS" flags on `fflib_SObjectSelector` should be considered deprecated and the constructors that take `dataAccess` arguments should be used instead - **April 2020**, **IMPORTANT CHANGE**, the directory format of this project repo was converted to [Salesforce DX Source Format](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_source_file_format.htm). While the GIT commit history was maintained, it is not visible on GitHub. If you need to see the history, either clone the repo and execute `git log --follow` from the command line or refer to this [tag](https://github.com/apex-enterprise-patterns/fflib-apex-common/tree/metadata-format-prior-to-dx-source-format-conversion) of the codebase prior to conversion. - **September 2014**, **IMPORTANT CHANGE**, changes applied to support Dreamforce 2014 advanced presentation, library now provides Application factories for major layers and support for ApexMocks. More details to follow! As a result [ApexMocks](https://github.com/apex-enterprise-patterns/fflib-apex-mocks) must be deployed to the org before deploying this library. The sample application [here](https://github.com/apex-enterprise-patterns/fflib-apex-common-samplecode) has also been updated to demonstrate the new features! - **July 2014**, **IMPORTANT CHANGE**, prior **23rd July 2014**, both the ``fflib_SObjectDomain.onValidate()`` and ``fflib_SObjectDomain.onValidate(Map existingRecords)`` methods where called during an on **after update** trigger event. From this point on the ``onValidate()`` method will only be called during on **after insert**. If you still require the orignal behaviour add the line ``Configuration.enableOldOnUpdateValidateBehaviour();`` into your constructor. - **June 2014**, New classes providing utilities to support security and dynamic queries, in addition to improvements to existing Apex Enterprise Pattern base classes. Read more [here](http://andyinthecloud.com/2014/06/28/financialforce-apex-common-updates/). -- **June 2014**, Experimental [branch](https://github.com/apex-enterprise-patterns/fflib-apex-common/tree/fls-support-experiment) supporting automated FLS checking, see [README](https://github.com/apex-enterprise-patterns/fflib-apex-common/tree/fls-support-experiment#expirimental-crud-and-fls-support) for more details. This Library ============ diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls index f00c0818764..11c464b2c9e 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls @@ -652,10 +652,10 @@ private with sharing class fflib_SObjectSelectorTest } @isTest - static void testPolymorphicSelectWithRelatedType() { + static void toSOQL_When_PolymorphicSelect_Expect_RelatedType() { //Given - Testfflib_CampaignMemberSelector cmSelector = new Testfflib_CampaignMemberSelector(); + CampaignMemberSelector cmSelector = new CampaignMemberSelector(fflib_SObjectSelector.DataAccess.LEGACY); fflib_QueryFactory qf = cmSelector.newQueryFactory(); new Testfflib_LeadSelector().configureQueryFactoryFields(qf, 'Lead'); new Testfflib_UserSelector().configureQueryFactoryFields(qf, 'Lead.Owner'); @@ -680,9 +680,33 @@ private with sharing class fflib_SObjectSelectorTest System.assertEquals(expectedSelectFields, new Set(actualSelectFields)); } - private class Testfflib_CampaignMemberSelector extends fflib_SObjectSelector { - public Testfflib_CampaignMemberSelector() { - super(); + @isTest + static void toSOQL_When_SystemModePolymorphicSelect_Expect_RelatedType() { + CampaignMemberSelector cmSelector = new CampaignMemberSelector(fflib_SObjectSelector.DataAccess.SYSTEM_MODE); + fflib_QueryFactory qf = cmSelector.newQueryFactory(); + new Testfflib_LeadSelector().configureQueryFactoryFields(qf, 'Lead'); + new Testfflib_UserSelector().configureQueryFactoryFields(qf, 'Lead.Owner'); + + List expectedSelectFields = new List{ + 'id', 'status', 'lead.ownerid', 'lead.id', 'lead.owner.userroleid', 'lead.owner.id' + }; + if (UserInfo.isMultiCurrencyOrganization()) { + expectedSelectFields.add('CurrencyIsoCode'); + } + + String expectedSOQL = 'SELECT ' + String.join(expectedSelectFields,', ') + ' FROM CampaignMember WITH SYSTEM_MODE ORDER BY CreatedDate ASC NULLS FIRST '; + + //When + String actualSOQL = qf.toSOQL(); + + //Then + System.assertEquals(expectedSOQL, actualSOQL); + } + + + private class CampaignMemberSelector extends fflib_SObjectSelector { + public CampaignMemberSelector(DataAccess access) { + super(false, access); } public List getSObjectFieldList() { From 958aca391cb3041715ac7365a11d30fa7f315fbc Mon Sep 17 00:00:00 2001 From: David Esposito Date: Tue, 20 Dec 2022 09:55:36 -0500 Subject: [PATCH 38/62] #419 - apparently my wiki syntax was wrong; updates the README further --- README.md | 2 +- sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 337cd8a9736..4f0e4f9e9ec 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ FFLib Apex Common Updates ======= -- **December 2022**, **IMPORTANT CHANGE** - Support for native Apex User Mode was added to the library per the discussion over on #419. For new projects, the old "enforceCRUD" and "enforceFLS" flags on `fflib_SObjectSelector` should be considered deprecated and the constructors that take `dataAccess` arguments should be used instead +- **December 2022**, **IMPORTANT CHANGE** - Support for native Apex User Mode was added to the library (see [discussion](apex-enterprise-patterns/fflib-apex-common/discussions/419)). For new projects, the old `enforceCRUD` and `enforceFLS` flags on `fflib_SObjectSelector` should be considered deprecated and the constructors that take `dataAccess` arguments should be used instead. There are measurable performance benefits to using `SYSTEM_MODE` and `USER_MODE` (Apex CPU usage reduction). - **April 2020**, **IMPORTANT CHANGE**, the directory format of this project repo was converted to [Salesforce DX Source Format](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_source_file_format.htm). While the GIT commit history was maintained, it is not visible on GitHub. If you need to see the history, either clone the repo and execute `git log --follow` from the command line or refer to this [tag](https://github.com/apex-enterprise-patterns/fflib-apex-common/tree/metadata-format-prior-to-dx-source-format-conversion) of the codebase prior to conversion. - **September 2014**, **IMPORTANT CHANGE**, changes applied to support Dreamforce 2014 advanced presentation, library now provides Application factories for major layers and support for ApexMocks. More details to follow! As a result [ApexMocks](https://github.com/apex-enterprise-patterns/fflib-apex-mocks) must be deployed to the org before deploying this library. The sample application [here](https://github.com/apex-enterprise-patterns/fflib-apex-common-samplecode) has also been updated to demonstrate the new features! - **July 2014**, **IMPORTANT CHANGE**, prior **23rd July 2014**, both the ``fflib_SObjectDomain.onValidate()`` and ``fflib_SObjectDomain.onValidate(Map existingRecords)`` methods where called during an on **after update** trigger event. From this point on the ``onValidate()`` method will only be called during on **after insert**. If you still require the orignal behaviour add the line ``Configuration.enableOldOnUpdateValidateBehaviour();`` into your constructor. diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls index b20011a0507..e0def0a7ed3 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls @@ -125,7 +125,7 @@ public abstract with sharing class fflib_SObjectSelector * Constructs the Selector * * @param includeFieldSetFields Set to true if the Selector queries are to include Fieldset fields as well - * @deprecated - consider using userMode for native platform enforcement of CRUD and FLS + * @deprecated - consider using dataAccess for native platform enforcement of CRUD and FLS **/ public fflib_SObjectSelector(Boolean includeFieldSetFields, Boolean enforceCRUD, Boolean enforceFLS) { From e3477152af27ff59d1721829bc7848b4a3ae7412 Mon Sep 17 00:00:00 2001 From: David Esposito Date: Tue, 20 Dec 2022 09:57:53 -0500 Subject: [PATCH 39/62] #419 - apparently relative links don't work; changing to absolute --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4f0e4f9e9ec..fe319c5315f 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ FFLib Apex Common Updates ======= -- **December 2022**, **IMPORTANT CHANGE** - Support for native Apex User Mode was added to the library (see [discussion](apex-enterprise-patterns/fflib-apex-common/discussions/419)). For new projects, the old `enforceCRUD` and `enforceFLS` flags on `fflib_SObjectSelector` should be considered deprecated and the constructors that take `dataAccess` arguments should be used instead. There are measurable performance benefits to using `SYSTEM_MODE` and `USER_MODE` (Apex CPU usage reduction). +- **December 2022**, **IMPORTANT CHANGE** - Support for native Apex User Mode was added to the library (see [discussion](https://github.com/apex-enterprise-patterns/fflib-apex-common/discussions/419)). For new projects, the old `enforceCRUD` and `enforceFLS` flags on `fflib_SObjectSelector` should be considered deprecated and the constructors that take `dataAccess` arguments should be used instead. There are measurable performance benefits to using `SYSTEM_MODE` and `USER_MODE` (Apex CPU usage reduction). - **April 2020**, **IMPORTANT CHANGE**, the directory format of this project repo was converted to [Salesforce DX Source Format](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_source_file_format.htm). While the GIT commit history was maintained, it is not visible on GitHub. If you need to see the history, either clone the repo and execute `git log --follow` from the command line or refer to this [tag](https://github.com/apex-enterprise-patterns/fflib-apex-common/tree/metadata-format-prior-to-dx-source-format-conversion) of the codebase prior to conversion. - **September 2014**, **IMPORTANT CHANGE**, changes applied to support Dreamforce 2014 advanced presentation, library now provides Application factories for major layers and support for ApexMocks. More details to follow! As a result [ApexMocks](https://github.com/apex-enterprise-patterns/fflib-apex-mocks) must be deployed to the org before deploying this library. The sample application [here](https://github.com/apex-enterprise-patterns/fflib-apex-common-samplecode) has also been updated to demonstrate the new features! - **July 2014**, **IMPORTANT CHANGE**, prior **23rd July 2014**, both the ``fflib_SObjectDomain.onValidate()`` and ``fflib_SObjectDomain.onValidate(Map existingRecords)`` methods where called during an on **after update** trigger event. From this point on the ``onValidate()`` method will only be called during on **after insert**. If you still require the orignal behaviour add the line ``Configuration.enableOldOnUpdateValidateBehaviour();`` into your constructor. From f18e3944b82566a07c5fef628c764a7204533756 Mon Sep 17 00:00:00 2001 From: John Date: Thu, 22 Dec 2022 13:54:59 -0800 Subject: [PATCH 40/62] Issue-437 - Pass selector's SObjectType to QueryFactory. - Supporting test and improvement --- .../main/classes/fflib_SObjectSelector.cls | 4 +- .../classes/fflib_SObjectSelectorTest.cls | 58 +++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls index 20a56f7a883..2664f248795 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls @@ -385,7 +385,7 @@ public abstract with sharing class fflib_SObjectSelector } // Automatically select the CurrencyIsoCode for MC orgs (unless the object is a known exception to the rule) if(UserInfo.isMultiCurrencyOrganization() && CURRENCY_ISO_CODE_ENABLED){ - queryFactory.selectField(relationshipFieldPath+'.CurrencyIsoCode'); + queryFactory.selectField(relationshipFieldPath+'.CurrencyIsoCode', getSObjectType()); } } @@ -468,7 +468,7 @@ public abstract with sharing class fflib_SObjectSelector // Automatically select the CurrencyIsoCode for MC orgs (unless the object is a known exception to the rule) if(UserInfo.isMultiCurrencyOrganization() && CURRENCY_ISO_CODE_ENABLED) - queryFactory.selectField('CurrencyIsoCode'); + queryFactory.selectField('CurrencyIsoCode', getSObjectType()); } // Parse the getOrderBy() diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls index c982d9144d4..cebc99ab541 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls @@ -491,6 +491,8 @@ private with sharing class fflib_SObjectSelectorTest }; if (UserInfo.isMultiCurrencyOrganization()) { expectedSelectFields.add('CurrencyIsoCode'); + expectedSelectFields.add('Lead.CurrencyIsoCode'); + expectedSelectFields.add('Lead.Owner.CurrencyIsoCode'); // Because the Selector is for User; Group would not have } //When @@ -505,6 +507,46 @@ private with sharing class fflib_SObjectSelectorTest System.assertEquals(expectedSelectFields, new Set(actualSelectFields)); } + @isTest + static void testPolymorphicSelectWithRelatedTypeWherePolymorphicNotImpactedByMulticurrency() { + //Given + + Testfflib_CampaignMemberSelector cmSelector = new Testfflib_CampaignMemberSelector(); + fflib_QueryFactory qf = cmSelector.newQueryFactory(); + new Testfflib_LeadSelector().configureQueryFactoryFields(qf, 'Lead'); + new Testfflib_GroupSelector().configureQueryFactoryFields(qf, 'Lead.Owner'); + + + Set expectedSelectFields = new Set{ + 'Id', 'Status', 'Lead.Id', 'Lead.OwnerId', 'Lead.Owner.Id' + }; + Set unexpectedSelectFields = new Set(); + if (UserInfo.isMultiCurrencyOrganization()) { + expectedSelectFields.add('CurrencyIsoCode'); + expectedSelectFields.add('Lead.CurrencyIsoCode'); + + unexpectedSelectFields.add('Lead.Owner.CurrencyIsoCode'); // Because Group does NOT have CurrencyIsoCode + } + + //When + String soql = qf.toSOQL(); + + //Then + Pattern soqlPattern = Pattern.compile('SELECT (.*) FROM CampaignMember ORDER BY CreatedDate ASC NULLS FIRST '); + Matcher soqlMatcher = soqlPattern.matcher(soql); + soqlMatcher.matches(); + + List actualSelectFields = soqlMatcher.group(1).deleteWhiteSpace().split(','); + Set actualSelectFieldsSet = new Set(actualSelectFields); + Assert.areEqual(expectedSelectFields, actualSelectFieldsSet); + if (unexpectedSelectFields.size() > 0) { + Assert.isFalse( + actualSelectFieldsSet.containsAll(unexpectedSelectFields), + String.format('The fields {0} were not expected on actualSelectFieldsSet {1}', new List>{unexpectedSelectFields, actualSelectFieldsSet}) + ); + } + } + private class Testfflib_CampaignMemberSelector extends fflib_SObjectSelector { public Testfflib_CampaignMemberSelector() { super(); @@ -539,6 +581,22 @@ private with sharing class fflib_SObjectSelectorTest } } + private class Testfflib_GroupSelector extends fflib_SObjectSelector { + public Testfflib_GroupSelector() { + super(); + } + + public List getSObjectFieldList() { + return new List{ + Group.Id + }; + } + + public Schema.SObjectType getSObjectType() { + return Group.sObjectType; + } + } + private class Testfflib_LeadSelector extends fflib_SObjectSelector { public Testfflib_LeadSelector() { super(); From d04b6d7b49db40309e3db206e1d2a37f9cc68647 Mon Sep 17 00:00:00 2001 From: David Esposito Date: Mon, 9 Jan 2023 11:00:52 -0500 Subject: [PATCH 41/62] #419 - updates README to call attention to UserModeDML and adds an optional constructor to UserModeDML to permit explicit SYSTEM_MODE --- README.md | 2 +- .../main/classes/fflib_SObjectUnitOfWork.cls | 18 +++++++++++++++--- .../classes/fflib_SObjectUnitOfWorkTest.cls | 12 ++++++++++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c7dcb81bedb..b1328c3d571 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ FFLib Apex Common Updates ======= -- **December 2022**, **IMPORTANT CHANGE** - Support for native Apex User Mode was added to the library (see [discussion](https://github.com/apex-enterprise-patterns/fflib-apex-common/discussions/419)). For new projects, the old `enforceCRUD` and `enforceFLS` flags on `fflib_SObjectSelector` should be considered deprecated and the constructors that take `dataAccess` arguments should be used instead. There are measurable performance benefits to using `SYSTEM_MODE` and `USER_MODE` (Apex CPU usage reduction). +- **December 2022**, **IMPORTANT CHANGE** - Support for native Apex User Mode was added to the library (see [discussion](https://github.com/apex-enterprise-patterns/fflib-apex-common/discussions/419)). For new projects, the old `enforceCRUD` and `enforceFLS` flags on `fflib_SObjectSelector` should be considered deprecated and the constructors that take `dataAccess` arguments should be used instead. Additionally, the introduction of `fflib_SObjectUnitOfWork.UserModeDML` provides an `IDML` implementation that supports `USER_MODE` or `SYSTEM_MODE`. `fflib_SObjectUnitOfWork.SimpleDML` (the default `IDML` implementation) should be considered deprecated. There are measurable performance benefits to using `SYSTEM_MODE` and `USER_MODE` (Apex CPU usage reduction). Additionally, the use of explicit `USER_MODE` and `SYSTEM_MODE` overrides the `with sharing` and `without sharing` class declaration and makes the expected behavior of DML and SOQL easier to understand. - **April 2020**, **IMPORTANT CHANGE**, the directory format of this project repo was converted to [Salesforce DX Source Format](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_source_file_format.htm). While the GIT commit history was maintained, it is not visible on GitHub. If you need to see the history, either clone the repo and execute `git log --follow` from the command line or refer to this [tag](https://github.com/apex-enterprise-patterns/fflib-apex-common/tree/metadata-format-prior-to-dx-source-format-conversion) of the codebase prior to conversion. - **September 2014**, **IMPORTANT CHANGE**, changes applied to support Dreamforce 2014 advanced presentation, library now provides Application factories for major layers and support for ApexMocks. More details to follow! As a result [ApexMocks](https://github.com/apex-enterprise-patterns/fflib-apex-mocks) must be deployed to the org before deploying this library. The sample application [here](https://github.com/apex-enterprise-patterns/fflib-apex-common-samplecode) has also been updated to demonstrate the new features! - **July 2014**, **IMPORTANT CHANGE**, prior **23rd July 2014**, both the ``fflib_SObjectDomain.onValidate()`` and ``fflib_SObjectDomain.onValidate(Map existingRecords)`` methods where called during an on **after update** trigger event. From this point on the ``onValidate()`` method will only be called during on **after insert**. If you still require the orignal behaviour add the line ``Configuration.enableOldOnUpdateValidateBehaviour();`` into your constructor. diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls b/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls index 7beef0dd9a9..1c38f657b61 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls @@ -123,14 +123,26 @@ public virtual class fflib_SObjectUnitOfWork } public virtual class UserModeDML extends SimpleDML{ + @TestVisible + private AccessLevel m_accessLevel; + + public UserModeDML(){ + this(AccessLevel.USER_MODE); + } + + /** Supply the AccessLevel explicitly (UserModeDML uses AccessMode.USER_MODE, by default) */ + public UserModeDML(AccessLevel access){ + m_accessLevel = access; + } + public virtual override void dmlInsert(List objList){ - Database.insert(objList,AccessLevel.USER_MODE); + Database.insert(objList,m_accessLevel); } public virtual override void dmlUpdate(List objList){ - Database.update(objList,AccessLevel.USER_MODE); + Database.update(objList,m_accessLevel); } public virtual override void dmlDelete(List objList){ - Database.delete(objList,AccessLevel.USER_MODE); + Database.delete(objList,m_accessLevel); } } diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls b/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls index 06274a9f38f..582e759bc38 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls @@ -629,6 +629,18 @@ private with sharing class fflib_SObjectUnitOfWorkTest System.assertEquals(1, mockDML.recordsForInsert.size()); } + @IsTest + private static void constructUserModeDML_When_DefaultConstructor_Expect_UserMode(){ + fflib_SObjectUnitOfWork.UserModeDML dml = new fflib_SObjectUnitOfWork.UserModeDML(); + System.assertEquals(AccessLevel.USER_MODE,dml.m_accessLevel); + } + + @IsTest + private static void constructUserModeDML_When_AccessLevelSupplied_Expect_SameAccessLevel(){ + fflib_SObjectUnitOfWork.UserModeDML dml = new fflib_SObjectUnitOfWork.UserModeDML(AccessLevel.SYSTEM_MODE); + System.assertEquals(AccessLevel.SYSTEM_MODE,dml.m_accessLevel); + } + /** * Assert that actual events exactly match expected events (size, order and name) * and types match expected types From 3e1e199a96eb1007471d6a97b0fbd1bc04136c96 Mon Sep 17 00:00:00 2001 From: John Storey Date: Tue, 31 Jan 2023 11:55:15 -0800 Subject: [PATCH 42/62] Merging UserMode feature into branch and fix tests accordingly --- .../classes/fflib_SObjectSelectorTest.cls | 60 ++++++++++++++++--- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls index 66e608db39b..8841ca44cdd 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls @@ -443,7 +443,7 @@ private with sharing class fflib_SObjectSelectorTest String soql = sel.createSelectAllWithAccountSOQL(); - String expected = 'SELECT name, id, amount, closedate, account\\.name, account\\.billingpostalcode(.*)FROM Opportunity WITH SYSTEM_MODE ORDER BY Name ASC NULLS FIRST '; + String expected = 'SELECT name, id, amount, closedate, (currencyisocode, )?account\\.name, account\\.billingpostalcode(.*)FROM Opportunity WITH SYSTEM_MODE ORDER BY Name ASC NULLS FIRST '; Pattern soqlPattern = Pattern.compile(expected); Matcher soqlMatcher = soqlPattern.matcher(soql); System.assert(soqlMatcher.matches(),'Expected: ' + expected + ' Actual:' + soql); @@ -455,7 +455,7 @@ private with sharing class fflib_SObjectSelectorTest String soql = sel.createSelectAccountWithOpportunitiesSOQL(); - String expected = 'SELECT name, id, annualrevenue, accountnumber,(.*)\\(SELECT name, id, amount, closedate FROM Opportunities ORDER BY Name ASC NULLS FIRST \\) FROM Account WITH SYSTEM_MODE ORDER BY Name ASC NULLS FIRST '; + String expected = 'SELECT name, id, annualrevenue, accountnumber,(.*)\\(SELECT name, id, amount, closedate(.*)FROM Opportunities ORDER BY Name ASC NULLS FIRST \\) FROM Account WITH SYSTEM_MODE ORDER BY Name ASC NULLS FIRST '; Pattern soqlPattern = Pattern.compile(expected); Matcher soqlMatcher = soqlPattern.matcher(soql); System.assert(soqlMatcher.matches(),'Expected: ' + expected + ' Actual:' + soql); @@ -683,19 +683,64 @@ private with sharing class fflib_SObjectSelectorTest } @isTest - static void toSOQL_When_SystemModePolymorphicSelect_Expect_RelatedType() { - CampaignMemberSelector cmSelector = new CampaignMemberSelector(fflib_SObjectSelector.DataAccess.SYSTEM_MODE); + static void toSOQL_When_PolymorphicSelectInMulticurrency_Expect_RelatedType() { + //Given + + CampaignMemberSelector cmSelector = new CampaignMemberSelector(fflib_SObjectSelector.DataAccess.LEGACY); fflib_QueryFactory qf = cmSelector.newQueryFactory(); new Testfflib_LeadSelector().configureQueryFactoryFields(qf, 'Lead'); - new Testfflib_UserSelector().configureQueryFactoryFields(qf, 'Lead.Owner'); + new Testfflib_GroupSelector().configureQueryFactoryFields(qf, 'Lead.Owner'); - List expectedSelectFields = new List{ - 'id', 'status', 'lead.ownerid', 'lead.id', 'lead.owner.userroleid', 'lead.owner.id' + + Set expectedSelectFields = new Set{ + 'Id', 'Status', 'Lead.Id', 'Lead.OwnerId', 'Lead.Owner.Id' }; + Set unexpectedSelectFields = new Set(); if (UserInfo.isMultiCurrencyOrganization()) { expectedSelectFields.add('CurrencyIsoCode'); + expectedSelectFields.add('Lead.CurrencyIsoCode'); + + unexpectedSelectFields.add('Lead.Owner.CurrencyIsoCode'); // Because Group does NOT have CurrencyIsoCode } + //When + String soql = qf.toSOQL(); + System.debug(soql); + + //Then + Pattern soqlPattern = Pattern.compile('SELECT (.*) FROM CampaignMember ORDER BY CreatedDate ASC NULLS FIRST '); + Matcher soqlMatcher = soqlPattern.matcher(soql); + soqlMatcher.matches(); + + List actualSelectFields = soqlMatcher.group(1).deleteWhiteSpace().split(','); + Set actualSelectFieldsSet = new Set(actualSelectFields); + Assert.areEqual(expectedSelectFields, actualSelectFieldsSet); + if (unexpectedSelectFields.size() > 0) { + Assert.isFalse( + actualSelectFieldsSet.containsAll(unexpectedSelectFields), + String.format('The fields {0} were not expected on actualSelectFieldsSet {1}', new List>{unexpectedSelectFields, actualSelectFieldsSet}) + ); + } + } + + @isTest + static void toSOQL_When_SystemModePolymorphicSelect_Expect_RelatedType() { + CampaignMemberSelector cmSelector = new CampaignMemberSelector(fflib_SObjectSelector.DataAccess.SYSTEM_MODE); + fflib_QueryFactory qf = cmSelector.newQueryFactory(); + new Testfflib_LeadSelector().configureQueryFactoryFields(qf, 'Lead'); + new Testfflib_UserSelector().configureQueryFactoryFields(qf, 'Lead.Owner'); + + List expectedSelectFields = new List(); + expectedSelectFields.add('id'); + expectedSelectFields.add('status'); + if (UserInfo.isMultiCurrencyOrganization()) expectedSelectFields.add('currencyisocode'); + expectedSelectFields.add('lead.ownerid'); + expectedSelectFields.add('lead.id'); + if (UserInfo.isMultiCurrencyOrganization()) expectedSelectFields.add('lead.currencyisocode'); + expectedSelectFields.add('lead.owner.userroleid'); + expectedSelectFields.add('lead.owner.id'); + if (UserInfo.isMultiCurrencyOrganization()) expectedSelectFields.add('lead.owner.currencyisocode'); + String expectedSOQL = 'SELECT ' + String.join(expectedSelectFields,', ') + ' FROM CampaignMember WITH SYSTEM_MODE ORDER BY CreatedDate ASC NULLS FIRST '; //When @@ -705,7 +750,6 @@ private with sharing class fflib_SObjectSelectorTest System.assertEquals(expectedSOQL, actualSOQL); } - private class CampaignMemberSelector extends fflib_SObjectSelector { public CampaignMemberSelector(DataAccess access) { super(false, access); From 1c3b7623050e608e5f65b46ea4d516a4ae9fda26 Mon Sep 17 00:00:00 2001 From: Clay Chipps Date: Mon, 3 Apr 2023 15:14:21 -0400 Subject: [PATCH 43/62] chore: bump to api 57.0 --- sfdx-project.json | 2 +- .../apex-common/main/classes/fflib_Application.cls-meta.xml | 2 +- sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml | 2 +- .../main/classes/fflib_IDomainConstructor.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_IObjects.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml | 2 +- .../main/classes/fflib_ISObjectSelector.cls-meta.xml | 2 +- .../main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_ISObjects.cls-meta.xml | 2 +- sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_QueryFactory.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml | 2 +- .../main/classes/fflib_SObjectUnitOfWork.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SObjects.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_StringBuilder.cls-meta.xml | 2 +- .../apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml | 2 +- .../apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml | 2 +- .../test/classes/fflib_QueryFactoryTest.cls-meta.xml | 2 +- .../test/classes/fflib_SObjectDescribeTest.cls-meta.xml | 2 +- .../test/classes/fflib_SObjectDomainTest.cls-meta.xml | 2 +- .../test/classes/fflib_SObjectSelectorTest.cls-meta.xml | 2 +- .../test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml | 2 +- .../apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml | 2 +- .../test/classes/fflib_SecurityUtilsTest.cls-meta.xml | 2 +- .../test/classes/fflib_StringBuilderTest.cls-meta.xml | 2 +- .../test/classes/mocks/fflib_SObjectMocks.cls-meta.xml | 2 +- 29 files changed, 29 insertions(+), 29 deletions(-) diff --git a/sfdx-project.json b/sfdx-project.json index fc789c2d464..88c7589efa9 100644 --- a/sfdx-project.json +++ b/sfdx-project.json @@ -7,5 +7,5 @@ ], "namespace": "", "sfdcLoginUrl": "https://login.salesforce.com", - "sourceApiVersion": "55.0" + "sourceApiVersion": "57.0" } \ No newline at end of file diff --git a/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml index 3b90cb4bda0..cac127cd1a1 100644 --- a/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml @@ -1,4 +1,4 @@ - 55.0 + 57.0 diff --git a/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active diff --git a/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml b/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml index 4b0bc9f3879..754ecb15544 100644 --- a/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml @@ -1,5 +1,5 @@ - 55.0 + 57.0 Active From 214cb7a7547ae199270254e3162d989fea6517de Mon Sep 17 00:00:00 2001 From: Clay Chipps Date: Mon, 17 Apr 2023 10:09:26 -0400 Subject: [PATCH 44/62] chore: bump 51.0 to 57.0 --- .../apex-common/main/classes/fflib_IDomainFactory.cls-meta.xml | 2 +- .../main/classes/fflib_ISelectorFactory.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_IServiceFactory.cls-meta.xml | 2 +- .../main/classes/fflib_IUnitOfWorkFactory.cls-meta.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_IDomainFactory.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IDomainFactory.cls-meta.xml index d75b0582fba..754ecb15544 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IDomainFactory.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IDomainFactory.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 57.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISelectorFactory.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISelectorFactory.cls-meta.xml index d75b0582fba..754ecb15544 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISelectorFactory.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISelectorFactory.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 57.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IServiceFactory.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IServiceFactory.cls-meta.xml index d75b0582fba..754ecb15544 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IServiceFactory.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IServiceFactory.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 57.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IUnitOfWorkFactory.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IUnitOfWorkFactory.cls-meta.xml index d75b0582fba..754ecb15544 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IUnitOfWorkFactory.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IUnitOfWorkFactory.cls-meta.xml @@ -1,5 +1,5 @@ - 51.0 + 57.0 Active From fb9e5b8bf8305522917a1da445d33412f585075c Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 6 May 2023 19:49:28 +1000 Subject: [PATCH 45/62] Allow for either Name or CreatedDate as order by. Harcoded Order by name fails with encrypted name. --- .../apex-common/test/classes/fflib_SObjectSelectorTest.cls | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls index 11c464b2c9e..d999ff74384 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls @@ -167,7 +167,7 @@ private with sharing class fflib_SObjectSelectorTest { Testfflib_SObjectSelectorDefaultSorting selector = new Testfflib_SObjectSelectorDefaultSorting(false); String soql = selector.newQueryFactory().toSOQL(); - Pattern p = Pattern.compile('SELECT (.*) FROM Account ORDER BY Name ASC NULLS FIRST '); + Pattern p = Pattern.compile('SELECT (.*) FROM Account ORDER BY (?:Name|CreatedDate) ASC NULLS FIRST '); Matcher m = p.matcher(soql); System.assert(m.matches(), 'Generated SOQL does not match expected pattern. Here is the generated SOQL: ' + soql); System.assertEquals(1, m.groupCount(), 'Unexpected number of groups captured.'); @@ -455,7 +455,7 @@ private with sharing class fflib_SObjectSelectorTest String soql = sel.createSelectAccountWithOpportunitiesSOQL(); - String expected = 'SELECT name, id, annualrevenue, accountnumber,(.*)\\(SELECT name, id, amount, closedate FROM Opportunities ORDER BY Name ASC NULLS FIRST \\) FROM Account WITH SYSTEM_MODE ORDER BY Name ASC NULLS FIRST '; + String expected = 'SELECT name, id, annualrevenue, accountnumber,(.*)\\(SELECT name, id, amount, closedate FROM Opportunities ORDER BY Name ASC NULLS FIRST \\) FROM Account WITH SYSTEM_MODE ORDER BY (?:Name|CreatedDate) ASC NULLS FIRST '; Pattern soqlPattern = Pattern.compile(expected); Matcher soqlMatcher = soqlPattern.matcher(soql); System.assert(soqlMatcher.matches(),'Expected: ' + expected + ' Actual:' + soql); From be30693f16d6fce1772c83cd2c697ff41625e66d Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 7 May 2023 16:55:29 +1000 Subject: [PATCH 46/62] Verify correct sort field --- .../test/classes/fflib_SObjectSelectorTest.cls | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls index d999ff74384..23318415cb6 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls @@ -27,6 +27,10 @@ @IsTest private with sharing class fflib_SObjectSelectorTest { + //Get the correct sort field depending on sortable status of Name field + static String getDefaultSortField(DescribeSObjectResult sobjDesc) { + return sobjDesc.fields.getMap().get('name').getDescribe().isSortable() ? 'Name' : 'CreatedDate'; + } @TestSetup static void testSetup(){ fflib_SecurityUtilsTest.testSetup(); @@ -167,7 +171,8 @@ private with sharing class fflib_SObjectSelectorTest { Testfflib_SObjectSelectorDefaultSorting selector = new Testfflib_SObjectSelectorDefaultSorting(false); String soql = selector.newQueryFactory().toSOQL(); - Pattern p = Pattern.compile('SELECT (.*) FROM Account ORDER BY (?:Name|CreatedDate) ASC NULLS FIRST '); + Pattern p = Pattern.compile(String.format('SELECT (.*) FROM Account ORDER BY {0} ASC NULLS FIRST ', + new List{getDefaultSortField(SObjectType.Account)})); Matcher m = p.matcher(soql); System.assert(m.matches(), 'Generated SOQL does not match expected pattern. Here is the generated SOQL: ' + soql); System.assertEquals(1, m.groupCount(), 'Unexpected number of groups captured.'); @@ -443,7 +448,8 @@ private with sharing class fflib_SObjectSelectorTest String soql = sel.createSelectAllWithAccountSOQL(); - String expected = 'SELECT name, id, amount, closedate, account\\.name, account\\.billingpostalcode(.*)FROM Opportunity WITH SYSTEM_MODE ORDER BY Name ASC NULLS FIRST '; + String expected = String.format('SELECT name, id, amount, closedate, account\\.name, account\\.billingpostalcode(.*)FROM Opportunity WITH SYSTEM_MODE ORDER BY {0} ASC NULLS FIRST ', + new List{getDefaultSortField(SObjectType.Opportunity)}); Pattern soqlPattern = Pattern.compile(expected); Matcher soqlMatcher = soqlPattern.matcher(soql); System.assert(soqlMatcher.matches(),'Expected: ' + expected + ' Actual:' + soql); @@ -455,7 +461,8 @@ private with sharing class fflib_SObjectSelectorTest String soql = sel.createSelectAccountWithOpportunitiesSOQL(); - String expected = 'SELECT name, id, annualrevenue, accountnumber,(.*)\\(SELECT name, id, amount, closedate FROM Opportunities ORDER BY Name ASC NULLS FIRST \\) FROM Account WITH SYSTEM_MODE ORDER BY (?:Name|CreatedDate) ASC NULLS FIRST '; + String expected = String.format('SELECT name, id, annualrevenue, accountnumber,(.*)\\(SELECT name, id, amount, closedate FROM Opportunities ORDER BY {0} ASC NULLS FIRST \\) FROM Account WITH SYSTEM_MODE ORDER BY {1} ASC NULLS FIRST ', + new List{getDefaultSortField(SObjectType.Opportunity),getDefaultSortField(SObjectType.Account)}); Pattern soqlPattern = Pattern.compile(expected); Matcher soqlMatcher = soqlPattern.matcher(soql); System.assert(soqlMatcher.matches(),'Expected: ' + expected + ' Actual:' + soql); From 39452502c26d5aaf5ba47579246e27f32ee268f5 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 8 May 2023 23:23:17 +1000 Subject: [PATCH 47/62] Resolves additional test issues due to encryption --- .../classes/fflib_SObjectSelectorTest.cls | 81 ++++++++++++++----- 1 file changed, 61 insertions(+), 20 deletions(-) diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls index 23318415cb6..bc892e3dfb2 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls @@ -44,12 +44,23 @@ private with sharing class fflib_SObjectSelectorTest } static testMethod void testSelectSObjectsById() - { - // Inserting in reverse order so that we can test the order by of select + { List accountList = new List { - new Account(Name='TestAccount2',AccountNumber='A2',AnnualRevenue=12345.67), - new Account(Name='TestAccount1',AccountNumber='A1',AnnualRevenue=76543.21) }; - insert accountList; + new Account(Name='TestAccount1',AccountNumber='A2',AnnualRevenue=null), + new Account(Name='TestAccount2',AccountNumber='A1',AnnualRevenue=76543.21), + new Account(Name='TestAccount3',AccountNumber='A3',AnnualRevenue=76543.21), + new Account(Name='TestAccount4',AccountNumber='A4',AnnualRevenue=12345.21) }; + insert accountList; + + final DateTime TODAYS_DATE = System.now(); + final DateTime YESTERDAYS_DATE = System.now().addDays(-1); + + //Set dates to allow sorting by created date as well as annualrevenue NULLS LAST + Test.setCreatedDate(accountList[0].Id,TODAYS_DATE); + Test.setCreatedDate(accountList[1].Id,TODAYS_DATE); + Test.setCreatedDate(accountList[2].Id,YESTERDAYS_DATE); + Test.setCreatedDate(accountList[3].Id,YESTERDAYS_DATE); + Set idSet = new Set(); for(Account item : accountList) idSet.add(item.Id); @@ -59,22 +70,40 @@ private with sharing class fflib_SObjectSelectorTest List result = (List) selector.selectSObjectsById(idSet); Test.stopTest(); - system.assertEquals(2,result.size()); + system.assertEquals(4,result.size()); system.assertEquals('TestAccount2',result[0].Name); - system.assertEquals('A2',result[0].AccountNumber); - system.assertEquals(12345.67,result[0].AnnualRevenue); + system.assertEquals('A1',result[0].AccountNumber); + system.assertEquals(76543.21,result[0].AnnualRevenue); system.assertEquals('TestAccount1',result[1].Name); - system.assertEquals('A1',result[1].AccountNumber); - system.assertEquals(76543.21,result[1].AnnualRevenue); + system.assertEquals('A2',result[1].AccountNumber); + system.assertEquals(null,result[1].AnnualRevenue); + system.assertEquals('TestAccount4',result[2].Name); + system.assertEquals('A4',result[2].AccountNumber); + system.assertEquals(12345.21,result[2].AnnualRevenue); + system.assertEquals('TestAccount3',result[3].Name); + system.assertEquals('A3',result[3].AccountNumber); + system.assertEquals(76543.21,result[3].AnnualRevenue); + } static testMethod void testQueryLocatorById() { - // Inserting in reverse order so that we can test the order by of select List accountList = new List { - new Account(Name='TestAccount2',AccountNumber='A2',AnnualRevenue=12345.67), - new Account(Name='TestAccount1',AccountNumber='A1',AnnualRevenue=76543.21) }; + new Account(Name='TestAccount1',AccountNumber='A2',AnnualRevenue=null), + new Account(Name='TestAccount2',AccountNumber='A1',AnnualRevenue=76543.21), + new Account(Name='TestAccount3',AccountNumber='A3',AnnualRevenue=76543.21), + new Account(Name='TestAccount4',AccountNumber='A4',AnnualRevenue=12345.21) }; insert accountList; + + final DateTime TODAYS_DATE = System.now(); + final DateTime YESTERDAYS_DATE = System.now().addDays(-1); + + //Set dates to allow sorting by created date as well as annualrevenue NULLS LAST + Test.setCreatedDate(accountList[0].Id,TODAYS_DATE); + Test.setCreatedDate(accountList[1].Id,TODAYS_DATE); + Test.setCreatedDate(accountList[2].Id,YESTERDAYS_DATE); + Test.setCreatedDate(accountList[3].Id,YESTERDAYS_DATE); + Set idSet = new Set(); for(Account item : accountList) idSet.add(item.Id); @@ -88,14 +117,26 @@ private with sharing class fflib_SObjectSelectorTest System.assert(true, iteratorResult.hasNext()); Account account = (Account) iteratorResult.next(); system.assertEquals('TestAccount2',account.Name); + system.assertEquals('A1',account.AccountNumber); + system.assertEquals(76543.21,account.AnnualRevenue); + System.assertEquals(true, iteratorResult.hasNext()); + account = (Account) iteratorResult.next(); + system.assertEquals('TestAccount1',account.Name); system.assertEquals('A2',account.AccountNumber); - system.assertEquals(12345.67,account.AnnualRevenue); + system.assertEquals(null,account.AnnualRevenue); + System.assertEquals(true, iteratorResult.hasNext()); + account = (Account) iteratorResult.next(); + system.assertEquals('TestAccount4',account.Name); + system.assertEquals('A4',account.AccountNumber); + system.assertEquals(12345.21,account.AnnualRevenue); System.assert(true, iteratorResult.hasNext()); account = (Account) iteratorResult.next(); - system.assertEquals('TestAccount1',account.Name); - system.assertEquals('A1',account.AccountNumber); + system.assertEquals('TestAccount3',account.Name); + system.assertEquals('A3',account.AccountNumber); system.assertEquals(76543.21,account.AnnualRevenue); System.assertEquals(false, iteratorResult.hasNext()); + + } static testMethod void testAssertIsAccessible() @@ -159,7 +200,7 @@ private with sharing class fflib_SObjectSelectorTest { Testfflib_SObjectSelector selector = new Testfflib_SObjectSelector(); String soql = selector.newQueryFactory().toSOQL(); - Pattern p = Pattern.compile('SELECT (.*) FROM Account ORDER BY Name DESC NULLS FIRST , AnnualRevenue ASC NULLS LAST '); + Pattern p = Pattern.compile('SELECT (.*) FROM Account ORDER BY CreatedDate DESC NULLS FIRST , AnnualRevenue ASC NULLS LAST '); Matcher m = p.matcher(soql); System.assert(m.matches(), 'Generated SOQL does not match expected pattern. Here is the generated SOQL: ' + soql); System.assertEquals(1, m.groupCount(), 'Unexpected number of groups captured.'); @@ -230,7 +271,7 @@ private with sharing class fflib_SObjectSelectorTest String soql = qf.toSOQL(); //Then - Pattern soqlPattern = Pattern.compile('SELECT (.*) FROM Account ORDER BY Name DESC NULLS FIRST , AnnualRevenue ASC NULLS LAST '); + Pattern soqlPattern = Pattern.compile('SELECT (.*) FROM Account ORDER BY CreatedDate DESC NULLS FIRST , AnnualRevenue ASC NULLS LAST '); Matcher soqlMatcher = soqlPattern.matcher(soql); soqlMatcher.matches(); @@ -257,7 +298,7 @@ private with sharing class fflib_SObjectSelectorTest String soql = qf.toSOQL(); // Assert that the - Pattern soqlPattern = Pattern.compile('SELECT (.*) FROM Account ORDER BY Name DESC NULLS FIRST , AnnualRevenue ASC NULLS LAST '); + Pattern soqlPattern = Pattern.compile('SELECT (.*) FROM Account ORDER BY CreatedDate DESC NULLS FIRST , AnnualRevenue ASC NULLS LAST '); Matcher soqlMatcher = soqlPattern.matcher(soql); system.assert(soqlMatcher.matches(), 'The SOQL should have that expected.'); } @@ -498,7 +539,7 @@ private with sharing class fflib_SObjectSelectorTest public override String getOrderBy() { - return 'Name DESC, AnnualRevenue ASC NULLS LAST'; + return 'CreatedDate DESC, AnnualRevenue ASC NULLS LAST'; } } From 7736d00485dcb55a0b8accfdc425be80dbe6b475 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 9 May 2023 19:22:58 +1000 Subject: [PATCH 48/62] Reduce test changes. Use AccountNumber in place of CreatedDate --- .../classes/fflib_SObjectSelectorTest.cls | 83 +++++-------------- 1 file changed, 21 insertions(+), 62 deletions(-) diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls index bc892e3dfb2..606d1c0d3df 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls @@ -44,23 +44,12 @@ private with sharing class fflib_SObjectSelectorTest } static testMethod void testSelectSObjectsById() - { + { + // Inserting in reverse order so that we can test the order by of select List accountList = new List { - new Account(Name='TestAccount1',AccountNumber='A2',AnnualRevenue=null), - new Account(Name='TestAccount2',AccountNumber='A1',AnnualRevenue=76543.21), - new Account(Name='TestAccount3',AccountNumber='A3',AnnualRevenue=76543.21), - new Account(Name='TestAccount4',AccountNumber='A4',AnnualRevenue=12345.21) }; - insert accountList; - - final DateTime TODAYS_DATE = System.now(); - final DateTime YESTERDAYS_DATE = System.now().addDays(-1); - - //Set dates to allow sorting by created date as well as annualrevenue NULLS LAST - Test.setCreatedDate(accountList[0].Id,TODAYS_DATE); - Test.setCreatedDate(accountList[1].Id,TODAYS_DATE); - Test.setCreatedDate(accountList[2].Id,YESTERDAYS_DATE); - Test.setCreatedDate(accountList[3].Id,YESTERDAYS_DATE); - + new Account(Name='TestAccount2',AccountNumber='A2',AnnualRevenue=12345.67), + new Account(Name='TestAccount1',AccountNumber='A1',AnnualRevenue=76543.21) }; + insert accountList; Set idSet = new Set(); for(Account item : accountList) idSet.add(item.Id); @@ -70,40 +59,22 @@ private with sharing class fflib_SObjectSelectorTest List result = (List) selector.selectSObjectsById(idSet); Test.stopTest(); - system.assertEquals(4,result.size()); + system.assertEquals(2,result.size()); system.assertEquals('TestAccount2',result[0].Name); - system.assertEquals('A1',result[0].AccountNumber); - system.assertEquals(76543.21,result[0].AnnualRevenue); + system.assertEquals('A2',result[0].AccountNumber); + system.assertEquals(12345.67,result[0].AnnualRevenue); system.assertEquals('TestAccount1',result[1].Name); - system.assertEquals('A2',result[1].AccountNumber); - system.assertEquals(null,result[1].AnnualRevenue); - system.assertEquals('TestAccount4',result[2].Name); - system.assertEquals('A4',result[2].AccountNumber); - system.assertEquals(12345.21,result[2].AnnualRevenue); - system.assertEquals('TestAccount3',result[3].Name); - system.assertEquals('A3',result[3].AccountNumber); - system.assertEquals(76543.21,result[3].AnnualRevenue); - + system.assertEquals('A1',result[1].AccountNumber); + system.assertEquals(76543.21,result[1].AnnualRevenue); } static testMethod void testQueryLocatorById() { + // Inserting in reverse order so that we can test the order by of select List accountList = new List { - new Account(Name='TestAccount1',AccountNumber='A2',AnnualRevenue=null), - new Account(Name='TestAccount2',AccountNumber='A1',AnnualRevenue=76543.21), - new Account(Name='TestAccount3',AccountNumber='A3',AnnualRevenue=76543.21), - new Account(Name='TestAccount4',AccountNumber='A4',AnnualRevenue=12345.21) }; + new Account(Name='TestAccount2',AccountNumber='A2',AnnualRevenue=12345.67), + new Account(Name='TestAccount1',AccountNumber='A1',AnnualRevenue=76543.21) }; insert accountList; - - final DateTime TODAYS_DATE = System.now(); - final DateTime YESTERDAYS_DATE = System.now().addDays(-1); - - //Set dates to allow sorting by created date as well as annualrevenue NULLS LAST - Test.setCreatedDate(accountList[0].Id,TODAYS_DATE); - Test.setCreatedDate(accountList[1].Id,TODAYS_DATE); - Test.setCreatedDate(accountList[2].Id,YESTERDAYS_DATE); - Test.setCreatedDate(accountList[3].Id,YESTERDAYS_DATE); - Set idSet = new Set(); for(Account item : accountList) idSet.add(item.Id); @@ -113,30 +84,18 @@ private with sharing class fflib_SObjectSelectorTest Database.QueryLocator result = selector.queryLocatorById(idSet); System.Iterator iteratorResult = result.iterator(); Test.stopTest(); - + System.assert(true, iteratorResult.hasNext()); Account account = (Account) iteratorResult.next(); system.assertEquals('TestAccount2',account.Name); - system.assertEquals('A1',account.AccountNumber); - system.assertEquals(76543.21,account.AnnualRevenue); - System.assertEquals(true, iteratorResult.hasNext()); - account = (Account) iteratorResult.next(); - system.assertEquals('TestAccount1',account.Name); system.assertEquals('A2',account.AccountNumber); - system.assertEquals(null,account.AnnualRevenue); - System.assertEquals(true, iteratorResult.hasNext()); - account = (Account) iteratorResult.next(); - system.assertEquals('TestAccount4',account.Name); - system.assertEquals('A4',account.AccountNumber); - system.assertEquals(12345.21,account.AnnualRevenue); + system.assertEquals(12345.67,account.AnnualRevenue); System.assert(true, iteratorResult.hasNext()); account = (Account) iteratorResult.next(); - system.assertEquals('TestAccount3',account.Name); - system.assertEquals('A3',account.AccountNumber); + system.assertEquals('TestAccount1',account.Name); + system.assertEquals('A1',account.AccountNumber); system.assertEquals(76543.21,account.AnnualRevenue); System.assertEquals(false, iteratorResult.hasNext()); - - } static testMethod void testAssertIsAccessible() @@ -200,7 +159,7 @@ private with sharing class fflib_SObjectSelectorTest { Testfflib_SObjectSelector selector = new Testfflib_SObjectSelector(); String soql = selector.newQueryFactory().toSOQL(); - Pattern p = Pattern.compile('SELECT (.*) FROM Account ORDER BY CreatedDate DESC NULLS FIRST , AnnualRevenue ASC NULLS LAST '); + Pattern p = Pattern.compile('SELECT (.*) FROM Account ORDER BY AccountNumber DESC NULLS FIRST , AnnualRevenue ASC NULLS LAST '); Matcher m = p.matcher(soql); System.assert(m.matches(), 'Generated SOQL does not match expected pattern. Here is the generated SOQL: ' + soql); System.assertEquals(1, m.groupCount(), 'Unexpected number of groups captured.'); @@ -271,7 +230,7 @@ private with sharing class fflib_SObjectSelectorTest String soql = qf.toSOQL(); //Then - Pattern soqlPattern = Pattern.compile('SELECT (.*) FROM Account ORDER BY CreatedDate DESC NULLS FIRST , AnnualRevenue ASC NULLS LAST '); + Pattern soqlPattern = Pattern.compile('SELECT (.*) FROM Account ORDER BY AccountNumber DESC NULLS FIRST , AnnualRevenue ASC NULLS LAST '); Matcher soqlMatcher = soqlPattern.matcher(soql); soqlMatcher.matches(); @@ -298,7 +257,7 @@ private with sharing class fflib_SObjectSelectorTest String soql = qf.toSOQL(); // Assert that the - Pattern soqlPattern = Pattern.compile('SELECT (.*) FROM Account ORDER BY CreatedDate DESC NULLS FIRST , AnnualRevenue ASC NULLS LAST '); + Pattern soqlPattern = Pattern.compile('SELECT (.*) FROM Account ORDER BY AccountNumber DESC NULLS FIRST , AnnualRevenue ASC NULLS LAST '); Matcher soqlMatcher = soqlPattern.matcher(soql); system.assert(soqlMatcher.matches(), 'The SOQL should have that expected.'); } @@ -539,7 +498,7 @@ private with sharing class fflib_SObjectSelectorTest public override String getOrderBy() { - return 'CreatedDate DESC, AnnualRevenue ASC NULLS LAST'; + return 'AccountNumber DESC, AnnualRevenue ASC NULLS LAST'; } } From e17b6c4fdd941ebeb4a0c60c97c6e2eaf073bce7 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 13 May 2023 20:58:33 +1000 Subject: [PATCH 49/62] Updates tests to rely on selector getOrderBy() --- .../classes/fflib_SObjectSelectorTest.cls | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls index 606d1c0d3df..92bfcfac36a 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls @@ -27,10 +27,6 @@ @IsTest private with sharing class fflib_SObjectSelectorTest { - //Get the correct sort field depending on sortable status of Name field - static String getDefaultSortField(DescribeSObjectResult sobjDesc) { - return sobjDesc.fields.getMap().get('name').getDescribe().isSortable() ? 'Name' : 'CreatedDate'; - } @TestSetup static void testSetup(){ fflib_SecurityUtilsTest.testSetup(); @@ -172,7 +168,7 @@ private with sharing class fflib_SObjectSelectorTest Testfflib_SObjectSelectorDefaultSorting selector = new Testfflib_SObjectSelectorDefaultSorting(false); String soql = selector.newQueryFactory().toSOQL(); Pattern p = Pattern.compile(String.format('SELECT (.*) FROM Account ORDER BY {0} ASC NULLS FIRST ', - new List{getDefaultSortField(SObjectType.Account)})); + new List{selector.getOrderBy()})); Matcher m = p.matcher(soql); System.assert(m.matches(), 'Generated SOQL does not match expected pattern. Here is the generated SOQL: ' + soql); System.assertEquals(1, m.groupCount(), 'Unexpected number of groups captured.'); @@ -304,7 +300,7 @@ private with sharing class fflib_SObjectSelectorTest //Then String soql = qf.toSOQL(); - Pattern soqlPattern = Pattern.compile('SELECT Id, \\(SELECT (.*) FROM Users ORDER BY Name ASC NULLS FIRST \\) +FROM Account'); + Pattern soqlPattern = Pattern.compile(String.format('SELECT Id, \\(SELECT (.*) FROM Users ORDER BY {0} ASC NULLS FIRST \\) +FROM Account',new List{selector.getOrderBy()})); Matcher soqlMatcher = soqlPattern.matcher(soql); System.assert(soqlMatcher.matches(), 'Generated SOQL does not match expected pattern. Here is the generated SOQL: ' + soql); @@ -329,7 +325,8 @@ private with sharing class fflib_SObjectSelectorTest //Then String soql = qf.toSOQL(); - Pattern soqlPattern = Pattern.compile('SELECT Id, \\(SELECT (.*) FROM Users ORDER BY Name ASC NULLS FIRST \\) +FROM Account'); + Pattern soqlPattern = Pattern.compile(String.format('SELECT Id, \\(SELECT (.*) FROM Users ORDER BY {0} ASC NULLS FIRST \\) +FROM Account', + new List{selector.getOrderBy()})); Matcher soqlMatcher = soqlPattern.matcher(soql); System.assert(soqlMatcher.matches(), 'Generated SOQL does not match expected pattern. Here is the generated SOQL: ' + soql); @@ -449,7 +446,7 @@ private with sharing class fflib_SObjectSelectorTest String soql = sel.createSelectAllWithAccountSOQL(); String expected = String.format('SELECT name, id, amount, closedate, account\\.name, account\\.billingpostalcode(.*)FROM Opportunity WITH SYSTEM_MODE ORDER BY {0} ASC NULLS FIRST ', - new List{getDefaultSortField(SObjectType.Opportunity)}); + new List{sel.getOrderBy()}); Pattern soqlPattern = Pattern.compile(expected); Matcher soqlMatcher = soqlPattern.matcher(soql); System.assert(soqlMatcher.matches(),'Expected: ' + expected + ' Actual:' + soql); @@ -461,8 +458,8 @@ private with sharing class fflib_SObjectSelectorTest String soql = sel.createSelectAccountWithOpportunitiesSOQL(); - String expected = String.format('SELECT name, id, annualrevenue, accountnumber,(.*)\\(SELECT name, id, amount, closedate FROM Opportunities ORDER BY {0} ASC NULLS FIRST \\) FROM Account WITH SYSTEM_MODE ORDER BY {1} ASC NULLS FIRST ', - new List{getDefaultSortField(SObjectType.Opportunity),getDefaultSortField(SObjectType.Account)}); + String expected = String.format('SELECT name, id, annualrevenue, accountnumber,(.*)\\(SELECT name, id, amount, closedate FROM Opportunities ORDER BY {0} ASC NULLS FIRST \\) FROM Account WITH SYSTEM_MODE ORDER BY {0} ASC NULLS FIRST ', + new List{sel.getOrderBy()}); Pattern soqlPattern = Pattern.compile(expected); Matcher soqlMatcher = soqlPattern.matcher(soql); System.assert(soqlMatcher.matches(),'Expected: ' + expected + ' Actual:' + soql); @@ -679,7 +676,8 @@ private with sharing class fflib_SObjectSelectorTest String soql = qf.toSOQL(); //Then - Pattern soqlPattern = Pattern.compile('SELECT (.*) FROM CampaignMember ORDER BY CreatedDate ASC NULLS FIRST '); + Pattern soqlPattern = Pattern.compile(String.format('SELECT (.*) FROM CampaignMember ORDER BY {0} ASC NULLS FIRST ', + new List{cmSelector.getOrderBy()})); Matcher soqlMatcher = soqlPattern.matcher(soql); soqlMatcher.matches(); @@ -701,7 +699,8 @@ private with sharing class fflib_SObjectSelectorTest expectedSelectFields.add('CurrencyIsoCode'); } - String expectedSOQL = 'SELECT ' + String.join(expectedSelectFields,', ') + ' FROM CampaignMember WITH SYSTEM_MODE ORDER BY CreatedDate ASC NULLS FIRST '; + String expectedSOQL = String.format('SELECT ' + String.join(expectedSelectFields,', ') + ' FROM CampaignMember WITH SYSTEM_MODE ORDER BY {0} ASC NULLS FIRST ', + new List{cmSelector.getOrderBy()}); //When String actualSOQL = qf.toSOQL(); From b912d7ba818d4eff479ca2d053f251d39678a15e Mon Sep 17 00:00:00 2001 From: John S Date: Sun, 9 Jul 2023 10:46:10 -0700 Subject: [PATCH 50/62] Conflict resolutions for merging with HEAD of master --- config/multicurrency-scratch-def.json | 15 +++++++++++++++ .../test/classes/fflib_SObjectSelectorTest.cls | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 config/multicurrency-scratch-def.json diff --git a/config/multicurrency-scratch-def.json b/config/multicurrency-scratch-def.json new file mode 100644 index 00000000000..13823162894 --- /dev/null +++ b/config/multicurrency-scratch-def.json @@ -0,0 +1,15 @@ +{ + "orgName": "apex-common", + "edition": "Developer", + "features": [ + "MultiCurrency" + ], + "settings": { + "currencySettings":{ + "enableMultiCurrency": true + }, + "lightningExperienceSettings": { + "enableS1DesktopEnabled": true + } + } +} diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls index 0303daa8aa2..3c100c280fd 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls @@ -445,7 +445,7 @@ private with sharing class fflib_SObjectSelectorTest String soql = sel.createSelectAllWithAccountSOQL(); - String expected = String.format('SELECT name, id, amount, closedate, (currencyisocode,)?account\\.name, account\\.billingpostalcode(.*)FROM Opportunity WITH SYSTEM_MODE ORDER BY {0} ASC NULLS FIRST ', + String expected = String.format('SELECT name, id, amount, closedate, (currencyisocode, )?account\\.name, account\\.billingpostalcode(.*)FROM Opportunity WITH SYSTEM_MODE ORDER BY {0} ASC NULLS FIRST ', new List{sel.getOrderBy()}); Pattern soqlPattern = Pattern.compile(expected); Matcher soqlMatcher = soqlPattern.matcher(soql); @@ -458,7 +458,7 @@ private with sharing class fflib_SObjectSelectorTest String soql = sel.createSelectAccountWithOpportunitiesSOQL(); - String expected = String.format('SELECT name, id, annualrevenue, accountnumber,(.*)\\(SELECT name, id, amount, closedate FROM Opportunities ORDER BY {0} ASC NULLS FIRST \\) FROM Account WITH SYSTEM_MODE ORDER BY {0} ASC NULLS FIRST ', + String expected = String.format('SELECT name, id, annualrevenue, accountnumber, (currencyisocode, )?\\(SELECT name, id, amount, closedate(, currencyisocode)? FROM Opportunities ORDER BY {0} ASC NULLS FIRST \\) FROM Account WITH SYSTEM_MODE ORDER BY {0} ASC NULLS FIRST ', new List{sel.getOrderBy()}); Pattern soqlPattern = Pattern.compile(expected); Matcher soqlMatcher = soqlPattern.matcher(soql); From dbda661a3a81fc350d14cb737016ca3bc49ec4ac Mon Sep 17 00:00:00 2001 From: John S Date: Sun, 9 Jul 2023 10:49:52 -0700 Subject: [PATCH 51/62] Consistently use "currencyisocode" in expected SOQL string. --- .../apex-common/test/classes/fflib_SObjectSelectorTest.cls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls index 3c100c280fd..1226cafbbe7 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls @@ -445,7 +445,7 @@ private with sharing class fflib_SObjectSelectorTest String soql = sel.createSelectAllWithAccountSOQL(); - String expected = String.format('SELECT name, id, amount, closedate, (currencyisocode, )?account\\.name, account\\.billingpostalcode(.*)FROM Opportunity WITH SYSTEM_MODE ORDER BY {0} ASC NULLS FIRST ', + String expected = String.format('SELECT name, id, amount, closedate, (currencyisocode, )?account\\.name, account\\.billingpostalcode(, currencyisocode)? FROM Opportunity WITH SYSTEM_MODE ORDER BY {0} ASC NULLS FIRST ', new List{sel.getOrderBy()}); Pattern soqlPattern = Pattern.compile(expected); Matcher soqlMatcher = soqlPattern.matcher(soql); From b377c8530f66942ff29bd496f6fb290d5681a46a Mon Sep 17 00:00:00 2001 From: Nathan Bruhn Date: Thu, 20 Jul 2023 13:24:55 -0400 Subject: [PATCH 52/62] skip unnecessary event publish --- .../apex-common/main/classes/fflib_SObjectUnitOfWork.cls | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls b/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls index 1c38f657b61..537bf3ed78f 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls @@ -109,6 +109,11 @@ public virtual class fflib_SObjectUnitOfWork } public virtual void eventPublish(List objList) { + if (objList.isEmpty()) + { + return; + } + EventBus.publish(objList); } public virtual void emptyRecycleBin(List objList) From 1c0ab182451548b61982a5c9e2b78fa966eb2cde Mon Sep 17 00:00:00 2001 From: John S Date: Sun, 23 Jul 2023 09:55:10 -0700 Subject: [PATCH 53/62] PR #438 feedback - Use brackets for if statements. - Removed "Testfflib" prefix from inner classes. --- .../classes/fflib_SObjectSelectorTest.cls | 48 +++++++++++-------- .../fflib_SObjectSelectorTest.cls-meta.xml | 2 +- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls index 1226cafbbe7..190393b31d2 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls @@ -209,7 +209,7 @@ private with sharing class fflib_SObjectSelectorTest } - @isTest + @IsTest static void testWithoutSorting() { //Given @@ -235,7 +235,7 @@ private with sharing class fflib_SObjectSelectorTest } // Test case of ordering with NULLS LAST option passed into the ordering method - @isTest + @IsTest static void testWithOrderingNullsLast() { // Build the selector to test with @@ -636,7 +636,7 @@ private with sharing class fflib_SObjectSelectorTest private static User createChatterExternalUser() { // Can only proceed with test if we have a suitable profile - Chatter External license has no access to Opportunity - List testProfiles = [Select Id From Profile where UserLicense.Name='Chatter External' limit 1]; + List testProfiles = [SELECT Id FROM Profile WHERE UserLicense.Name='Chatter External' LIMIT 1]; if(testProfiles.size()!=1) return null; @@ -655,14 +655,14 @@ private with sharing class fflib_SObjectSelectorTest return fflib_SecurityUtilsTest.setupTestUser('Read Only'); } - @isTest + @IsTest static void toSOQL_When_PolymorphicSelect_Expect_RelatedType() { //Given CampaignMemberSelector cmSelector = new CampaignMemberSelector(fflib_SObjectSelector.DataAccess.LEGACY); fflib_QueryFactory qf = cmSelector.newQueryFactory(); - new Testfflib_LeadSelector().configureQueryFactoryFields(qf, 'Lead'); - new Testfflib_UserSelector().configureQueryFactoryFields(qf, 'Lead.Owner'); + new LeadSelector().configureQueryFactoryFields(qf, 'Lead'); + new UserSelector().configureQueryFactoryFields(qf, 'Lead.Owner'); Set expectedSelectFields = new Set{ @@ -687,14 +687,14 @@ private with sharing class fflib_SObjectSelectorTest System.assertEquals(expectedSelectFields, new Set(actualSelectFields)); } - @isTest + @IsTest static void toSOQL_When_PolymorphicSelectInMulticurrency_Expect_RelatedType() { //Given CampaignMemberSelector cmSelector = new CampaignMemberSelector(fflib_SObjectSelector.DataAccess.LEGACY); fflib_QueryFactory qf = cmSelector.newQueryFactory(); - new Testfflib_LeadSelector().configureQueryFactoryFields(qf, 'Lead'); - new Testfflib_GroupSelector().configureQueryFactoryFields(qf, 'Lead.Owner'); + new LeadSelector().configureQueryFactoryFields(qf, 'Lead'); + new GroupSelector().configureQueryFactoryFields(qf, 'Lead.Owner'); Set expectedSelectFields = new Set{ @@ -728,23 +728,29 @@ private with sharing class fflib_SObjectSelectorTest } } - @isTest + @IsTest static void toSOQL_When_SystemModePolymorphicSelect_Expect_RelatedType() { CampaignMemberSelector cmSelector = new CampaignMemberSelector(fflib_SObjectSelector.DataAccess.SYSTEM_MODE); fflib_QueryFactory qf = cmSelector.newQueryFactory(); - new Testfflib_LeadSelector().configureQueryFactoryFields(qf, 'Lead'); - new Testfflib_UserSelector().configureQueryFactoryFields(qf, 'Lead.Owner'); + new LeadSelector().configureQueryFactoryFields(qf, 'Lead'); + new UserSelector().configureQueryFactoryFields(qf, 'Lead.Owner'); List expectedSelectFields = new List(); expectedSelectFields.add('id'); expectedSelectFields.add('status'); - if (UserInfo.isMultiCurrencyOrganization()) expectedSelectFields.add('currencyisocode'); + if (UserInfo.isMultiCurrencyOrganization()) { + expectedSelectFields.add('currencyisocode'); + } expectedSelectFields.add('lead.ownerid'); expectedSelectFields.add('lead.id'); - if (UserInfo.isMultiCurrencyOrganization()) expectedSelectFields.add('lead.currencyisocode'); + if (UserInfo.isMultiCurrencyOrganization()) { + expectedSelectFields.add('lead.currencyisocode'); + } expectedSelectFields.add('lead.owner.userroleid'); expectedSelectFields.add('lead.owner.id'); - if (UserInfo.isMultiCurrencyOrganization()) expectedSelectFields.add('lead.owner.currencyisocode'); + if (UserInfo.isMultiCurrencyOrganization()) { + expectedSelectFields.add('lead.owner.currencyisocode'); + } String expectedSOQL = String.format('SELECT ' + String.join(expectedSelectFields,', ') + ' FROM CampaignMember WITH SYSTEM_MODE ORDER BY {0} ASC NULLS FIRST ', new List{cmSelector.getOrderBy()}); @@ -773,8 +779,8 @@ private with sharing class fflib_SObjectSelectorTest } } - private class Testfflib_UserSelector extends fflib_SObjectSelector { - public Testfflib_UserSelector() { + private class UserSelector extends fflib_SObjectSelector { + public UserSelector() { super(); } @@ -790,8 +796,8 @@ private with sharing class fflib_SObjectSelectorTest } } - private class Testfflib_GroupSelector extends fflib_SObjectSelector { - public Testfflib_GroupSelector() { + private class GroupSelector extends fflib_SObjectSelector { + public GroupSelector() { super(); } @@ -806,8 +812,8 @@ private with sharing class fflib_SObjectSelectorTest } } - private class Testfflib_LeadSelector extends fflib_SObjectSelector { - public Testfflib_LeadSelector() { + private class LeadSelector extends fflib_SObjectSelector { + public LeadSelector() { super(); } diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active From a5323b1cdda5f66875acaa393b094a3647702486 Mon Sep 17 00:00:00 2001 From: "John M. Daniel" Date: Mon, 14 Aug 2023 09:47:25 -0400 Subject: [PATCH 54/62] devops chore: bump to v58.0 API --- .../apex-common/main/classes/fflib_Application.cls-meta.xml | 2 +- sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml | 2 +- .../main/classes/fflib_IDomainConstructor.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_IDomainFactory.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_IObjects.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml | 2 +- .../main/classes/fflib_ISObjectSelector.cls-meta.xml | 2 +- .../main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_ISObjects.cls-meta.xml | 2 +- .../main/classes/fflib_ISelectorFactory.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_IServiceFactory.cls-meta.xml | 2 +- .../main/classes/fflib_IUnitOfWorkFactory.cls-meta.xml | 2 +- sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_QueryFactory.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml | 2 +- .../main/classes/fflib_SObjectUnitOfWork.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SObjects.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml | 2 +- .../apex-common/main/classes/fflib_StringBuilder.cls-meta.xml | 2 +- .../apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml | 2 +- .../apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml | 2 +- .../test/classes/fflib_QueryFactoryTest.cls-meta.xml | 2 +- .../test/classes/fflib_SObjectDescribeTest.cls-meta.xml | 2 +- .../test/classes/fflib_SObjectDomainTest.cls-meta.xml | 2 +- .../test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml | 2 +- .../apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml | 2 +- .../test/classes/fflib_SecurityUtilsTest.cls-meta.xml | 2 +- .../test/classes/fflib_StringBuilderTest.cls-meta.xml | 2 +- .../test/classes/mocks/fflib_SObjectMocks.cls-meta.xml | 2 +- 31 files changed, 31 insertions(+), 31 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IDomainFactory.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IDomainFactory.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IDomainFactory.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IDomainFactory.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISelectorFactory.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISelectorFactory.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISelectorFactory.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISelectorFactory.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IServiceFactory.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IServiceFactory.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IServiceFactory.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IServiceFactory.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IUnitOfWorkFactory.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IUnitOfWorkFactory.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IUnitOfWorkFactory.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IUnitOfWorkFactory.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml index cac127cd1a1..6fb1721ed2f 100644 --- a/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml @@ -1,4 +1,4 @@ - 57.0 + 58.0 diff --git a/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active diff --git a/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml b/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml index 754ecb15544..7a51829787a 100644 --- a/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml @@ -1,5 +1,5 @@ - 57.0 + 58.0 Active From 894731a23343063fdc60a592f8d3e127523c7e59 Mon Sep 17 00:00:00 2001 From: "John M. Daniel" Date: Mon, 14 Aug 2023 09:56:06 -0400 Subject: [PATCH 55/62] updated API of sfdx-project.json to v58.0 --- sfdx-project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sfdx-project.json b/sfdx-project.json index 88c7589efa9..bd76b258653 100644 --- a/sfdx-project.json +++ b/sfdx-project.json @@ -7,5 +7,5 @@ ], "namespace": "", "sfdcLoginUrl": "https://login.salesforce.com", - "sourceApiVersion": "57.0" + "sourceApiVersion": "58.0" } \ No newline at end of file From 6fbe36932c29c1ce0dcd7ebb89cb17328e9abc71 Mon Sep 17 00:00:00 2001 From: "John M. Daniel" Date: Wed, 23 Aug 2023 22:07:05 -0400 Subject: [PATCH 56/62] fixed issue that would not resolve a person account based cross-object syntax --- .../main/classes/fflib_SObjectDescribe.cls | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls b/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls index ac1575a5e57..c0be3c45b92 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls @@ -100,12 +100,18 @@ public class fflib_SObjectDescribe { * e.g. getting the Account field on Contact would fail without being referenced as AccountId - both work here. **/ public Schema.SObjectField getField(String fieldName, Boolean implyNamespace){ - Schema.SObjectField result = wrappedFields.get( - (fieldName.endsWithIgnoreCase('__r') ? //resolve custom field cross-object (__r) syntax - (fieldName.removeEndIgnoreCase('__r')+'__c') : - fieldName), - implyNamespace - ); + String fieldNameAdjusted = fieldName; + + if ( fieldName.endsWithIgnoreCase('__r') ) //resolve custom field cross-object (__r) syntax + { + fieldNameAdjusted = fieldName.removeEndIgnoreCase('__r') + '__c'; + } + else if ( fieldName.endsWithIgnoreCase('__pr') ) //resolve custom field cross-object (__pr) syntax for person accounts + { + fieldNameAdjusted = fieldName.removeEndIgnoreCase('__pr') + '__c'; + } + + Schema.SObjectField result = wrappedFields.get( fieldNameAdjusted, implyNamespace ); if(result == null){ result = wrappedFields.get(fieldName+'Id', implyNamespace); //in case it's a standard lookup in cross-object format } From ee2ac7e6402a2294e2f3da47b92200c9734f740d Mon Sep 17 00:00:00 2001 From: "John M. Daniel" Date: Mon, 4 Sep 2023 23:08:38 -0400 Subject: [PATCH 57/62] fixes #463 ...again --- sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls b/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls index c0be3c45b92..0eac50185f0 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls @@ -108,7 +108,7 @@ public class fflib_SObjectDescribe { } else if ( fieldName.endsWithIgnoreCase('__pr') ) //resolve custom field cross-object (__pr) syntax for person accounts { - fieldNameAdjusted = fieldName.removeEndIgnoreCase('__pr') + '__c'; + fieldNameAdjusted = fieldName.removeEndIgnoreCase('__pr') + '__pc'; } Schema.SObjectField result = wrappedFields.get( fieldNameAdjusted, implyNamespace ); From d482301903515aa6a4a150acc71902df52c0c7be Mon Sep 17 00:00:00 2001 From: "John M. Daniel" Date: Mon, 2 Oct 2023 09:38:22 -0400 Subject: [PATCH 58/62] corrected inline comment --- .../apex-common/main/classes/fflib_SObjectSelector.cls | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls index 2d15652a29a..3abbdc4e380 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls @@ -438,7 +438,7 @@ public abstract with sharing class fflib_SObjectSelector } /** - * Adds a subselect QueryFactory based on this selector to the given QueryFactor, returns the parentQueryFactory + * Adds a subselect QueryFactory based on this selector to the given QueryFactor, returns the child QueryFactory **/ public fflib_QueryFactory addQueryFactorySubselect(fflib_QueryFactory parentQueryFactory) { @@ -461,7 +461,7 @@ public abstract with sharing class fflib_SObjectSelector } /** - * Adds a subselect QueryFactory based on this selector to the given QueryFactor, returns the parentQueryFactory + * Adds a subselect QueryFactory based on this selector to the given QueryFactor, returns the child QueryFactory **/ public fflib_QueryFactory addQueryFactorySubselect(fflib_QueryFactory parentQueryFactory, String relationshipName) { From eb4d06d6f0cc1b697baab6ee32cfbb6caa66a2ce Mon Sep 17 00:00:00 2001 From: "John M. Daniel" Date: Sat, 4 Nov 2023 22:26:41 -0400 Subject: [PATCH 59/62] Adjustments and updates to video and related links --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index b1328c3d571..65cadaa5040 100644 --- a/README.md +++ b/README.md @@ -32,14 +32,6 @@ Application Enterprise Patterns on Force.com Design patterns are an invaluable tool for developers and architects looking to build enterprise solutions. Here are presented some tried and tested enterprise application engineering patterns that have been used in other platforms and languages. We will discuss and illustrate how patterns such as Data Mapper, Service Layer, Unit of Work and of course Model View Controller can be applied to Force.com. Applying these patterns can help manage governed resources (such as DML) better, encourage better separation-of-concerns in your logic and enforce Force.com coding best practices. -Dreamforce Session and Slides ------------------------------ - -- View slides for the **Dreamforce 2013** session [here](https://docs.google.com/file/d/0B6brfGow3cD8RVVYc1dCX2s0S1E/edit) -- Video recording of the **Dreamforce 2013** session [here](http://www.youtube.com/watch?v=qlq46AEAlLI). -- Video recording of the **Advanced Apex Enterprise Dreamforce 2014** session [here](http://dreamforce.vidyard.com/watch/7QtP2628KmtXfmiwI-7B1w%20). -- View slides for the **Dreamforce 2015** session [here](http://www.slideshare.net/andyinthecloud/building-strong-foundations-apex-enterprise-patterns) - Documentation ------------- @@ -52,11 +44,19 @@ Documentation - [Apex Enterprise Patterns - Service Layer](http://wiki.developerforce.com/page/Apex_Enterprise_Patterns_-_Service_Layer) - [Apex Enterprise Patterns - Domain Layer](http://wiki.developerforce.com/page/Apex_Enterprise_Patterns_-_Domain_Layer) - [Apex Enterprise Patterns - Selector Layer](https://github.com/financialforcedev/df12-apex-enterprise-patterns#data-mapper-selector) +- View slides for the **Dreamforce 2013** session [here](https://docs.google.com/file/d/0B6brfGow3cD8RVVYc1dCX2s0S1E/edit) +- View slides for the **Dreamforce 2015** session [here](http://www.slideshare.net/andyinthecloud/building-strong-foundations-apex-enterprise-patterns) + +**Related Webinars** +- [Advanced Apex Enterprise Patterns](https://www.youtube.com/watch?v=BLXp0ZP0cF0) +- [Apex Hours (August 2020): Apex Enterprise Patterns](https://www.apexhours.com/apex-enterprise-patterns/) + +**Related Book** +- [Salesforce Platform Enterprise Architecture, 4th Edition, by Andrew Fawcett](https://www.amazon.com/Salesforce-Platform-Enterprise-Architecture-applications-ebook/dp/B0BD8TBT75/ref=pd_ci_mcx_mh_mcx_views_0) **Other Related Blogs** - [Preview of Advanced Apex Patterns Session (Application Factory and ApexMocks Features)](http://andyinthecloud.com/2014/08/26/preview-of-advanced-apex-enterprise-patterns-session/) - [Unit Testing with the Domain Layer](http://andyinthecloud.com/2014/03/23/unit-testing-with-the-domain-layer/) -- [MavensMate Templates](http://andyinthecloud.com/2014/05/23/mavensmate-templates-and-apex-enterprise-patterns/) - [FinancialForce Apex Common Updates](http://andyinthecloud.com/2014/06/28/financialforce-apex-common-updates/) From 125b0109d0593909532ade9d10668cc94980ea2b Mon Sep 17 00:00:00 2001 From: "John M. Daniel" Date: Sun, 5 Nov 2023 15:20:53 -0500 Subject: [PATCH 60/62] removed extranious items from link to book --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 65cadaa5040..f048e626413 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Documentation - [Apex Hours (August 2020): Apex Enterprise Patterns](https://www.apexhours.com/apex-enterprise-patterns/) **Related Book** -- [Salesforce Platform Enterprise Architecture, 4th Edition, by Andrew Fawcett](https://www.amazon.com/Salesforce-Platform-Enterprise-Architecture-applications-ebook/dp/B0BD8TBT75/ref=pd_ci_mcx_mh_mcx_views_0) +- [Salesforce Platform Enterprise Architecture, 4th Edition, by Andrew Fawcett](https://www.amazon.com/Salesforce-Platform-Enterprise-Architecture-applications-ebook/dp/B0BD8TBT75/) **Other Related Blogs** From c584d115e49bc291e180c9f3cff300118321f104 Mon Sep 17 00:00:00 2001 From: "John M. Daniel" Date: Sun, 5 Nov 2023 16:03:32 -0500 Subject: [PATCH 61/62] addition of the manage sf api version github action --- .github/workflows/manage.sf.api.versions.yml | 22 ++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/manage.sf.api.versions.yml diff --git a/.github/workflows/manage.sf.api.versions.yml b/.github/workflows/manage.sf.api.versions.yml new file mode 100644 index 00000000000..6900179c01d --- /dev/null +++ b/.github/workflows/manage.sf.api.versions.yml @@ -0,0 +1,22 @@ +name: Manage SF API Versions +on: + workflow_dispatch: + inputs: + api-version: + description: 'api version in the format XX e.g 58' + required: true + type: string +jobs: + update: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: apex-enterprise-patterns/manage-sf-api-version@v1.0.0 + with: + api-version: ${{inputs.api-version}} + - uses: peter-evans/create-pull-request@v5 + with: + title: 'Bump API Versions to ${{inputs.api-version}}.0' + body: 'Automatically bumped by GitHub Actions ' + branch: 'devops/bump-api-versions-v${{inputs.api-version}}.0' + commit-message: 'chore: bump api to v${{inputs.api-version}}.0' From c74146511fe37f101f2c873190477b65838fe4c1 Mon Sep 17 00:00:00 2001 From: ImJohnMDaniel Date: Mon, 6 Nov 2023 20:24:16 +0000 Subject: [PATCH 62/62] chore: bump api to v59.0 --- sfdx-project.json | 18 +++++++++--------- .../classes/fflib_Application.cls-meta.xml | 2 +- .../main/classes/fflib_IDomain.cls-meta.xml | 2 +- .../fflib_IDomainConstructor.cls-meta.xml | 2 +- .../classes/fflib_IDomainFactory.cls-meta.xml | 2 +- .../main/classes/fflib_IObjects.cls-meta.xml | 2 +- .../classes/fflib_ISObjectDomain.cls-meta.xml | 2 +- .../fflib_ISObjectSelector.cls-meta.xml | 2 +- .../fflib_ISObjectUnitOfWork.cls-meta.xml | 2 +- .../main/classes/fflib_ISObjects.cls-meta.xml | 2 +- .../fflib_ISelectorFactory.cls-meta.xml | 2 +- .../classes/fflib_IServiceFactory.cls-meta.xml | 2 +- .../fflib_IUnitOfWorkFactory.cls-meta.xml | 2 +- .../main/classes/fflib_Objects.cls-meta.xml | 2 +- .../classes/fflib_QueryFactory.cls-meta.xml | 2 +- .../classes/fflib_SObjectDescribe.cls-meta.xml | 2 +- .../classes/fflib_SObjectDomain.cls-meta.xml | 2 +- .../classes/fflib_SObjectSelector.cls-meta.xml | 2 +- .../fflib_SObjectUnitOfWork.cls-meta.xml | 2 +- .../main/classes/fflib_SObjects.cls-meta.xml | 2 +- .../classes/fflib_SecurityUtils.cls-meta.xml | 2 +- .../classes/fflib_StringBuilder.cls-meta.xml | 2 +- .../classes/fflib_ApplicationTest.cls-meta.xml | 2 +- .../classes/fflib_ObjectsTest.cls-meta.xml | 2 +- .../fflib_QueryFactoryTest.cls-meta.xml | 2 +- .../fflib_SObjectDescribeTest.cls-meta.xml | 2 +- .../fflib_SObjectDomainTest.cls-meta.xml | 2 +- .../fflib_SObjectSelectorTest.cls-meta.xml | 2 +- .../fflib_SObjectUnitOfWorkTest.cls-meta.xml | 2 +- .../classes/fflib_SObjectsTest.cls-meta.xml | 2 +- .../fflib_SecurityUtilsTest.cls-meta.xml | 2 +- .../fflib_StringBuilderTest.cls-meta.xml | 2 +- .../mocks/fflib_SObjectMocks.cls-meta.xml | 2 +- 33 files changed, 41 insertions(+), 41 deletions(-) diff --git a/sfdx-project.json b/sfdx-project.json index bd76b258653..bb1d3657196 100644 --- a/sfdx-project.json +++ b/sfdx-project.json @@ -1,11 +1,11 @@ { - "packageDirectories": [ - { - "path": "sfdx-source/apex-common", - "default": true - } - ], - "namespace": "", - "sfdcLoginUrl": "https://login.salesforce.com", - "sourceApiVersion": "58.0" + "packageDirectories": [ + { + "path": "sfdx-source/apex-common", + "default": true + } + ], + "namespace": "", + "sfdcLoginUrl": "https://login.salesforce.com", + "sourceApiVersion": "59.0" } \ No newline at end of file diff --git a/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_Application.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IDomain.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IDomainConstructor.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IDomainFactory.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IDomainFactory.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IDomainFactory.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IDomainFactory.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IObjects.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjectDomain.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjectSelector.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjectUnitOfWork.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISObjects.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_ISelectorFactory.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_ISelectorFactory.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/main/classes/fflib_ISelectorFactory.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_ISelectorFactory.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IServiceFactory.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IServiceFactory.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IServiceFactory.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IServiceFactory.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_IUnitOfWorkFactory.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_IUnitOfWorkFactory.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/main/classes/fflib_IUnitOfWorkFactory.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_IUnitOfWorkFactory.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_Objects.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_QueryFactory.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectDescribe.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectDomain.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectSelector.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjectUnitOfWork.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SObjects.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_SecurityUtils.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml b/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml +++ b/sfdx-source/apex-common/main/classes/fflib_StringBuilder.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml index 6fb1721ed2f..d12609be92e 100644 --- a/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_ApplicationTest.cls-meta.xml @@ -1,4 +1,4 @@ - 58.0 + 59.0 diff --git a/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_ObjectsTest.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_QueryFactoryTest.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectDescribeTest.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectDomainTest.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectSelectorTest.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectUnitOfWorkTest.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SObjectsTest.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_SecurityUtilsTest.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml b/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/fflib_StringBuilderTest.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active diff --git a/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml b/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml index 7a51829787a..b1a915c9c6d 100644 --- a/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml +++ b/sfdx-source/apex-common/test/classes/mocks/fflib_SObjectMocks.cls-meta.xml @@ -1,5 +1,5 @@ - 58.0 + 59.0 Active