Add primitive domains and criteria feature

This commit is contained in:
Wim Velzeboer
2021-06-24 12:15:06 +01:00
parent 5346864513
commit 910aa6e04c
39 changed files with 3308 additions and 3 deletions
+107
View File
@@ -0,0 +1,107 @@
# fflib-apex-extensions
## Criteria based filter for Domains and Selectors
A common criteria based filter for domains and SOQL condition generator for Selectors.
It is very often that we have the same filters in domain and elector classes. The Criteria feature provides a solution that extracts the filter conditions into a single reusable criteria class. These filter conditions are dynamic and can be evaluated in run-time, or be converted to a SOQL statement condition.
```
+ - - - - - - - - +
+ - - - | Filter Criteria | - - - +
| + - - - - - - - - + |
| |
| |
+ - - - - - - - + + - - - - - - - +
| Domain | | Selector |
+ - - - - - - - + + - - - - - - - +
```
Here is an example on how its used:
The criteria class is the place where all the filter conditions are stored for a single SObjectType.
```apex
public with sharing class AccountCriteria extends fflib_Criteria
{
public AccountCriteria ShippingCountryEquals(String countryName)
{
equalTo(Schema.Account.ShippingCountry, countryName);
return this;
}
public AccountCriteria NumberOfEmployeesGreaterThan(Integer numberOfEmployees)
{
greaterThan(Schema.Account.NumberOfEmployees, numberOfEmployees);
return this;
}
}
```
How it can be applied in a Domain class:
```apex
public with sharing class Accounts
extends SObjects
implements IAccounts
{
private static final Integer LARGE_ACCOUNT_EMPLOYEE_NUMBERS = 500;
public Accounts getByCountry(String countryName)
{
return new Accounts(
getRecords(
new AccountCriteria().ShippingCountryEquals(countryName)
)
);
}
public Accounts getByNumberOfEmployeesGreaterThan(Integer numberOfEmployees)
{
return new Accounts(
getRecords(
new AccountCriteria().NumberOfEmployeesGreaterThan(numberOfEmployees)
)
);
}
public Accounts getByLargeAccountsInCountry(String countryName)
{
return new Accounts(
getRecords(
new AccountCriteria()
.ShippingCountryEquals(countryName)
.NumberOfEmployeesGreaterThan(numberOfEmployees)
)
);
}
}
```
In this example we see three filters; one for country, another for checking minimal number of employees and a third that combines the first two.
It is important not to have a filter with too many conditions.
One filter criteria condition per method is ideal to have maximum flexibility and a high chance on code-reuse.
How the same filters can be used in the Selector class:
```apex
public with sharing class AccountsSelector
extends fflib_SObjectSelector
implements IAccountsSelector
{
...
public List<Account> selectByCountryWithMinimalNumberOfEmployees(String country, Integer minimalNumberOfEmployees)
{
return (List<Account>) Database.query(
newQueryFactory()
.setCondition(
new AccountCriteria()
.ShippingCountryEquals(country)
.NumberOfEmployeesGreaterThan(minimalNumberOfEmployees)
);
}
...
}
```
With this feature developers can avoid a lot of code duplications.
Hope you like it!
+22
View File
@@ -0,0 +1,22 @@
# fflib-apex-extensions
## Primitive Domains
A huge benefit of using primitive domains, is that you write less code.
Instead of:
```apex
List<String> myStrings = getSomeStrings();
```
You can write:
```apex
Strings myStrings = getSomeString();
```
It is a small thing, but it makes things looks much nicer.
One other benefit is that you can encapsulate more logic as Lists. You can see these lists as a Domain.
Take a look at the SObjects primitive domain, it is the new source for extending domain classes.