From a0fc1bd10d605b88959afd3ac36a0a660db192fa Mon Sep 17 00:00:00 2001 From: Wim Velzeboer Date: Fri, 1 Sep 2023 14:52:25 +0100 Subject: [PATCH] Improve performance of Dynamic Application Factories Also added a method overload to provide a Package Name. Useful for DX based second generation packages. Now each package can have their own bindings. --- .run/RunAllTest.run.xml | 33 +++++++ .../dynamic/classes/fflib_AppBinding.cls | 22 +++++ .../fflib_AppBindingMetaDataModule.cls | 1 + .../classes/fflib_AppBindingResolver.cls | 5 ++ .../dynamic/classes/fflib_AppBindings.cls | 78 ++++++++++++++--- .../classes/fflib_AppBindingsSelector.cls | 5 +- .../classes/fflib_DynamicAppFactory.cls | 2 + .../classes/fflib_DynamicDomainFactory.cls | 86 ++++++++++-------- .../classes/fflib_DynamicSelectorFactory.cls | 87 ++++++++----------- .../classes/fflib_DynamicServiceFactory.cls | 62 ++++++------- .../classes/interfaces/fflib_IAppBinding.cls | 11 +++ .../interfaces/fflib_IAppBindingResolver.cls | 1 + .../classes/interfaces/fflib_IAppBindings.cls | 10 ++- ...inding__mdt-Binding Layout.layout-meta.xml | 4 + ...Application Package Layout.layout-meta.xml | 67 ++++++++++++++ .../ApplicationPackage__c.field-meta.xml | 13 +++ ...ib_ApplicationPackage__mdt.object-meta.xml | 7 ++ .../classes/utils/fflib_MockSObjectUtil.cls | 1 - .../fflib_DynamicDomainFactoryTest.cls | 56 +++++++++++- .../classes/domains/fflib_SObjects2Test.cls | 2 - .../logger/fflib_LogEventAppenderTest.cls | 1 - .../tests/classes/logger/fflib_LoggerTest.cls | 1 - 22 files changed, 416 insertions(+), 139 deletions(-) create mode 100644 .run/RunAllTest.run.xml create mode 100644 sfdx-source/apex-extensions/main/application/dynamic/layouts/fflib_ApplicationPackage__mdt-Application Package Layout.layout-meta.xml create mode 100644 sfdx-source/apex-extensions/main/application/dynamic/objects/fflib_AppBinding__mdt/fields/ApplicationPackage__c.field-meta.xml create mode 100644 sfdx-source/apex-extensions/main/application/dynamic/objects/fflib_ApplicationPackage__mdt/fflib_ApplicationPackage__mdt.object-meta.xml diff --git a/.run/RunAllTest.run.xml b/.run/RunAllTest.run.xml new file mode 100644 index 0000000..fce4f8f --- /dev/null +++ b/.run/RunAllTest.run.xml @@ -0,0 +1,33 @@ + + + + + + + \ No newline at end of file diff --git a/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_AppBinding.cls b/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_AppBinding.cls index 5cc5f38..e88ae6c 100644 --- a/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_AppBinding.cls +++ b/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_AppBinding.cls @@ -37,6 +37,7 @@ public virtual class fflib_AppBinding protected System.Type implementationType { get; set; } protected System.Type interfaceType { get; set; } protected String namespacePrefix { get; set; } + protected String packageName { get; set; } protected fflib_SharingMode sharingMode { get; set; } public Integer compareTo(Object compareTo) @@ -89,6 +90,14 @@ public virtual class fflib_AppBinding return this.namespacePrefix; } + /** + * @return Returns the Application Package Name for the binding + */ + public String getPackageName() + { + return this.packageName; + } + /** * @return Returns the number of the order sequence in which the binding should be returned */ @@ -188,6 +197,19 @@ public virtual class fflib_AppBinding return this; } + /** + * Sets the Application Second Generation Package Name + * + * @param applicationPackageName The name of the 2GP package + * + * @return An instance of itself to enable method chaining + */ + public fflib_IAppBinding setPackageName(String applicationPackageName) + { + this.packageName = applicationPackageName; + return this; + } + /** * Set the order number so that the resolver can sort the bindings. * The higher the number, the more priority. diff --git a/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_AppBindingMetaDataModule.cls b/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_AppBindingMetaDataModule.cls index 100dbab..ddb522e 100644 --- a/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_AppBindingMetaDataModule.cls +++ b/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_AppBindingMetaDataModule.cls @@ -43,6 +43,7 @@ public with sharing class fflib_AppBindingMetaDataModule .setImplementationType(getSystemType(binding, fflib_AppBinding__mdt.ImplementationType__c)) .setInterfaceType(getSystemType(binding, fflib_AppBinding__mdt.InterfaceType__c)) .setNamespacePrefix(binding.NamespacePrefix) + .setPackageName(binding.ApplicationPackage__r.DeveloperName) .setSequence(binding.BindingSequence__c) .setSharingMode(getSharingModeFromString(binding.SharingMode__c)) ); diff --git a/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_AppBindingResolver.cls b/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_AppBindingResolver.cls index 8d24fcf..406617b 100644 --- a/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_AppBindingResolver.cls +++ b/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_AppBindingResolver.cls @@ -132,6 +132,11 @@ public virtual class fflib_AppBindingResolver return this; } + public fflib_IAppBindingResolver byPackageName(String packageName) + { + this.bindingToResolve.setPackageName(packageName); + return this; + } /** * Handles lazy loading of modules, if no custom module is configured (via addModule) the default module is returned diff --git a/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_AppBindings.cls b/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_AppBindings.cls index 31abd24..7ff4053 100644 --- a/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_AppBindings.cls +++ b/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_AppBindings.cls @@ -63,6 +63,67 @@ public virtual class fflib_AppBindings } } + public List getBindings() + { + return this.bindings; + } + + public Map getImplementationByBindingObject() + { + this.bindings.sort(); + + Map result = new Map(); + for (fflib_IAppBinding binding : bindings) + { + Object bindingObject = binding.getBindingObject(); + if (result.containsKey(bindingObject)) continue; // Skip bindings with lower sequence + + result.put(bindingObject, binding.getImplementationType()); + } + return result; + } + + public Map getImplementationByInterface() + { + this.bindings.sort(); + + Map result = new Map(); + for (fflib_IAppBinding binding : bindings) + { + Type interfaceType = binding.getInterfaceType(); + if (result.containsKey(interfaceType)) continue; // Skip bindings with lower sequence + + result.put(interfaceType, binding.getImplementationType()); + } + return result; + } + + public Map getImplementationBySObjectType() + { + Map result = new Map(); + for (fflib_IAppBinding binding : bindings) + { + Object bindingObject = binding.getBindingObject(); + if (bindingObject instanceof SObjectType && result.containsKey((SObjectType) bindingObject) == false) + { + result.put((SObjectType) bindingObject, binding.getImplementationType()); + } + } + return result; + } + + public List getImplementations() + { + List result = new List(); + for (fflib_IAppBinding binding : bindings) + { + result.add( + binding.getImplementationType() + ); + } + return result; + } + public fflib_IAppBindings selectByObject(Object bindingObject) { if (null == bindingObject) return this; @@ -149,21 +210,18 @@ public virtual class fflib_AppBindings return new fflib_AppBindings(result); } - public List getBindings() + public fflib_IAppBindings selectByPackageName(String packageName) { - return this.bindings; - } + if (null == packageName) return this; - public List getImplementations() - { - List result = new List(); + List result = new List(); for (fflib_IAppBinding binding : bindings) { - result.add( - binding.getImplementationType() - ); + if (binding.getPackageName() != packageName) continue; + + result.add(binding); } - return result; + return new fflib_AppBindings(result); } public List getObjects() diff --git a/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_AppBindingsSelector.cls b/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_AppBindingsSelector.cls index d8bc2d5..05d268d 100644 --- a/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_AppBindingsSelector.cls +++ b/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_AppBindingsSelector.cls @@ -75,6 +75,7 @@ public virtual without sharing class fflib_AppBindingsSelector extends fflib_SOb return (List) Database.query( newQueryFactory() + .selectField('ApplicationPackage__r.DeveloperName') .selectField('BindingObject__r.QualifiedApiName') .toSOQL()); */ @@ -84,7 +85,9 @@ public virtual without sharing class fflib_AppBindingsSelector extends fflib_SOb 'SELECT {0} FROM {1}', new List { - getFieldListString() + ', BindingObject__r.QualifiedApiName', + getFieldListString() + + ', BindingObject__r.QualifiedApiName' + + ', ApplicationPackage__r.DeveloperName', getSObjectType().getDescribe().getName() } ) diff --git a/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_DynamicAppFactory.cls b/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_DynamicAppFactory.cls index 9080afb..863966e 100644 --- a/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_DynamicAppFactory.cls +++ b/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_DynamicAppFactory.cls @@ -30,6 +30,8 @@ */ public abstract class fflib_DynamicAppFactory { + protected String packageName; + protected fflib_SharingMode sharingMode { get diff --git a/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_DynamicDomainFactory.cls b/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_DynamicDomainFactory.cls index aa85666..7985e8e 100644 --- a/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_DynamicDomainFactory.cls +++ b/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_DynamicDomainFactory.cls @@ -33,9 +33,8 @@ public virtual class fflib_DynamicDomainFactory extends fflib_DynamicAppFactory implements fflib_IDomainFactory { - protected Map mockDomainByObjectType = new Map(); protected fflib_ISelectorFactory selectorFactory; - + protected fflib_ClassicDomainFactory domainFactory; /** * Class constructor @@ -44,9 +43,25 @@ public virtual class fflib_DynamicDomainFactory * @param selectorFactory A reference to the selector factory instance */ public fflib_DynamicDomainFactory(fflib_IAppBindingResolver resolver, fflib_ISelectorFactory selectorFactory) + { + this(resolver, selectorFactory, null); + } + + /** + * Class constructor + * + * @param resolver A reference to the resolve instance + * @param selectorFactory A reference to the selector factory instance + * @param packageName The package name + */ + public fflib_DynamicDomainFactory( + fflib_IAppBindingResolver resolver, + fflib_ISelectorFactory selectorFactory, + String packageName) { this.resolver = resolver; this.selectorFactory = selectorFactory; + this.packageName = packageName; } public fflib_IDomain newInstance(Set recordIds) @@ -61,42 +76,16 @@ public virtual class fflib_DynamicDomainFactory public fflib_IDomain newInstance(List records) { - SObjectType sObjectType = records.getSObjectType(); + if (domainFactory == null) loadBindings(); - if (sObjectType == null) - throw new DeveloperException('Could not determine the SObjectType of the provided records'); - - return newInstance( - (List) records, - (Object) sObjectType - ); + return this.domainFactory.newInstance(records); } public fflib_IDomain newInstance(List objects, Object objectType) { - if (hasMock(objectType)) return (fflib_IDomain) getMock(objectType); + if (domainFactory == null) loadBindings(); - List bindings = resolver.byObject(objectType) - .byType(fflib_AppBindingType.Domain) - .resolve(); - - if (bindings.isEmpty()) - throw new DeveloperException('Unable to find domain binding for ' + objectType); - - System.Type domainImplementationType = bindings.get(0).getImplementationType(); - - Object instance = domainImplementationType.newInstance(); - - if (!(instance instanceof fflib_IDomainConstructor)) - throw new DeveloperException( - String.format( - 'Domain implementation {0} should be an instance of fflib_IDomainConstructor', - new List { domainImplementationType.getName() } - ) - ); - - return ((fflib_IDomainConstructor) domainImplementationType.newInstance()) - .construct(objects); + return this.domainFactory.newInstance(objects, objectType); } public fflib_IDomain newInstance(List records, SObjectType domainSObjectType) @@ -106,22 +95,47 @@ public virtual class fflib_DynamicDomainFactory public void setMock(fflib_ISObjectDomain mockDomain) { - super.setMock(mockDomain.getType(), mockDomain); + if (domainFactory == null) loadBindings(); + + this.domainFactory.setMock(mockDomain); } public void setMock(Schema.SObjectType sObjectType, fflib_ISObjectDomain mockDomain) { - super.setMock(sObjectType, mockDomain); + if (domainFactory == null) loadBindings(); + + this.domainFactory.setMock(sObjectType, mockDomain); } public void setMock(fflib_IDomain mockDomain) { - super.setMock(mockDomain.getType(), mockDomain); + if (domainFactory == null) loadBindings(); + + this.domainFactory.setMock(mockDomain); } public void setMock(Object domainType, fflib_IDomain mockDomain) { - super.setMock(domainType, mockDomain); + if (domainFactory == null) loadBindings(); + + this.domainFactory.setMock(domainType, mockDomain); + } + + private void loadBindings() + { + fflib_IAppBindings appBindings = new fflib_AppBindings(resolver.resolve()); + + // If a package name is provide we should filter on package name + if (String.isNotBlank(this.packageName)) + { + appBindings = appBindings.selectByPackageName(this.packageName); + } + + Map constructorByObject = + appBindings.selectByType(fflib_AppBindingType.Domain) + .getImplementationByBindingObject(); + + this.domainFactory = new fflib_ClassicDomainFactory(this.selectorFactory, constructorByObject); } public class DeveloperException extends Exception {} diff --git a/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_DynamicSelectorFactory.cls b/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_DynamicSelectorFactory.cls index 27c4a97..65eec43 100644 --- a/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_DynamicSelectorFactory.cls +++ b/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_DynamicSelectorFactory.cls @@ -32,86 +32,66 @@ public virtual class fflib_DynamicSelectorFactory extends fflib_DynamicAppFactory implements fflib_ISelectorFactory { - public static final fflib_AppBindingType SELECTOR_BINDING_TYPE = fflib_AppBindingType.Selector; - - protected Map mockSelectorImplByObjectType = new Map(); + protected fflib_ClassicSelectorFactory selectorFactory; public fflib_DynamicSelectorFactory(fflib_IAppBindingResolver resolver) + { + this(resolver, null); + } + + public fflib_DynamicSelectorFactory(fflib_IAppBindingResolver resolver, String packageName) { this.resolver = resolver; + this.packageName = packageName; } public fflib_ISObjectSelector newInstance(SObjectType sObjectType) { - if (hasMock(sObjectType)) return (fflib_ISObjectSelector) getMock(sObjectType); + if (this.selectorFactory == null) loadBindings(); - List bindings = resolver - .byType(SELECTOR_BINDING_TYPE) - .byObject(sObjectType) - .bySharingMode(sharingMode) - .resolve(); - - if (bindings.isEmpty()) - throw new DeveloperException( - String.format( - 'Unable to find selector binding for {0} with sharing mode {1}', - new List - { - sObjectType.getDescribe().getName(), - sharingMode.name() - } - ) - ); - - return (fflib_ISObjectSelector) bindings.get(0).newImplInstance(); + return this.selectorFactory.newInstance(sObjectType); } public List selectById(Set recordIds) { - if (null == recordIds || recordIds.size() == 0) - throw new fflib_Application.DeveloperException('Invalid record Id\'s set'); + if (this.selectorFactory == null) loadBindings(); - return selectById(recordIds, new List(recordIds)[0].getSObjectType()); + return this.selectorFactory.selectById(recordIds); } public List selectById(Set recordIds, SObjectType sObjectType) { - if (null == recordIds || recordIds.size() == 0) - throw new fflib_Application.DeveloperException('Invalid record Id\'s set'); + if (this.selectorFactory == null) loadBindings(); - return newInstance(sObjectType) - .selectSObjectsById(recordIds); + return this.selectorFactory.selectById(recordIds, sObjectType); } public List selectByRelationship(List relatedRecords, SObjectField relationshipField) { - Set relatedIds = - new RelatedRecordsDomain(relatedRecords) - .getRelatedIds(relationshipField); + if (this.selectorFactory == null) loadBindings(); - if (relatedIds.isEmpty()) return new List(); - - return selectById(relatedIds); + return this.selectorFactory.selectByRelationship(relatedRecords, relationshipField); } public void replaceWith(SObjectType sObjectType, Type replacementImplType) { - resolver.byType(fflib_AppBindingType.Selector) - .byObject(sObjectType) - .bySharingMode(this.sharingMode) - .resolve() - .get(0) - .setImplementationType(replacementImplType); + if (this.selectorFactory == null) loadBindings(); + + this.selectorFactory.replaceWith(sObjectType, replacementImplType); } public void setMock(fflib_ISObjectSelector selectorInstance) { - setMock(selectorInstance.sObjectType(), selectorInstance); + if (this.selectorFactory == null) loadBindings(); + + this.selectorFactory.setMock(selectorInstance); } public void setMock(SObjectType sObjectType, fflib_ISObjectSelector selectorInstance) { - super.setMock(sObjectType, selectorInstance); + if (this.selectorFactory == null) loadBindings(); + + this.selectorFactory.setMock(sObjectType, selectorInstance); } public fflib_DynamicSelectorFactory setSharingMode(fflib_SharingMode sharingMode) @@ -120,17 +100,22 @@ public virtual class fflib_DynamicSelectorFactory return this; } - private class RelatedRecordsDomain extends fflib_SObjects2 + private void loadBindings() { - public RelatedRecordsDomain(List records) + fflib_IAppBindings appBindings = new fflib_AppBindings(resolver.resolve()); + + // If a package name is provide we should filter on package name + if (String.isNotBlank(this.packageName)) { - super(records); + appBindings = appBindings.selectByPackageName(this.packageName); } - public Set getRelatedIds(Schema.SObjectField relationshipField) - { - return getIdFieldValues(relationshipField); - } + Map implementationBySObjectType = + appBindings.selectByType(fflib_AppBindingType.Selector) + .selectBySharingMode(this.sharingMode) + .getImplementationBySObjectType(); + + this.selectorFactory = new fflib_ClassicSelectorFactory(implementationBySObjectType); } public class DeveloperException extends Exception {} diff --git a/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_DynamicServiceFactory.cls b/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_DynamicServiceFactory.cls index a956232..a0808a8 100644 --- a/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_DynamicServiceFactory.cls +++ b/sfdx-source/apex-extensions/main/application/dynamic/classes/fflib_DynamicServiceFactory.cls @@ -32,53 +32,38 @@ public virtual class fflib_DynamicServiceFactory extends fflib_DynamicAppFactory implements fflib_IServiceFactory { - public static final fflib_AppBindingType SERVICE_BINDING_TYPE = fflib_AppBindingType.Service; - - protected Map mockServiceImplByObjectType = new Map(); + protected fflib_ClassicServiceFactory serviceFactory; public fflib_DynamicServiceFactory(fflib_IAppBindingResolver resolver) + { + this(resolver, null); + } + + public fflib_DynamicServiceFactory(fflib_IAppBindingResolver resolver, String packageName) { this.resolver = resolver; + this.packageName = packageName; } public Object newInstance(Type serviceInterfaceType) { - if (hasMock(serviceInterfaceType)) return getMock(serviceInterfaceType); + if (serviceFactory == null) loadBindings(); - List bindings = resolver - .byType(SERVICE_BINDING_TYPE) - .byInterfaceType(serviceInterfaceType) - .bySharingMode(sharingMode) - .resolve(); - - if (bindings.isEmpty()) - throw new DeveloperException( - String.format( - 'Unable to find service binding for {0} with sharing more {1}', - new List - { - serviceInterfaceType.getName(), - sharingMode.name() - } - ) - ); - - return bindings.get(0).newImplInstance(); + return this.serviceFactory.newInstance(serviceInterfaceType); } public void replaceWith(Type serviceInterfaceType, Type replacementImplType) { - resolver.byType(SERVICE_BINDING_TYPE) - .byInterfaceType(serviceInterfaceType) - .bySharingMode(sharingMode) - .resolve() - .get(0) // TODO - validate that there are any resolved bindings - .setImplementationType(replacementImplType); + if (serviceFactory == null) loadBindings(); + + this.serviceFactory.replaceWith(serviceInterfaceType, replacementImplType); } public void setMock(Type serviceInterfaceType, Object serviceImpl) { - super.setMock(serviceInterfaceType, serviceImpl); + if (serviceFactory == null) loadBindings(); + + this.serviceFactory.setMock(serviceInterfaceType, serviceImpl); } public fflib_DynamicServiceFactory setSharingMode(fflib_SharingMode sharingMode) @@ -87,5 +72,22 @@ public virtual class fflib_DynamicServiceFactory return this; } + private void loadBindings() + { + fflib_IAppBindings appBindings = new fflib_AppBindings(resolver.resolve()); + + // If a package name is provide we should filter on package name + if (String.isNotBlank(this.packageName)) + { + appBindings = appBindings.selectByPackageName(this.packageName); + } + + Map implementationByInterface = + appBindings.selectByType(fflib_AppBindingType.Service) + .getImplementationByInterface(); + + this.serviceFactory = new fflib_ClassicServiceFactory(implementationByInterface); + } + public class DeveloperException extends Exception {} } \ No newline at end of file diff --git a/sfdx-source/apex-extensions/main/application/dynamic/classes/interfaces/fflib_IAppBinding.cls b/sfdx-source/apex-extensions/main/application/dynamic/classes/interfaces/fflib_IAppBinding.cls index 345f9df..29d6c26 100644 --- a/sfdx-source/apex-extensions/main/application/dynamic/classes/interfaces/fflib_IAppBinding.cls +++ b/sfdx-source/apex-extensions/main/application/dynamic/classes/interfaces/fflib_IAppBinding.cls @@ -56,6 +56,10 @@ public interface fflib_IAppBinding * @return Returns the Namespace for the binding */ String getNamespacePrefix(); + /** + * @return Returns the Application Package Name for the binding + */ + String getPackageName(); /** * @return Returns the number of the order sequence in which the binding should be returned @@ -127,6 +131,13 @@ public interface fflib_IAppBinding */ fflib_IAppBinding setNamespacePrefix(String namespacePrefix); + /** + * @param applicationPackageName The name of the Application Second Generation Package + * + * @return An instance of itself to enable method chaining + */ + fflib_IAppBinding setPackageName(String applicationPackageName); + /** * Set the order number so that the resolver can sort the bindings. * The higher the number, the more priority. diff --git a/sfdx-source/apex-extensions/main/application/dynamic/classes/interfaces/fflib_IAppBindingResolver.cls b/sfdx-source/apex-extensions/main/application/dynamic/classes/interfaces/fflib_IAppBindingResolver.cls index 53e5cdb..187f443 100644 --- a/sfdx-source/apex-extensions/main/application/dynamic/classes/interfaces/fflib_IAppBindingResolver.cls +++ b/sfdx-source/apex-extensions/main/application/dynamic/classes/interfaces/fflib_IAppBindingResolver.cls @@ -37,5 +37,6 @@ public interface fflib_IAppBindingResolver fflib_IAppBindingResolver byInterfaceType(System.Type interfaceType); fflib_IAppBindingResolver bySharingMode(fflib_SharingMode sharingMode); fflib_IAppBindingResolver byNamespacePrefix(String namespacePrefix); + fflib_IAppBindingResolver byPackageName(String packageName); List resolve(); } \ No newline at end of file diff --git a/sfdx-source/apex-extensions/main/application/dynamic/classes/interfaces/fflib_IAppBindings.cls b/sfdx-source/apex-extensions/main/application/dynamic/classes/interfaces/fflib_IAppBindings.cls index 381a4cd..edce326 100644 --- a/sfdx-source/apex-extensions/main/application/dynamic/classes/interfaces/fflib_IAppBindings.cls +++ b/sfdx-source/apex-extensions/main/application/dynamic/classes/interfaces/fflib_IAppBindings.cls @@ -34,13 +34,17 @@ public interface fflib_IAppBindings void addBinding(fflib_IAppBinding binding); void addBindings(List bindings); + List getBindings(); + Map getImplementationByBindingObject(); + Map getImplementationByInterface(); + Map getImplementationBySObjectType(); + List getImplementations(); + fflib_IAppBindings selectByObject(Object bindingObject); fflib_IAppBindings selectBySequence(Decimal sequence); fflib_IAppBindings selectByType(fflib_AppBindingType bindingType); fflib_IAppBindings selectByInterfaceType(System.Type interfaceType); fflib_IAppBindings selectBySharingMode(fflib_SharingMode sharingMode); fflib_IAppBindings selectByNamespacePrefix(String namespacePrefix); - - List getBindings(); - List getImplementations(); + fflib_IAppBindings selectByPackageName(String packageName); } \ No newline at end of file diff --git a/sfdx-source/apex-extensions/main/application/dynamic/layouts/fflib_AppBinding__mdt-Binding Layout.layout-meta.xml b/sfdx-source/apex-extensions/main/application/dynamic/layouts/fflib_AppBinding__mdt-Binding Layout.layout-meta.xml index 96e3a3a..e20ce5c 100644 --- a/sfdx-source/apex-extensions/main/application/dynamic/layouts/fflib_AppBinding__mdt-Binding Layout.layout-meta.xml +++ b/sfdx-source/apex-extensions/main/application/dynamic/layouts/fflib_AppBinding__mdt-Binding Layout.layout-meta.xml @@ -18,6 +18,10 @@ Required Type__c + + Edit + ApplicationPackage__c + diff --git a/sfdx-source/apex-extensions/main/application/dynamic/layouts/fflib_ApplicationPackage__mdt-Application Package Layout.layout-meta.xml b/sfdx-source/apex-extensions/main/application/dynamic/layouts/fflib_ApplicationPackage__mdt-Application Package Layout.layout-meta.xml new file mode 100644 index 0000000..4df42f6 --- /dev/null +++ b/sfdx-source/apex-extensions/main/application/dynamic/layouts/fflib_ApplicationPackage__mdt-Application Package Layout.layout-meta.xml @@ -0,0 +1,67 @@ + + + + false + false + true + + + + Required + MasterLabel + + + Required + DeveloperName + + + + + Edit + IsProtected + + + Required + NamespacePrefix + + + + + + false + false + true + + + + Readonly + CreatedById + + + + + Readonly + LastModifiedById + + + + + + false + false + false + + + + + MasterLabel + DeveloperName + NamespacePrefix + fflib_AppBinding__mdt.ApplicationPackage__c + + false + false + false + false + false + diff --git a/sfdx-source/apex-extensions/main/application/dynamic/objects/fflib_AppBinding__mdt/fields/ApplicationPackage__c.field-meta.xml b/sfdx-source/apex-extensions/main/application/dynamic/objects/fflib_AppBinding__mdt/fields/ApplicationPackage__c.field-meta.xml new file mode 100644 index 0000000..8855a33 --- /dev/null +++ b/sfdx-source/apex-extensions/main/application/dynamic/objects/fflib_AppBinding__mdt/fields/ApplicationPackage__c.field-meta.xml @@ -0,0 +1,13 @@ + + + ApplicationPackage__c + false + DeveloperControlled + + fflib_ApplicationPackage__mdt + Application Bindings + ApplicationBindings + false + MetadataRelationship + false + diff --git a/sfdx-source/apex-extensions/main/application/dynamic/objects/fflib_ApplicationPackage__mdt/fflib_ApplicationPackage__mdt.object-meta.xml b/sfdx-source/apex-extensions/main/application/dynamic/objects/fflib_ApplicationPackage__mdt/fflib_ApplicationPackage__mdt.object-meta.xml new file mode 100644 index 0000000..cba55be --- /dev/null +++ b/sfdx-source/apex-extensions/main/application/dynamic/objects/fflib_ApplicationPackage__mdt/fflib_ApplicationPackage__mdt.object-meta.xml @@ -0,0 +1,7 @@ + + + Define individual packages if your application contains multiple second generation packages (2GP) + + Application Packages + Public + diff --git a/sfdx-source/apex-extensions/main/default/classes/utils/fflib_MockSObjectUtil.cls b/sfdx-source/apex-extensions/main/default/classes/utils/fflib_MockSObjectUtil.cls index e3d089b..51fc38a 100644 --- a/sfdx-source/apex-extensions/main/default/classes/utils/fflib_MockSObjectUtil.cls +++ b/sfdx-source/apex-extensions/main/default/classes/utils/fflib_MockSObjectUtil.cls @@ -111,6 +111,5 @@ public with sharing class fflib_MockSObjectUtil Lead record = new Lead(Id = fflib_IDGenerator.generate(Schema.Lead.SObjectType)); SObject result = addFieldValue(record, Lead.ConvertedDate, today); System.assertEquals(today, result.get(Lead.ConvertedDate)); - System.debug('result: '+result); } } \ No newline at end of file diff --git a/sfdx-source/apex-extensions/tests/classes/application/fflib_DynamicDomainFactoryTest.cls b/sfdx-source/apex-extensions/tests/classes/application/fflib_DynamicDomainFactoryTest.cls index fbeaf0d..9e7de58 100644 --- a/sfdx-source/apex-extensions/tests/classes/application/fflib_DynamicDomainFactoryTest.cls +++ b/sfdx-source/apex-extensions/tests/classes/application/fflib_DynamicDomainFactoryTest.cls @@ -31,15 +31,24 @@ @IsTest(IsParallel=true) public class fflib_DynamicDomainFactoryTest { + private static final SObjectType ACCOUNT_OBJECT_TYPE = Schema.Account.SObjectType; + private static final String PACKAGE_FORCE_APP = 'force-app'; + private static final String PACKAGE_OTHER_APP = 'other-app'; + private static final fflib_IAppBindingResolver bindingResolver = new fflib_AppBindingResolver(); - private static final fflib_DynamicDomainFactory Domain = new fflib_DynamicDomainFactory( bindingResolver, - fflib_DynamicSelectorFactoryTest.Selector); - private static final SObjectType ACCOUNT_OBJECT_TYPE = Schema.Account.SObjectType; + fflib_DynamicSelectorFactoryTest.Selector, + PACKAGE_FORCE_APP); + + private static final fflib_DynamicDomainFactory OtherDomain = + new fflib_DynamicDomainFactory( + bindingResolver, + fflib_DynamicSelectorFactoryTest.Selector, + PACKAGE_OTHER_APP); @IsTest static void itShouldReturnDomain() @@ -107,6 +116,19 @@ public class fflib_DynamicDomainFactoryTest System.Assert.isTrue(instanceB.getRecords().isEmpty()); } + @IsTest + static void itShouldReturnTheRightDomainForThePackage() + { + fflib_AppBindingsSelector.SELECTOR_IMPL_TYPE = AppBindingsSelectorMock.class; + + final List records = generateAccountRecords(); + + System.Test.startTest(); + fflib_IDomain otherDomain = OtherDomain.newInstance(records); + System.Test.stopTest(); + + System.Assert.isTrue(otherDomain instanceof fflib_SObjects2, 'Incorrect returned instance'); + } private static List generateAccountRecords() { @@ -128,18 +150,46 @@ public class fflib_DynamicDomainFactoryTest } } + public class OtherDomainConstructor implements fflib_IDomainConstructor + { + public fflib_IDomain construct(List objects) + { + return new fflib_SObjects2((List) objects); + } + } + private class AppBindingsSelectorMock extends fflib_AppBindingsSelector { public override List selectAll() { + fflib_ApplicationPackage__mdt forceApp = + new fflib_ApplicationPackage__mdt( + Id = fflib_IDGenerator.generate(fflib_ApplicationPackage__mdt.SObjectType), + DeveloperName = PACKAGE_FORCE_APP); + fflib_ApplicationPackage__mdt otherApp = + new fflib_ApplicationPackage__mdt( + Id = fflib_IDGenerator.generate(fflib_ApplicationPackage__mdt.SObjectType), + DeveloperName = PACKAGE_OTHER_APP); + return new List { new fflib_AppBinding__mdt( + ApplicationPackage__c = forceApp.Id, + ApplicationPackage__r = forceApp, Type__c = 'Domain', BindingObject__c = '', BindingObjectAlternate__c = ACCOUNT_OBJECT_TYPE.getDescribe().getName(), ImplementationType__c = MyDomainConstructor.class.getName(), SharingMode__c = 'None' + ), + new fflib_AppBinding__mdt( + ApplicationPackage__c = otherApp.Id, + ApplicationPackage__r = otherApp, + Type__c = 'Domain', + BindingObject__c = '', + BindingObjectAlternate__c = ACCOUNT_OBJECT_TYPE.getDescribe().getName(), + ImplementationType__c = OtherDomainConstructor.class.getName(), + SharingMode__c = 'None' ) }; } diff --git a/sfdx-source/apex-extensions/tests/classes/domains/fflib_SObjects2Test.cls b/sfdx-source/apex-extensions/tests/classes/domains/fflib_SObjects2Test.cls index 5cd5edf..527c32b 100644 --- a/sfdx-source/apex-extensions/tests/classes/domains/fflib_SObjects2Test.cls +++ b/sfdx-source/apex-extensions/tests/classes/domains/fflib_SObjects2Test.cls @@ -153,7 +153,6 @@ private class fflib_SObjects2Test } ); System.Test.stopTest(); - System.debug('result: ' + JSON.serializePretty(result)); // THEN it should return the AccountId By CaseId System.Assert.areEqual(1, result.size(), 'Expected one account'); @@ -194,7 +193,6 @@ private class fflib_SObjects2Test } ); System.Test.stopTest(); - System.debug('result: ' + JSON.serializePretty(result)); // THEN it should return the AccountId By CaseId System.Assert.areEqual(1, result.size(), 'Expected one account'); diff --git a/sfdx-source/apex-extensions/tests/classes/logger/fflib_LogEventAppenderTest.cls b/sfdx-source/apex-extensions/tests/classes/logger/fflib_LogEventAppenderTest.cls index 02060d9..47bd60f 100644 --- a/sfdx-source/apex-extensions/tests/classes/logger/fflib_LogEventAppenderTest.cls +++ b/sfdx-source/apex-extensions/tests/classes/logger/fflib_LogEventAppenderTest.cls @@ -91,7 +91,6 @@ private class fflib_LogEventAppenderTest fflib_LogEventAppender eventAppender = new fflib_LogEventAppender(); fflib_LogLevelFilter__c orgSettings = fflib_LogLevelFilter__c.getOrgDefaults(); - System.debug(orgSettings); orgSettings.LogLevel__c = 'INFO'; insert orgSettings; diff --git a/sfdx-source/apex-extensions/tests/classes/logger/fflib_LoggerTest.cls b/sfdx-source/apex-extensions/tests/classes/logger/fflib_LoggerTest.cls index ad24f53..be8a901 100644 --- a/sfdx-source/apex-extensions/tests/classes/logger/fflib_LoggerTest.cls +++ b/sfdx-source/apex-extensions/tests/classes/logger/fflib_LoggerTest.cls @@ -96,7 +96,6 @@ private class fflib_LoggerTest // THEN - It should be appended to the logAppender final List result = APPENDER_MOCK .getAppendedMessages(System.LoggingLevel.DEBUG); - System.debug(result); System.Assert.areEqual(1, result.size(), 'Expected only one error'); System.Assert.isTrue(result.get(0).startsWith(ERROR_MESSAGE_FORMATTED_WITH_EXCEPTION), 'Incorrect returned error message'); }