fflib-apex-common icon indicating copy to clipboard operation
fflib-apex-common copied to clipboard

New Selector Pattern

Open ejwill opened this issue 7 years ago • 2 comments

@afawcett I said earlier in a different issue #75 that is now closed that we developed a selector pattern that allows us to work with different fields based on the call to the selector. We have been using it primarily to lookup all fields, updateable fields, or a list of external ids

We accomplish this by setting an enum before we call one of the selector methods.

You can see an example of this in the code below of an Account Selector

public class AccountSelector extends fflib_SObjectSelector {

	/**
	* @description Get the type of the sObject
	*/ 
	public Schema.SObjectType getSObjectType(){
		return Account.sObjectType;
	}

	//Enum used to change the fieldnames selected by the selector
    public enum SelectorOption {ALL, UPDATEABLE, STANDARD}
    //Variable used to store the SelectorOption enum value
    public SelectorOption selectorOptionValue = SelectorOption.STANDARD;

	public List<Schema.SObjectField> getSObjectFieldList(){
		if (selectorOptionValue.name() == SelectorOption.ALL.name()) {
            //Select all fields on the object
			return Account.sObjectType.getDescribe().fields.getMap().values();
		} else if (selectorOptionValue.name() == SelectorOption.UPDATEABLE.name()) {
            //select only the updateable fields
			List<Schema.SObjectField> editableFields = new List<Schema.SObjectField>();
			List<Schema.SObjectField> allFields = Account.sObjectType.getDescribe().fields.getMap().values();
			for(Schema.SObjectField field : allFields) {
				Schema.DescribeFieldResult fd = field.getDescribe();
				if (fd.isUpdateable()) {
					editableFields.add(field);
				}
			}
            
			return editableFields;
		} else {
            //Default or STANDARD enum option
			return new List<Schema.SObjectField> {
				Account.Id,
				Account.FirstName,
				Account.MiddleName,
				Account.LastName,
				Account.Suffix,
				Account.PersonEmail,
				Account.Phone,
				Account.PersonBirthdate
			};
		}
	}

the call to the selector looks like this

AccountSelector selector = new AccountSelector();
selector.selectorOptionValue = AccountSelector.SelectorOption.ALL;
List<Account> accounts = selector.selectAccountsById(new Set<Id>{accountId});

There are probably areas for improvement and there might be a way to code this into fflib if there is value in that.

Let me know what you think

ejwill avatar Dec 13 '17 16:12 ejwill

Thanks for sharing. I am less keen on state based configurations effecting the behaviour of standard methods. If the selector instance is passed around or used later in the execution it becomes less clear how its been configured. Have you considered the decorator pattern? https://www.journaldev.com/1540/decorator-design-pattern-in-java-example

afawcett avatar Dec 31 '17 03:12 afawcett

I agree with Andy -- if you want a specific Selector to return only updateable fields, then the usage would be AccountsSelector.newInstance().selectAllUpdateableById(someIdSet) and let the selector method itself resolve from the Describe those fields that are updateable

cropredyHelix avatar Jan 16 '18 19:01 cropredyHelix