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
+9
View File
@@ -37,9 +37,18 @@ $RECYCLE.BIN/
# Local environment variables
.env
# Ignore VSCode config files
.vscode/
# Ignore Intellij config files
.idea/
*.iml
*.iws
IlluminatedCloud/
.project.license
temp/
# Ignore other fflib packages
sfdx-source/apex-mocks
sfdx-source/apex-common
sfdx-source/apex-extensions-examples
+13 -1
View File
@@ -1,2 +1,14 @@
# fflib-apex-extensions
Extension for the fflib-apex-common Library. Introducing many advanced features on top of the Apex Enterprise Patterns
Extensions for the fflib-apex-common Library. Introducing many advanced features on top of the Apex Enterprise Patterns
**Dependencies:**<br/>
This extension package is dependent on the following packages:
- [fflib-apex-mocks](https://github.com/apex-enterprise-patterns/fflib-apex-mocks)
- [fflib-apex-common](https://github.com/apex-enterprise-patterns/fflib-apex-common)
## Contents
This extension pack includes the following features
- [Primitive domains](./docs/primitive-domains.md)
- [A common criteria based filter](./docs/criteria-based-filter.md) for Domains and Selector
+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.
+1 -1
View File
@@ -1,7 +1,7 @@
{
"packageDirectories": [
{
"path": "sfdx-source/force-app",
"path": "sfdx-source/apex-extensions",
"default": true
}
],
@@ -0,0 +1,178 @@
/**
* File Name: fflib_Comparator
* Description: Comparator for primitive values
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public with sharing class fflib_Comparator
{
public static Boolean compareTo(Object object1, fflib_Operator operator, Object object2)
{
Integer result = compare(object1, object2);
if (operator == fflib_Operator.EQUALS && result == 0)
return true;
else if (operator == fflib_Operator.NOT_EQUALS && result != 0)
return true;
else if (operator == fflib_Operator.LESS_THAN && result == -1)
return true;
else if (operator == fflib_Operator.LESS_THAN_OR_EQUAL_TO && result != 1)
return true;
else if (operator == fflib_Operator.GREATER_THAN && result == 1)
return true;
else if (operator == fflib_Operator.GREATER_THAN_OR_EQUAL_TO && result != -1)
return true;
else
return false;
}
public static Integer compare(Object object1, Object object2)
{
if (object1 == null && object2 == null)
return 0;
else if (object1 == null)
return -1;
else if (object2 == null)
return 1;
else if (object1 instanceof Boolean && object2 instanceof Boolean)
return compare((Boolean) object1, (Boolean) object2);
else if (object1 instanceof Date && object2 instanceof Date)
return compare((Date) object1, (Date) object2);
else if (object1 instanceof Datetime && object2 instanceof Datetime)
return compare((Datetime) object1, (Datetime) object2);
else if (object1 instanceof Integer && object2 instanceof Integer)
return compare((Integer) object1, (Integer) object2);
else if (object1 instanceof Long && object2 instanceof Long)
return compare((Long) object1, (Long) object2);
else if (object1 instanceof Double && object2 instanceof Double)
return compare((Double) object1, (Double) object2);
else if (object1 instanceof Time && object2 instanceof Time)
return compare((Time) object1, (Time) object2);
else if (object1 instanceof String && object2 instanceof String)
return compare((String) object1, (String) object2);
else
throw new IllegalArgumentException(
'Both arguments must be type Boolean, Date, Datetime, Decimal, Double, ID, Integer, Long, Time, or String');
}
public static Integer compare(Boolean b1, Boolean b2)
{
if (!b1 && b2) return -1;
else if (b1 == b2) return 0;
else return 1;
}
public static Integer compare(Date d1, Date d2)
{
if (d1 < d2) return -1;
else if (d1 == d2) return 0;
else return 1;
}
public static Integer compare(Datetime d1, Datetime d2)
{
if (d1 < d2) return -1;
else if (d1 == d2) return 0;
else return 1;
}
public static Integer compare(Double d1, Double d2)
{
if (d1 < d2) return -1;
else if (d1 == d2) return 0;
else return 1;
}
public static Integer compare(Integer i1, Integer i2)
{
if (i1 < i2) return -1;
else if (i1 == i2) return 0;
else return 1;
}
public static Integer compare(Long l1, Long l2)
{
if (l1 < l2) return -1;
else if (l1 == l2) return 0;
else return 1;
}
public static Integer compare(String s1, String s2)
{
if (s1 < s2) return -1;
else if (s1 == s2) return 0;
else return 1;
}
public static Integer compare(Time t1, Time t2)
{
return compare('' + t1, '' + t2);
}
/**
* @description check if a Set contains a value
* @author architect ir. Wim G.J. Velzeboer
* @param object1 - Object - a Set of objects
* @param object2 - Object - the object to check if its a member of the Set
* @return Boolean - TRUE if the object is a member of the Set
*/
public static Boolean contains(Object object1, Object object2)
{
if (object1 == null && object2 == null)
return true;
else if (object1 == null)
return false;
else if (object2 == null)
return false;
else if (object1 instanceof set<Date> && object2 instanceof Date)
return ((set<Date>) object1).contains((date) object2);
else if (object1 instanceof set<Datetime> && object2 instanceof Datetime)
return ((set<Datetime>) object1).contains((Datetime) object2);
else if (object1 instanceof set<Double> && object2 instanceof Double)
return ((set<Double>) object1).contains((Double) object2);
else if (object1 instanceof set<Id> && object2 instanceof Id)
return ((set<Id>) object1).contains((Id) object2);
else if (object1 instanceof set<Integer> && object2 instanceof Integer)
return ((set<Integer>) object1).contains((Integer) object2);
else if (object1 instanceof set<Long> && object2 instanceof Long)
return ((set<Long>) object1).contains((Long) object2);
else if (object1 instanceof set<Object>)
return ((set<Object>) object1).contains((Object) object2);
else if (object1 instanceof set<Time> && object2 instanceof Time)
return ((set<Time>) object1).contains((Time) object2);
else if (object1 instanceof set<String> && object2 instanceof String)
return ((set<String>) object1).contains((String) object2);
else
throw new IllegalArgumentException(
'Both arguments must be type Date, Datetime, Decimal, Double, ID, Integer, Long, Object, Time, Object or String');
}
public class IllegalArgumentException extends Exception {
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>41.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,697 @@
/**
* File Name: fflib_Criteria
* Description: A evaluator based on criteria
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual with sharing class fflib_Criteria
implements Evaluator
{
// Add brace when generated to SQL
private Boolean embraced = false;
// List to hold all evaluators
private List<Evaluator> evaluators;
// The type of comparator NONE | AND | OR
private String type;
/**
* populate private variables with default settings.
*/
public fflib_Criteria()
{
this.evaluators = new List<Evaluator>();
this.type = 'AND';
}
/**
* Changes the default comparator for each criteria to OR
*
* @return Instance of fflib_Criteria
*
* @example
* new fflib_Criteria()
* .orCriteria()
* .equalTo(Account.Name, 'Example')
* .equalTo(Account.AccountNumber, '1234567')
*
* Evaluates:
* Name = 'Example' OR AccountNumber = '1234567'
*/
public fflib_Criteria orCriteria()
{
this.type = 'OR';
return this;
}
/**
* Changes the default comparator for each criteria to AND.
* By default the comparator is set to AND,
* so this method should only be used in custom implementations extended from fflib_Criteria
*
* @return Instance of fflib_Criteria
*
* @example
* new MyCustomCriteria()
* .andCriteria()
* .equalTo(Account.Name, 'Example')
* .equalTo(Account.AccountNumber, '1234567')
*
* Evaluates:
* Name = 'Example' AND AccountNumber = '1234567'
*/
public fflib_Criteria andCriteria()
{
this.type = 'AND';
return this;
}
/**
* Adds a sub criteria with OR comparator
*
* @param subCriteria The condition of the sub criteria
*
* @return Instance of fflib_Criteria
*
* @example
* new fflib_Criteria()
* .equalTo(Account.Name, 'Example')
* .addOrCriteria(
* new fflib_Criteria()
* .equalTo(Account.AccountNumber, '0001')
* .equalTo(Account.AccountNumber, '0002'))
*
* Evaluates:
* Account.Name = 'Example' AND (Account.AccountNumber = '0001' OR Account.AccountNumber = '0002')
*/
public fflib_Criteria addOrCriteria(fflib_Criteria subCriteria)
{
subCriteria.orCriteria();
subCriteria.setEmbraced(true);
evaluators.add(subCriteria);
return this;
}
/**
* Adds a sub criteria with AND comparator
*
* @param subCriteria The condition of the sub criteria
*
* @return Instance of fflib_Criteria
*
* @example
* new fflib_Criteria()
* .orCriteria()
* .equalTo(Account.Name, 'Example')
* .addAndCriteria(
* new fflib_Criteria()
* .equalTo(Account.AccountNumber, '0001')
* .equalTo(Account.ShippingCountry, 'USA'))
*
* Evaluates:
* Name = 'Example' OR (AccountNumber = '0001' AND ShippingCountry = 'USA')
*/
public fflib_Criteria addAndCriteria(fflib_Criteria subCriteria)
{
subCriteria.andCriteria();
subCriteria.setEmbraced(true);
evaluators.add(subCriteria);
return this;
}
/**
* add an equal to criteria comparing a fields value to a given value
*
* @param field The sObjectField to evaluate
* @param value The value to be compared to the fields value
*
* @return Instance of fflib_Criteria
*
* @example
* new fflib_Criteria()
* .equalTo(Account.Name, 'Example')
*
* Evaluates:
* Name = 'Example'
*/
public fflib_Criteria equalTo(Schema.SObjectField field, Object value)
{
evaluators.add(new FieldEvaluator(field, fflib_Operator.EQUALS, value));
return this;
}
/**
* add a not equal to criteria while comparing a fields value to a given value
*
* @param field The sObjectField to evaluate
* @param value The value to be compared to the fields value
*
* @return Instance of fflib_Criteria
*
* @example
* new fflib_Criteria()
* .notEqualTo(Account.Name, 'Example')
*
* Evaluates:
* Name != 'Example'
*/
public fflib_Criteria notEqualTo(Schema.SObjectField field, Object value)
{
evaluators.add(new FieldEvaluator(field, fflib_Operator.NOT_EQUALS, value));
return this;
}
/**
* Evaluates the stored criteria based on the given SObject
*
* @param record The SObject to evaluate
*
* @return The Boolean result of the evaluated criteria
*/
public Boolean evaluate(Object record)
{
if (this.evaluators.isEmpty()) return true;
Boolean result = !(this.type == 'OR');
for (Evaluator evaluator : evaluators)
{
Boolean evaluateResult = evaluator.evaluate(record);
if (evaluateResult && (this.type == 'OR' || this.type == 'NONE'))
{
return true;
}
else if (!evaluateResult && this.type == 'AND')
{
return false;
}
}
return result;
}
/**
* compares the fields values to be greater or equal to the given value
* Evaluates to false if the field value is null
*
* @param field The field to use its value
* @param value The value to be compared to the fields value
*
* @return Instance of fflib_Criteria
*
* @example
* new fflib_Criteria()
* .greaterOrEqualTo(Account.AnnualRevenue, 54321)
*
* Evaluates:
* AnnualRevenue >= 54321
*/
public fflib_Criteria greaterOrEqualTo(Schema.SObjectField field, Object value)
{
evaluators.add(new FieldEvaluator(field, fflib_Operator.GREATER_THAN_OR_EQUAL_TO, value));
return this;
}
/**
* compares the fields values to be greater or equal to the given value
* Evaluates to false if the field value is null
*
* @param field The field to use its value
* @param value The value to be compared to the fields value
*
* @return Instance of fflib_Criteria
*
* @example
* new fflib_Criteria()
* .greaterThan(Account.AnnualRevenue, 54321)
*
* Evaluates:
* AnnualRevenue > 54321
*/
public fflib_Criteria greaterThan(Schema.SObjectField field, Object value)
{
evaluators.add(new FieldEvaluator(field, fflib_Operator.GREATER_THAN, value));
return this;
}
/**
* compares the fields values to be less or equal to the given value
* Evaluates to true if the field value is null
*
* @param field The field to use its value
* @param value The value to be compared to the fields value
*
* @return Instance of fflib_Criteria
*
* @example
* new fflib_Criteria()
* .lessOrEqualTo(Account.AnnualRevenue, 54321)
*
* Evaluates:
* AnnualRevenue <= 54321
*/
public fflib_Criteria lessOrEqualTo(Schema.SObjectField field, Object value)
{
evaluators.add(new FieldEvaluator(field, fflib_Operator.LESS_THAN_OR_EQUAL_TO, value));
return this;
}
/**
* compares the fields values to be greater or equal to the given value
* Evaluates to true if the field value is null
*
* @param field The field to use its value
* @param value The value to be compared to the fields value
*
* @return Instance of fflib_Criteria
*
* @example
* new fflib_Criteria()
* .lessThan(Account.AnnualRevenue, 54321)
*
* Evaluates:
* AnnualRevenue < 54321
*/
public fflib_Criteria lessThan(Schema.SObjectField field, Object value)
{
evaluators.add(new FieldEvaluator(field, fflib_Operator.LESS_THAN, value));
return this;
}
/**
* checks if the given sets contains the fields values
*
* @param field The field to use its value
* @param values The value to be compared to the fields value
*
* @return Instance of fflib_Criteria
*
* @example
* new fflib_Criteria()
* .inSet(Account.Type, new Set<Object>{'Customer', 'Competitor', 'Partner'})
*
* Evaluates:
* Account.Type IN ('Customer','Competitor','Partner')
*/
public fflib_Criteria inSet(Schema.SObjectField field, Set<Object> values)
{
return inSet(field, new Objects(values));
}
// Method overrides
public fflib_Criteria inSet(Schema.SObjectField field, Set<Date> values)
{
return inSet(field, new Dates(values));
}
public fflib_Criteria inSet(Schema.SObjectField field, Set<DateTime> values)
{
return inSet(field, new DateTimes(values));
}
public fflib_Criteria inSet(Schema.SObjectField field, Set<Decimal> values)
{
return inSet(field, new Decimals(values));
}
public fflib_Criteria inSet(Schema.SObjectField field, Set<Double> values)
{
return inSet(field, new Doubles(values));
}
public fflib_Criteria inSet(Schema.SObjectField field, Set<Id> values)
{
return inSet(field, new Ids(values));
}
public fflib_Criteria inSet(Schema.SObjectField field, Set<Integer> values)
{
return inSet(field, new Integers(values));
}
public fflib_Criteria inSet(Schema.SObjectField field, Set<Long> values)
{
return inSet(field, new Longs(values));
}
public fflib_Criteria inSet(Schema.SObjectField field, Set<String> values)
{
return inSet(field, new Strings(values));
}
/**
* checks if the given sets contains the fields values
*
* @param field The field to use its value
* @param values The value to be compared to the fields value
*
* @return Instance of fflib_Criteria
*
* @example
* new fflib_Criteria()
* .inSet(Account.Type, new Objects(new Set<Object>{'Customer', 'Competitor', 'Partner'}))
*
* Evaluates:
* Account.Type IN ('Customer','Competitor','Partner')
*/
public fflib_Criteria inSet(Schema.SObjectField field, Objects values)
{
evaluators.add(new FieldSetEvaluator(field, fflib_Operator.INx, values));
return this;
}
/**
* checks if the given sets contains the fields values
*
* @param field The field to use its value
* @param values The value to be compared to the fields value
*
* @return Instance of fflib_Criteria
*
* @example
* new fflib_Criteria()
* .notInSet(Account.Type, new Set<Object>{'Customer', 'Competitor', 'Partner'})
*
* Evaluates:
* Account.Type NOT IN ('Customer','Competitor','Partner')
*/
public fflib_Criteria notInSet(Schema.SObjectField field, Set<Date> values)
{
return notInSet(field, new Dates(values));
}
public fflib_Criteria notInSet(Schema.SObjectField field, Set<DateTime> values)
{
return notInSet(field, new DateTimes(values));
}
public fflib_Criteria notInSet(Schema.SObjectField field, Set<Decimal> values)
{
return notInSet(field, new Decimals(values));
}
public fflib_Criteria notInSet(Schema.SObjectField field, Set<Double> values)
{
return notInSet(field, new Doubles(values));
}
public fflib_Criteria notInSet(Schema.SObjectField field, Set<Id> values)
{
return notInSet(field, new Ids(values));
}
public fflib_Criteria notInSet(Schema.SObjectField field, Set<Integer> values)
{
return notInSet(field, new Integers(values));
}
public fflib_Criteria notInSet(Schema.SObjectField field, Set<Long> values)
{
return notInSet(field, new Longs(values));
}
public fflib_Criteria notInSet(Schema.SObjectField field, Set<String> values)
{
return notInSet(field, new Strings(values));
}
public fflib_Criteria notInSet(Schema.SObjectField field, Set<Object> values)
{
return notInSet(field, new Objects(values));
}
/**
* checks if the given sets contains the fields values
*
* @param field The field to use its value
* @param values The value to be compared to the fields value
*
* @return Instance of fflib_Criteria
*
* @example
* new fflib_Criteria()
* .notInSet(Account.Type, new Objects(new Set<Object>{'Customer', 'Competitor', 'Partner'}))
*
* Evaluates:
* Account.Type NOT IN ('Customer','Competitor','Partner')
*/
public fflib_Criteria notInSet(Schema.SObjectField field, Objects values)
{
evaluators.add(new FieldSetEvaluator(field, fflib_Operator.NOT_IN, values));
return this;
}
/**
* Generates the SOQL equivalent of the criteria provided
*
* @return The "where" part in the SOQL statement
*/
public String toSOQL()
{
if (this.evaluators.isEmpty()) return '';
String result = '';
for (Evaluator evaluator : this.evaluators)
{
if (result != '')
{
result += ' ' + this.type + ' ';
}
result += evaluator.toSOQL();
}
if (this.embraced) result = '(' + result + ')';
return result;
}
private static String operatorToString(fflib_Operator operator)
{
if (operator == fflib_Operator.EQUALS)
return '=';
else if (operator == fflib_Operator.NOT_EQUALS)
return '!=';
else if (operator == fflib_Operator.LESS_THAN)
return '<';
else if (operator == fflib_Operator.LESS_THAN_OR_EQUAL_TO)
return '<=';
else if (operator == fflib_Operator.GREATER_THAN)
return '>';
else if (operator == fflib_Operator.GREATER_THAN_OR_EQUAL_TO)
return '>=';
else if (operator == fflib_Operator.LIKEx)
return ' like ';
else if (operator == fflib_Operator.INx)
return ' IN ';
else if (operator == fflib_Operator.NOT_IN)
return ' NOT IN ';
else if (operator == fflib_Operator.INCLUDES)
return ' INCLUDES ';
else if (operator == fflib_Operator.EXCLUDES)
return ' EXCLUDES ';
else
return null;
}
/**
* Adds braces to the condition when generated to SOQL
*
* @param embraced Braces will be added if set to TRUE
*/
private void setEmbraced(Boolean embraced)
{
this.embraced = embraced;
}
/**
* @param value The value to convert
*
* @return Returns the given value converted to literal string
*/
private static String toLiteral(final Object value)
{
if (value == null) return 'null';
if (value instanceof String || value instanceof Id)
{
String manipulated = (String) value;
return '\'' + manipulated + '\'';
}
else if (value instanceof Boolean ||
value instanceof Integer ||
value instanceof Long ||
value instanceof Double ||
value instanceof Decimal)
{
return '' + value;
}
else if (value instanceof Date)
{
return '' + Datetime.newInstance(((Date) value).year(), ((Date) value).month(), ((Date) value).day()).format('yyyy-MM-dd');
}
else if (value instanceof Datetime)
{
return '' + ((Datetime) value).format('yyyy-MM-dd') + 'T' + ((Datetime) value).format('HH:mm:ss') + 'Z';
}
throw new CriteriaException(
'invalid value; value must a primitive type (String|Id|Boolean|Integer|Long|Double|Decimal|Date|Datetime)'
);
}
/**
* @param values The values to convert
*
* @return Returns the given values converted to literal string separated by a comma
*/
private static String toLiteral(final Objects values)
{
if (values.isEmpty()) return '';
String result = '(';
for (Object obj : values.getObjects())
{
if (result != '(')
{
result += ',';
}
result += toLiteral(obj);
}
return result + ')';
}
/**
* Generic criteria handler for comparing against sets
*/
private class FieldSetEvaluator implements Evaluator
{
private Schema.SObjectField sObjectField;
private Objects values;
private fflib_Operator operator;
public FieldSetEvaluator(Schema.SObjectField sObjectField, fflib_Operator operator, Objects values)
{
this.sObjectField = sObjectField;
this.values = values;
this.operator = operator;
}
public Boolean evaluate(Object record)
{
if (!(record instanceof SObject))
throw new CriteriaException('Only records of type SObject can have fieldCriteria');
Object fieldValue = ((SObject) record).get(this.sObjectField);
Boolean isIn = this.values.contains(fieldValue);
return ((operator == fflib_Operator.INx && isIn) || (operator == fflib_Operator.NOT_IN && !isIn));
}
public String toSOQL()
{
return String.format(
'{0} {2} {3}',
new List<String>
{
this.sObjectField.getDescribe().getName(),
operatorToString(this.operator),
toLiteral(this.values)
}
);
}
}
private interface Evaluator
{
Boolean evaluate(Object obj);
String toSOQL();
}
/**
* Generic field Evaluator
*/
private class FieldEvaluator implements Evaluator
{
private Schema.SObjectField sObjectField;
private Object value;
private fflib_Operator operator;
public FieldEvaluator(Schema.SObjectField sObjectField, fflib_Operator operator, Object value)
{
this.sObjectField = sObjectField;
this.value = value;
this.operator = operator;
}
public Boolean evaluate(Object record)
{
if (!(record instanceof SObject))
throw new CriteriaException('Only records of type SObject can have fieldCriteria');
Object fieldValue = ((SObject) record).get(this.sObjectField);
return fflib_Comparator.compareTo(fieldValue, operator, this.value);
}
public String toSOQL()
{
return String.join(
new List<String>
{
this.sObjectField.getDescribe().getName(),
operatorToString(this.operator),
toLiteral(this.value)
},
''
);
}
}
private class PropertyEvaluator implements Evaluator
{
private Object property;
private Object value;
private fflib_Operator operator;
public PropertyEvaluator(Object property, fflib_Operator operator, Object value)
{
this.property = property;
this.value = value;
this.operator = operator;
}
public Boolean evaluate(Object dto)
{
Object fieldValue = getX(dto, this.property);
return fflib_Comparator.compareTo(fieldValue, operator, this.value);
}
public String toSOQL()
{
throw new CriteriaException('Property Objects cannot be used in SOQL queries');
}
// todo - should be moved one abstraction level higher, to prevent it from serializing multiple times (for each condition)
private Object getX(Object dto, Object propertyName)
{
String serializedJSON = JSON.serialize(dto);
Map<Object, Object> valueByPropertyName =
(Map<Object, Object>) JSON.deserializeUntyped(serializedJSON);
return valueByPropertyName.get(propertyName);
}
}
/**
* Class exception handler
*/
public class CriteriaException extends Exception
{
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>41.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,47 @@
/**
* File Name: sflib_Operator
* Description: Enum of Operators
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public enum fflib_Operator
{
EQUALS, // =
NOT_EQUALS, // !=
LESS_THAN, // <
LESS_THAN_OR_EQUAL_TO, // <=
GREATER_THAN, // >
GREATER_THAN_OR_EQUAL_TO, // >=
LIKEx, // like
INCLUDES, // includes
EXCLUDES, // excludes
INx, // in
NOT_IN, // not in
ANDx, // AND
ORx // OR
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>41.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,75 @@
/**
* File Name: sflib_sflib_OperatorUtils
* Description:
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public with sharing class fflib_OperatorUtils
{
public static final fflib_Operator EQUALS = fflib_Operator.EQUALS;
public static final fflib_Operator NOT_EQUALS = fflib_Operator.NOT_EQUALS;
public static final fflib_Operator LESS_THAN = fflib_Operator.LESS_THAN;
public static final fflib_Operator LESS_THAN_OR_EQUAL_TO = fflib_Operator.LESS_THAN_OR_EQUAL_TO;
public static final fflib_Operator GREATER_THAN = fflib_Operator.GREATER_THAN;
public static final fflib_Operator GREATER_THAN_OR_EQUAL_TO = fflib_Operator.GREATER_THAN_OR_EQUAL_TO;
public static final fflib_Operator LIKEx = fflib_Operator.LIKEx;
public static final fflib_Operator INx = fflib_Operator.INx;
public static final fflib_Operator NOT_IN = fflib_Operator.NOT_IN;
public static final fflib_Operator INCLUDES = fflib_Operator.INCLUDES;
public static final fflib_Operator EXCLUDES = fflib_Operator.EXCLUDES;
public static final fflib_Operator DEFAULT_sflib_Operator = EQUALS;
public static String operatorToString(fflib_Operator op)
{
if (op == EQUALS)
return '=';
else if (op == NOT_EQUALS)
return '!=';
else if (op == LESS_THAN)
return '<';
else if (op == LESS_THAN_OR_EQUAL_TO)
return '<=';
else if (op == GREATER_THAN)
return '>';
else if (op == GREATER_THAN_OR_EQUAL_TO)
return '>=';
else if (op == LIKEx)
return 'like';
else if (op == INx)
return 'IN';
else if (op == NOT_IN)
return 'NOT IN';
else if (op == INCLUDES)
return 'INCLUDES';
else if (op == EXCLUDES)
return 'EXCLUDES';
else
return null;
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>41.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,58 @@
/**
* File Name: DateTimes
* Description: Primitive domain for the object type DateTime
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual with sharing class DateTimes
extends Objects
{
public DateTimes(Set<Datetime> dateTimes)
{
super(new List<Datetime>(dateTimes));
}
public DateTimes(List<Datetime> dateTimes)
{
super((List<Object>) dateTimes);
}
public DateTimes(List<Object> elements)
{
super(elements);
}
public Set<Datetime> getDateTimeSet()
{
return new Set<Datetime>(getDateTimes());
}
public List<Datetime> getDateTimes()
{
return (List<Datetime>) getObjects();
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,58 @@
/**
* File Name: Dates
* Description: Primitive domain for the object type Date
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual class Dates
extends Objects
{
public Dates(Set<Date> dates)
{
super(new List<Date>(dates));
}
public Dates(List<Date> dates)
{
super((List<Object>) dates);
}
public Dates(List<Object> elements)
{
super(elements);
}
public Set<Date> getDateSet()
{
return new Set<Date>(getDates());
}
public List<Date> getDates()
{
return (List<Date>) getObjects();
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,58 @@
/**
* File Name: Decimals
* Description: Primitive domain for the object type Decimal
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual with sharing class Decimals
extends Objects
{
public Decimals(Set<Decimal> decimals)
{
super(new List<Decimal>(decimals));
}
public Decimals(List<Decimal> decimals)
{
super((List<Object>) decimals);
}
public Decimals(List<Object> elements)
{
super(elements);
}
public Set<Decimal> getDecimalSet()
{
return new Set<Decimal>(getDecimals());
}
public List<Decimal> getDecimals()
{
return (List<Decimal>) getObjects();
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,59 @@
/**
* File Name: Doubles
* Description: Primitive domain for the object type Double
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual with sharing class Doubles
extends Objects
{
public Doubles(Set<Double> doubles)
{
super(new List<Double>(doubles));
}
public Doubles(List<Double> doubles)
{
super((List<Object>) doubles);
}
public Doubles(List<Object> elements)
{
super(elements);
}
public Set<Double> getDoubleSet()
{
return new Set<Double>(getDoubles());
}
public List<Double> getDoubles()
{
return (List<Double>) getObjects();
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,75 @@
/**
* File Name: Ids
* Description: Primitive domain for the object type Id
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual with sharing class Ids
extends Objects
{
public Ids(Set<Id> idSet)
{
super(new List<Id>(idSet));
}
public Ids(List<Id> ids)
{
super((List<Object>) ids);
}
public Ids(List<Object> elements)
{
super(elements);
}
public Ids(Objects objects)
{
super(getIdList(objects));
}
public Set<Id> getIds()
{
return new Set<Id>(getIdList());
}
public List<Id> getIdList()
{
return (List<Id>) getObjects();
}
private static List<Id> getIdList(Objects objects)
{
List<Id> result = new List<Id>();
for (Object obj : objects.getObjects())
{
if (!(obj instanceof Id)) continue;
result.add((Id) obj);
}
return result;
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,58 @@
/**
* File Name: Integers
* Description: Primitive domain for the object type Integer
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual with sharing class Integers
extends Objects
{
public Integers(Set<Integer> integerSet)
{
super(new List<Integer>(integerSet));
}
public Integers(List<Integer> integerList)
{
super((List<Integer>) integerList);
}
public Integers(List<Object> elements)
{
super(elements);
}
public Set<Integer> getIntegerSet()
{
return new Set<Integer>(getIntegers());
}
public List<Integer> getIntegers()
{
return (List<Integer>) getObjects();
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,58 @@
/**
* File Name: Longs
* Description: Primitive domain for the object type Long
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual with sharing class Longs
extends Objects
{
public Longs(Set<Long> longs)
{
super(new List<Long>(longs));
}
public Longs(List<Long> longs)
{
super((List<Object>) longs);
}
public Longs(List<Object> elements)
{
super(elements);
}
public Set<Long> getLongSet()
{
return new Set<Long>(getLongs());
}
public List<Long> getLongs()
{
return (List<Long>) getObjects();
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,90 @@
/**
* File Name: Objects
* Description: Primitive domain for the object type Object
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual with sharing class Objects
extends fflib_Objects
implements fflib_IObjects
{
// The objects contained in the domain
protected List<Object> objects { get; private set; }
// The object type of the objects contained in the domain
private Object objectType;
/**
* Class constructor
*
* @param obj The object to contain inside the domain
*/
public Objects(Object obj)
{
this(new List<Object>{ obj });
}
/**
* Class constructor
*
* @param objects The objects to contain inside the domain
*/
public Objects(Set<Object> objects)
{
this(new List<Object>(objects));
}
/**
* Class constructor
*
* @param objects The objects to contain inside the domain
*/
public Objects(List<Object> objects)
{
this(objects, Object.class);
}
/**
* Class constructor
*
* @param objects The objects to contain inside the domain
* @param objectType The object type of the given objects
*/
public Objects(List<Object> objects, Object objectType)
{
super(objects);
this.objectType = this.objectType;
}
/**
* @return Returns a unique set of objects which are contained in the domain
*/
public Set<Object> getObjectsSet()
{
return new Set<Object>(getObjects());
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,401 @@
/**
* File Name: SObjects
* Description: Primitive domain for the object type SObject
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual class SObjects
extends fflib_SObjects
implements fflib_ISObjects
{
protected Schema.DescribeSObjectResult SObjectDescribe { get; private set; }
/**
* Class constructors
*
* @param objects The Objects of type SObjectType, to contain inside the domain
*/
public SObjects(List<Object> objects)
{
// todo - assert of objects of type SObject
this((List<SObject>) objects);
}
/**
* Class constructor
*
* @param records The records to contain inside the domain
*/
public SObjects(List<SObject> records)
{
this(records, records.getSObjectType());
}
/**
* Class constructor
*
* @param records The records to contain inside the domain
* @param sObjectType The SObjectType of the records
*/
public SObjects(List<SObject> records, Schema.SObjectType sObjectType)
{
super(records, sObjectType);
SObjectDescribe = sObjectType.getDescribe();
}
/**
* Adds an error message to the records in the domain
*
* @param message The error message to add to each record
*/
@TestVisible
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
*/
@TestVisible
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
*/
@TestVisible
protected void clearField(Schema.SObjectField sObjectField)
{
clearFields(new Set<Schema.SObjectField>{ sObjectField });
}
/**
* Clear the field values on all the records of the domain
* @param sObjectFields The fields to nullify
*/
@TestVisible
protected void clearFields(Set<Schema.SObjectField> sObjectFields)
{
for (SObject record : getRecords())
{
for (SObjectField sObjectField : sObjectFields)
{
record.put(sObjectField, null);
}
}
}
/**
* @param sObjectField The Schema.SObjectField to get their Id values
*
* @return The Date values of the given sObjectField, null values are omitted
*/
@TestVisible
protected virtual Dates getDateFieldValues(Schema.SObjectField sObjectField)
{
Set<Date> result = new Set<Date>();
for (SObject record : getRecords())
{
Object fieldValue = record.get(sObjectField);
if (fieldValue == null) continue;
result.add((Date) fieldValue);
}
return new Dates(result);
}
/**
* @param sObjectField The Schema.SObjectField to get their Id values
* @param criteria The criteria condition that must be met to include the value in the return
*
* @return The Date values of the given sObjectField, null values are omitted
*/
@TestVisible
protected virtual Dates getDateFieldValues(Schema.SObjectField sObjectField, fflib_Criteria criteria)
{
return new SObjects(getRecords(criteria))
.getDateFieldValues(sObjectField);
}
/**
* @param sObjectField The Schema.SObjectField to get their Id values
*
* @return The DateTime values of the given sObjectField, null values are omitted
*/
@TestVisible
protected virtual DateTimes getDateTimeFieldValues(Schema.SObjectField sObjectField)
{
Set<Datetime> result = new Set<Datetime>();
for (SObject record : getRecords())
{
Object fieldValue = record.get(sObjectField);
if (fieldValue == null) continue;
result.add((Datetime) fieldValue);
}
return new DateTimes(result);
}
/**
* @param sObjectField The Schema.SObjectField to get their Id values
* @param criteria The criteria condition that must be met to include the value in the return
*
* @return The DateTime values of the given sObjectField, null values are omitted
*/
@TestVisible
protected virtual DateTimes getDateTimeFieldValues(Schema.SObjectField sObjectField, fflib_Criteria criteria)
{
return new SObjects(getRecords(criteria))
.getDateTimeFieldValues(sObjectField);
}
/**
* @param sObjectField The Schema.SObjectField to get their Id values
*
* @return The Decimal values of the given sObjectField, null values are omitted
*/
@TestVisible
protected virtual Decimals getDecimalFieldValues(Schema.SObjectField sObjectField)
{
Set<Decimal> result = new Set<Decimal>();
for (SObject record : getRecords())
{
Object fieldValue = record.get(sObjectField);
if (fieldValue == null) continue;
result.add((Decimal) fieldValue);
}
return new Decimals(result);
}
/**
* @param sObjectField The Schema.SObjectField to get their Id values
* @param criteria The criteria condition that must be met to include the value in the return
*
* @return The Decimal values of the given sObjectField, null values are omitted
*/
@TestVisible
protected virtual Decimals getDecimalFieldValues(Schema.SObjectField sObjectField, fflib_Criteria criteria)
{
return new SObjects(getRecords(criteria))
.getDecimalFieldValues(sObjectField);
}
/**
* @param sObjectField The Schema.SObjectField to get their Id values
*
* @return The Double values of the given sObjectField, null values are omitted
*/
@TestVisible
protected virtual Doubles getDoubleFieldValues(Schema.SObjectField sObjectField)
{
Set<Double> result = new Set<Double>();
for (SObject record : getRecords())
{
Object fieldValue = record.get(sObjectField);
if (fieldValue == null) continue;
result.add((Double) fieldValue);
}
return new Doubles(result);
}
/**
* @param sObjectField The Schema.SObjectField to get their Id values
* @param criteria The criteria condition that must be met to include the value in the return
*
* @return The Double values of the given sObjectField, null values are omitted
*/
@TestVisible
protected virtual Doubles getDoubleFieldValues(Schema.SObjectField sObjectField, fflib_Criteria criteria)
{
return new SObjects(getRecords(criteria))
.getDoubleFieldValues(sObjectField);
}
/**
* @param sObjectField The Schema.SObjectField to get their Id values
*
* @return The Id values of the given sObjectField, null values are omitted
*/
@TestVisible
protected virtual Ids getIdFieldValues(Schema.SObjectField sObjectField)
{
Set<Id> result = new Set<Id>();
for (SObject record : getRecords())
{
Object fieldValue = record.get(sObjectField);
if (fieldValue == null) continue;
result.add(Id.valueOf(String.valueOf(fieldValue)));
}
return new Ids(result);
// todo - alternative return to avoid code duplications: return new Ids(getFieldValues(sObjectField));
}
/**
* @param sObjectField The Schema.SObjectField to get their Id values
* @param criteria The criteria condition that must be met to include the value in the return
*
* @return The Id values of the given sObjectField, null values are omitted
*/
@TestVisible
protected virtual Ids getIdFieldValues(Schema.SObjectField sObjectField, fflib_Criteria criteria)
{
return new SObjects(getRecords(criteria))
.getIdFieldValues(sObjectField);
}
/**
* @param sObjectField The Schema.SObjectField to get their values
*
* @return The Integer values of the given sObjectField, null values are omitted
*/
@TestVisible
protected virtual Integers getIntegerFieldValues(Schema.SObjectField sObjectField)
{
Set<Integer> result = new Set<Integer>();
for (SObject record : getRecords())
{
Object fieldValue = record.get(sObjectField);
if (fieldValue == null) continue;
result.add(Integer.valueOf(fieldValue));
}
return new Integers(result);
}
/**
* @param sObjectField The Schema.SObjectField to get their values
* @param criteria The criteria condition that must be met to include the value in the return
*
* @return The Integer values of the given sObjectField, null values are omitted
*/
@TestVisible
protected virtual Integers getIntegerFieldValues(Schema.SObjectField sObjectField, fflib_Criteria criteria)
{
return new SObjects(getRecords(criteria))
.getIntegerFieldValues(sObjectField);
}
/**
* @param sObjectField The Schema.SObjectField to get their values
*
* @return The Long values of the given sObjectField, null values are omitted
*/
@TestVisible
protected virtual Longs getLongFieldValues(Schema.SObjectField sObjectField)
{
Set<Long> result = new Set<Long>();
for (SObject record : getRecords())
{
Object fieldValue = record.get(sObjectField);
if (fieldValue == null) continue;
result.add((Long) fieldValue);
}
return new Longs(result);
}
/**
* @param sObjectField The Schema.SObjectField to get their values
* @param criteria The criteria condition that must be met to include the value in the return
*
* @return The Long values of the given sObjectField, null values are omitted
*/
@TestVisible
protected virtual Longs getLongFieldValues(Schema.SObjectField sObjectField, fflib_Criteria criteria)
{
return new SObjects(getRecords(criteria))
.getLongFieldValues(sObjectField);
}
/**
* @param criteria The condition the returned record must meet
*
* @return Return the SObject records contained in the domain
*/
@TestVisible
public virtual List<SObject> getRecords(fflib_Criteria criteria)
{
List<SObject> result = new List<SObject>();
for (SObject record : getRecords())
{
if (!criteria.evaluate(record)) continue;
result.add(record);
}
return result;
}
/**
* @param sObjectField The Schema.SObjectField to get their values
*
* @return The String values of the given sObjectField
*/
@TestVisible
protected virtual Strings getStringFieldValues(Schema.SObjectField sObjectField)
{
Set<String> result = new Set<String>();
for (SObject record : getRecords())
{
result.add(String.valueOf(record.get(sObjectField)));
}
return new Strings(result);
}
/**
* @param sObjectField The Schema.SObjectField to get their values
* @param criteria The criteria condition that must be met to include the value in the return
*
* @return The String values of the given sObjectField
*/
@TestVisible
protected virtual Strings getStringFieldValues(Schema.SObjectField sObjectField, fflib_Criteria criteria)
{
return new SObjects(getRecords(criteria))
.getStringFieldValues(sObjectField);
}
/**
* @param sObjectField The Schema.SObjectField to change its value
* @param value The new value for the given sObjectField
* @param criteria The criteria condition that must be met to include the value in the return
*/
@TestVisible
protected virtual void setFieldValue(Schema.SObjectField sObjectField, Object value, fflib_Criteria criteria)
{
new SObjects(getRecords(criteria))
.setFieldValue(sObjectField, value);
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,64 @@
/**
* File Name: Strings
* Description: Primitive domain for the object type String
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual with sharing class Strings
extends Objects
{
public Strings(Set<String> stringSet)
{
super(new List<String>(stringSet));
}
public Strings(List<String> stringList)
{
super((List<String>) stringList);
}
public Strings(List<Object> elements)
{
super(elements);
}
/**
* @return Returns a set with unique values of the Strings contained in this domain
*/
public Set<String> getStringSet()
{
return new Set<String>(getStrings());
}
/**
* @return Returns all values of the Strings contained in this domain, including duplicate values
*/
public List<String> getStrings()
{
return (List<String>) getObjects();
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,273 @@
/**
* File Name: fflib_ComparatorTest
* Description: Unit test class for fflib_Comparator
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@IsTest
private with sharing class fflib_ComparatorTest
{
private static testmethod void testNulls()
{
String aNull = null;
Object aNullO = aNull;
Object xyz = 'xyz';
System.assertEquals(-1, fflib_Comparator.compare(aNullO, xyz));
System.assertEquals(0, fflib_Comparator.compare(aNullO, aNullO));
System.assertEquals(1, fflib_Comparator.compare(xyz, aNullO));
}
private static testmethod void testBlob()
{
Object b1 = Blob.valueOf('123');
Object b2 = Blob.valueOf('abc');
Boolean exceptionThrown = false;
try
{
fflib_Comparator.compare(b1, b2);
}
catch (fflib_Comparator.IllegalArgumentException e)
{
exceptionThrown = true;
}
System.assert(exceptionThrown);
}
private static testmethod void testBoolean()
{
assertCompareBoolean(false, true, -1);
assertCompareBoolean(true, true, 0);
assertCompareBoolean(false, false, 0);
assertCompareBoolean(true, false, 1);
}
private static void assertCompareBoolean(Object b1, Object b2, Integer expected)
{
System.assertEquals(expected, fflib_Comparator.compare(b1, b2));
}
private static testmethod void testDate()
{
assertCompareDate(date.newinstance(1980, 2, 17), date.newinstance(1981, 2, 17), -1);
assertCompareDate(date.newinstance(1981, 2, 17), date.newinstance(1981, 2, 17), 0);
assertCompareDate(date.newinstance(1981, 2, 17), date.newinstance(1980, 2, 17), 1);
}
private static void assertCompareDate(Object d1, Object d2, Integer expected)
{
System.assertEquals(expected, fflib_Comparator.compare(d1, d2));
}
private static testmethod void testDatetime()
{
Object d1 = datetime.newInstance(2008, 12, 1, 12, 30, 1);
Object d2 = datetime.newInstance(2008, 12, 1, 12, 30, 2);
assertCompareDatetime(d1, d2, -1);
assertCompareDatetime(d1, d1, 0);
assertCompareDatetime(d2, d1, 1);
}
private static void assertCompareDatetime(Object d1, Object d2, Integer expected)
{
System.assertEquals(expected, fflib_Comparator.compare(d1, d2));
}
private static testmethod void testDecimal()
{
Decimal d1 = 123.123;
Decimal d2 = 125.125;
assertCompareDecimal(d1, d2, -1);
assertCompareDecimal(d1, d1, 0);
assertCompareDecimal(d2, d1, 1);
}
private static void assertCompareDecimal(Object d1, Object d2, Integer expected)
{
System.assertEquals(expected, fflib_Comparator.compare(d1, d2));
}
private static testmethod void testDouble()
{
Double d1 = 123.123;
Double d2 = 125.125;
assertCompareDouble(d1, d2, -1);
assertCompareDouble(d1, d1, 0);
assertCompareDouble(d2, d1, 1);
}
private static void assertCompareDouble(Object d1, Object d2, Integer expected)
{
System.assertEquals(expected, fflib_Comparator.compare(d1, d2));
}
private static testmethod void testInteger()
{
Integer i1 = -10;
Integer i2 = 15;
assertCompare(i1, i2, -1);
assertCompare(i1, i1, 0);
assertCompare(i2, i1, 1);
}
private static void assertCompare(Object i1, Object i2, Integer expected)
{
System.assertEquals(expected, fflib_Comparator.compare(i1, i2));
}
private static testmethod void testLong()
{
Long i1 = -10;
Long i2 = 15;
assertCompareLong(i1, i2, -1);
assertCompareLong(i1, i1, 0);
assertCompareLong(i2, i1, 1);
}
private static void assertCompareLong(Object l1, Object l2, Integer expected)
{
System.assertEquals(expected, fflib_Comparator.compare(l1, l2));
}
private static testmethod void testTime()
{
Time t1 = Time.newInstance(18, 30, 2, 20);
Time t2 = Time.newInstance(18, 30, 2, 21);
assertCompareTime(t1, t2, -1);
assertCompareTime(t2, t2, 0);
assertCompareTime(t2, t1, 1);
}
private static void assertCompareTime(Object t1, Object t2, Integer expected)
{
System.assertEquals(expected, fflib_Comparator.compare(t1, t2));
}
private static testmethod void testString()
{
String s1 = 'abc';
String s2 = 'def';
assertCompareString(s1, s2, -1);
assertCompareString(s1, s1, 0);
assertCompareString(s2, s1, 1);
}
private static void assertCompareString(Object s1, Object s2, Integer expected)
{
System.assertEquals(expected, fflib_Comparator.compare(s1, s2));
}
private static testMethod void assertContainsNull()
{
System.assert(fflib_Comparator.contains(null, null));
}
private static testMethod void assertContainsSourceNull()
{
System.assert(!fflib_Comparator.contains(null, 0));
}
private static testMethod void assertContainsSearchNull()
{
System.assert(!fflib_Comparator.contains(new Set<String>(), null));
}
private static testMethod void assertContainsDate()
{
Date myDate = Date.newInstance(1976, 6, 1);
System.assert(fflib_Comparator.contains(new Set<Date> {myDate}, myDate));
}
private static testMethod void assertContainsDateTime()
{
Datetime myDateTime = DateTime.newInstance(1976, 6, 1, 11, 55, 0);
System.assert(fflib_Comparator.contains(new Set<Datetime> {myDateTime}, myDateTime));
}
private static testMethod void assertContainsDouble()
{
Double myDouble = Double.valueOf(123);
System.assert(fflib_Comparator.contains(new Set<Double> {myDouble}, myDouble));
}
private static testMethod void assertContainsId()
{
Id id = fflib_IDGenerator.generate(Account.SObjectType);
System.assert(fflib_Comparator.contains(new Set<Id> {id}, id));
}
private static testMethod void assertContainsInteger()
{
Set<Integer> integerSet = new Set<Integer>
{
0, 1, 2, 3
};
Object obj = (object) integerSet;
System.assertEquals(true, fflib_Comparator.contains(obj, 2));
System.assertEquals(false, fflib_Comparator.contains(obj, 5));
Account acc = new Account(Name = 'TEST', NumberOfEmployees = 1);
System.assertEquals(true, (object) acc.get('NumberOfEmployees') instanceof integer);
}
private static testMethod void assertContainsLong()
{
Long myLong = Long.valueOf('3123');
System.assert(fflib_Comparator.contains(new Set<Long> {myLong}, myLong));
}
private static testMethod void assertContainsObject()
{
Object obj = (Object) '134';
System.assert(fflib_Comparator.contains(new Set<Object>{obj}, obj));
}
private static testMethod void assertContainsTime()
{
Time myTime = Time.newInstance(11, 55, 0, 0);
System.assert(fflib_Comparator.contains(new Set<Time> {myTime}, myTime));
}
private static testMethod void assertContainsString()
{
System.assert(fflib_Comparator.contains(new Set<String> {'Test'}, 'Test'));
}
private static testMethod void assertContainsSObject()
{
Account myAccount = new Account();
Boolean exceptionThrown = false;
try
{
fflib_Comparator.contains(new Set<SObject> {myAccount}, myAccount);
} catch (fflib_Comparator.IllegalArgumentException e)
{
exceptionThrown = true;
}
System.assert(exceptionThrown);
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>41.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,553 @@
/**
* File Name: fflib_CriteriaTest
* Description:
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@IsTest(IsParallel=true)
private with sharing class fflib_CriteriaTest
{
private static final Integer HIGHER_NUMBER = 98765;
private static final Integer A_NUMBER = 54321;
private static final Integer SAME_NUMBER = A_NUMBER;
private static final Integer LOWER_NUMBER = 0;
private static final String A_STRING = 'Example';
private static final String SAME_STRING = A_STRING;
private static final String ANOTHER_STRING = 'Something Else';
private static final String HELLO_WORLD = 'Hello World!';
private static final Boolean FAILING = false;
@IsTest
static void itShouldEvaluateAnEqualsToCondition()
{
System.assert(
new fflib_Criteria()
.andCriteria()
.equalTo(Account.Name, A_STRING)
.evaluate(new Account(Name = SAME_STRING))
);
}
@IsTest
static void itShouldEvaluateAnEqualsToCondition_ReturningFalse()
{
System.assert(
new fflib_Criteria()
.equalTo(Account.Name, A_STRING)
.evaluate(new Account(Name = ANOTHER_STRING))
== FAILING
);
}
@IsTest
static void itShouldEvaluateAnEqualsToCondition_NullValues()
{
System.assert(
new fflib_Criteria()
.equalTo(Account.Name, A_STRING)
.evaluate(new Account())
== FAILING
);
}
@IsTest
static void itShouldEvaluateANotEqualsToCondition()
{
System.assert(
new fflib_Criteria()
.notEqualTo(Account.Name, A_STRING)
.evaluate(new Account(Name = ANOTHER_STRING))
);
}
@IsTest
static void itShouldEvaluateANotEqualsToCondition_ReturningFalse()
{
System.assert(
new fflib_Criteria()
.notEqualTo(Account.Name, A_STRING)
.evaluate(new Account(Name = SAME_STRING))
== FAILING
);
}
@IsTest
static void itShouldEvaluateAddGreaterOrEqualToCondition()
{
System.assert(
new fflib_Criteria()
.greaterOrEqualTo(Account.AnnualRevenue, A_NUMBER)
.evaluate(new Account(AnnualRevenue = HIGHER_NUMBER))
);
}
@IsTest
static void itShouldEvaluateAddGreaterOrEqualToCondition_Equal()
{
System.assert(
new fflib_Criteria()
.greaterOrEqualTo(Account.AnnualRevenue, A_NUMBER)
.evaluate(new Account(AnnualRevenue = SAME_NUMBER))
);
}
@IsTest
static void itShouldEvaluateAddGreaterOrEqualToCondition_ReturningFalse()
{
System.assert(
new fflib_Criteria()
.greaterOrEqualTo(Account.AnnualRevenue, A_NUMBER)
.evaluate(new Account(AnnualRevenue = LOWER_NUMBER))
== FAILING
);
}
@IsTest
static void itShouldEvaluateAddGreaterOrEqualToCondition_NullValues()
{
System.assert(
new fflib_Criteria()
.greaterOrEqualTo(Account.AnnualRevenue, A_NUMBER)
.evaluate(new Account())
== FAILING
);
}
@IsTest
static void itShouldEvaluateAddGreaterThanCondition()
{
System.assert(
new fflib_Criteria()
.greaterThan(Account.AnnualRevenue, A_NUMBER)
.evaluate(new Account(AnnualRevenue = HIGHER_NUMBER))
);
}
@IsTest
static void itShouldEvaluateAddGreaterThanCondition_EqualValues()
{
System.assert(
new fflib_Criteria()
.greaterThan(Account.AnnualRevenue, A_NUMBER)
.evaluate(new Account(AnnualRevenue = SAME_NUMBER))
== FAILING
);
}
@IsTest
static void itShouldEvaluateAddGreaterThanCondition_ReturningFalse()
{
System.assert(
new fflib_Criteria()
.greaterThan(Account.AnnualRevenue, A_NUMBER)
.evaluate(new Account(AnnualRevenue = LOWER_NUMBER))
== FAILING
);
}
@IsTest
static void itShouldEvaluateAddGreaterThanCondition_NullValues()
{
System.assert(
new fflib_Criteria()
.greaterThan(Account.AnnualRevenue, A_NUMBER)
.evaluate(new Account())
== FAILING
);
}
@IsTest
static void itShouldEvaluateAddLessOrEqualToCondition()
{
System.assert(
new fflib_Criteria()
.lessOrEqualTo(Account.AnnualRevenue, A_NUMBER)
.evaluate(new Account(AnnualRevenue = LOWER_NUMBER))
);
}
@IsTest
static void itShouldEvaluateAddLessOrEqualToCondition_Equal()
{
System.assert(
new fflib_Criteria()
.lessOrEqualTo(Account.AnnualRevenue, A_NUMBER)
.evaluate(new Account(AnnualRevenue = SAME_NUMBER))
);
}
@IsTest
static void itShouldEvaluateAddLessOrEqualToCondition_ReturningFalse()
{
System.assert(
new fflib_Criteria()
.lessOrEqualTo(Account.AnnualRevenue, A_NUMBER)
.evaluate(new Account(AnnualRevenue = HIGHER_NUMBER))
== FAILING
);
}
@IsTest
static void itShouldEvaluateAddLessOrEqualToCondition_NullValues()
{
System.assert(
new fflib_Criteria()
.lessOrEqualTo(Account.AnnualRevenue, A_NUMBER)
.evaluate(new Account())
);
}
@IsTest
static void itShouldEvaluateAddLessThanCondition()
{
System.assert(
new fflib_Criteria()
.lessThan(Account.AnnualRevenue, A_NUMBER)
.evaluate(new Account(AnnualRevenue = LOWER_NUMBER))
);
}
@IsTest
static void itShouldEvaluateAddLessThanCondition_EqualValues()
{
System.assert(
new fflib_Criteria()
.lessThan(Account.AnnualRevenue, A_NUMBER)
.evaluate(new Account(AnnualRevenue = SAME_NUMBER))
== FAILING
);
}
@IsTest
static void itShouldEvaluateAddLessThanCondition_ReturningFalse()
{
System.assert(
new fflib_Criteria()
.lessThan(Account.AnnualRevenue, A_NUMBER)
.evaluate(new Account(AnnualRevenue = HIGHER_NUMBER))
== FAILING
);
}
@IsTest
static void itShouldEvaluateAddLessThanCondition_NullValues()
{
System.assert(
new fflib_Criteria()
.lessThan(Account.AnnualRevenue, A_NUMBER)
.evaluate(new Account())
);
}
@IsTest
static void itShouldEvaluateInSetCondition_Decimal()
{
System.assert(
new fflib_Criteria()
.inSet(Account.AnnualRevenue, new Set<Decimal> {1.1, 2.2})
.evaluate(new Account(AnnualRevenue = 1.1))
);
}
@IsTest
static void itShouldEvaluateInSetCondition_Id()
{
Id idOne = fflib_IDGenerator.generate(Account.SObjectType);
Id idTwo = fflib_IDGenerator.generate(Account.SObjectType);
System.assert(
new fflib_Criteria()
.inSet(Account.Id, new Set<Id> {idOne, idTwo})
.evaluate(new Account(Id = idOne))
);
}
@IsTest
static void itShouldEvaluateInSetCondition_Integer()
{
System.assert(
new fflib_Criteria()
.inSet(Account.NumberOfEmployees, new Set<Integer> {1, 10})
.evaluate(new Account(NumberOfEmployees = 1))
);
}
@IsTest
static void itShouldEvaluateInSetCondition()
{
System.assert(
new fflib_Criteria()
.inSet(Account.Type, new Set<String> {A_STRING, HELLO_WORLD})
.evaluate(new Account(Type = SAME_STRING))
);
}
@IsTest
static void itShouldEvaluateInSetCondition_ReturningFalse()
{
System.assert(
new fflib_Criteria()
.inSet(Account.Type, new Set<String> {A_STRING, HELLO_WORLD})
.evaluate(new Account(Type = ANOTHER_STRING))
== FAILING
);
}
@IsTest
static void itShouldEvaluateInSetCondition_NullValues()
{
System.assert(
new fflib_Criteria()
.inSet(Account.Type, new Set<String> {A_STRING, HELLO_WORLD})
.evaluate(new Account())
== FAILING
);
}
@IsTest
static void itShouldEvaluateNotInSetCondition()
{
System.assert(
new fflib_Criteria()
.notInSet(Account.Name, new Set<String> {A_STRING, HELLO_WORLD})
.evaluate(new Account(Name = ANOTHER_STRING))
);
}
@IsTest
static void itShouldEvaluateNotInSetCondition_Failing()
{
System.assert(
new fflib_Criteria()
.notInSet(Account.Name, new Set<String> {A_STRING, HELLO_WORLD})
.evaluate(new Account(Name = SAME_STRING))
== FAILING
);
}
@IsTest
static void itShouldEvaluateNotInSetCondition_Decimal()
{
System.assert(
new fflib_Criteria()
.notInSet(Account.AnnualRevenue, new Set<Decimal> {1.1, 2.2})
.evaluate(new Account(AnnualRevenue = 3.3))
);
}
@IsTest
static void itShouldEvaluateNotInSetCondition_Id()
{
Id idOne = fflib_IDGenerator.generate(Account.SObjectType);
Id idTwo = fflib_IDGenerator.generate(Account.SObjectType);
Id idThree = fflib_IDGenerator.generate(Account.SObjectType);
System.assert(
new fflib_Criteria()
.notInSet(Account.Id, new Set<Id> {idOne, idTwo})
.evaluate(new Account(Id = idThree))
);
}
@IsTest
static void itShouldEvaluateNotInSetCondition_Integer()
{
System.assert(
new fflib_Criteria()
.notInSet(Account.NumberOfEmployees, new Set<Integer> {1, 10})
.evaluate(new Account(NumberOfEmployees = 2))
);
}
@IsTest
static void itShouldEvaluateOrCondition_First()
{
System.assert(
new fflib_Criteria()
.orCriteria()
.equalTo(Account.Name, A_STRING)
.equalTo(Account.Name, ANOTHER_STRING)
.evaluate(new Account(Name = A_STRING))
);
}
@IsTest
static void itShouldEvaluateOrCondition_Second()
{
System.assert(
new fflib_Criteria()
.orCriteria()
.equalTo(Account.Name, A_STRING)
.equalTo(Account.Name, ANOTHER_STRING)
.evaluate(new Account(Name = ANOTHER_STRING))
);
}
@IsTest
static void itShouldEvaluateOrCondition_Failing()
{
System.assert(
new fflib_Criteria()
.orCriteria()
.equalTo(Account.Name, A_STRING)
.equalTo(Account.Name, ANOTHER_STRING)
.evaluate(new Account(Name = HELLO_WORLD))
== FAILING
);
}
@IsTest
static void itShouldEvaluateAddOrCondition_First()
{
System.assert(
new fflib_Criteria()
.equalTo(Account.Name, A_STRING)
.addOrCriteria(
new fflib_Criteria()
.equalTo(Account.AccountNumber, '001')
.equalTo(Account.AccountNumber, '002')
)
.evaluate(new Account(Name = A_STRING, AccountNumber = '001'))
);
}
@IsTest
static void itShouldEvaluateAddOrCondition_Second()
{
System.assert(
new fflib_Criteria()
.equalTo(Account.Name, A_STRING)
.addOrCriteria(
new fflib_Criteria()
.equalTo(Account.AccountNumber, '001')
.equalTo(Account.AccountNumber, '002')
)
.evaluate(new Account(Name = A_STRING, AccountNumber = '002'))
);
}
@IsTest
static void itShouldEvaluateAddOrCondition_Failing()
{
System.assert(
new fflib_Criteria()
.equalTo(Account.Name, A_STRING)
.addOrCriteria(
new fflib_Criteria()
.equalTo(Account.AccountNumber, '001')
.equalTo(Account.AccountNumber, '002')
)
.evaluate(new Account(Name = ANOTHER_STRING, AccountNumber = '001'))
== FAILING
);
}
@IsTest
static void itShouldEvaluateAddAndCondition_First()
{
System.assert(
new fflib_Criteria()
.orCriteria()
.equalTo(Account.Name, A_STRING)
.equalTo(Account.Name, ANOTHER_STRING)
.addAndCriteria(
new fflib_Criteria()
.equalTo(Account.Name, HELLO_WORLD)
.equalTo(Account.AccountNumber, '002')
)
.evaluate(new Account(Name = ANOTHER_STRING))
);
}
@IsTest
static void itShouldEvaluateAddAndCondition_Second()
{
System.assert(
new fflib_Criteria()
.orCriteria()
.equalTo(Account.Name, A_STRING)
.equalTo(Account.Name, ANOTHER_STRING)
.addAndCriteria(
new fflib_Criteria()
.equalTo(Account.Name, HELLO_WORLD)
.equalTo(Account.AccountNumber, '002')
)
.evaluate(new Account(Name = HELLO_WORLD, AccountNumber = '002'))
);
}
@IsTest
static void itShouldEvaluateAddAndCondition_SecondFailing()
{
System.assert(
new fflib_Criteria()
.orCriteria()
.equalTo(Account.Name, A_STRING)
.equalTo(Account.Name, ANOTHER_STRING)
.addAndCriteria(
new fflib_Criteria()
.equalTo(Account.Name, HELLO_WORLD)
.equalTo(Account.AccountNumber, '002')
)
.evaluate(new Account(Name = HELLO_WORLD))
== FAILING
);
}
@IsTest
static void itShouldEvaluateEmptyCondition()
{
System.assert(
new fflib_Criteria()
.evaluate(new Account())
);
}
@IsTest
static void itShouldGenerateQueryString_EqualsToCondition()
{
System.assertEquals(
'Name=\'Example\'',
new fflib_Criteria()
.andCriteria()
.equalTo(Account.Name, A_STRING)
.toSOQL()
);
}
@IsTest
static void itShouldGenerateQueryString_AddOrCondition()
{
System.assertEquals(
'Name=\'Example\' AND (AccountNumber=\'001\' OR AccountNumber=\'002\')',
new fflib_Criteria()
.equalTo(Account.Name, A_STRING)
.addOrCriteria(
new fflib_Criteria()
.equalTo(Account.AccountNumber, '001')
.equalTo(Account.AccountNumber, '002')
)
.toSOQL()
);
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>41.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,268 @@
/**
* File Name: SObjects
* Description: Primitive domain for the object type SObject
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@IsTest
private class SObjectsTest
{
@IsTest
static void itShouldClearTheField()
{
Account record = new Account(ShippingCountry = 'Holland');
DomainAccounts domain = new DomainAccounts(new List<Account> {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()
{
System.assertEquals(
(Object) Schema.Account.SObjectType,
new DomainAccounts(new List<Account>())
.getType(),
'Unexpected Domain Type'
);
System.assertEquals(
Schema.Account.SObjectType,
new DomainAccounts(new List<Account>())
.getSObjectType(),
'Unexpected Domain SObjectType'
);
}
@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<SObject>
{
new Account(Id = idA),
new Account(Id = idB),
new Account(Id = idC)
}
);
Set<Id> recordIds = new Set<Id> {idA, idB, idC};
System.assert(
domain.getRecordIds().containsAll(recordIds),
'The domain should return all the record Ids'
);
}
@IsTest
static void itShouldReturnRecordsWithFieldValues()
{
DomainAccounts domain = generateDomain();
System.assert(domain.selectByShippingCountry('USA').size() == 1);
}
@IsTest
static void itShouldReturnRecordsWithoutFieldValues()
{
DomainAccounts domain = generateDomain();
System.assert(domain.selectWithoutShippingCountry().size() == 3);
}
@IsTest
static void itShouldReturnRecordsWithoutAllFieldValues()
{
DomainAccounts domain = generateDomain();
System.assert(domain.selectWithEmptyRecord().size() == 1);
}
@IsTest
static void itShouldReturnRecordsWithShippingCountry()
{
DomainAccounts domain = generateDomain();
System.assert(domain.selectWithShippingCountry().size() == 3);
}
@IsTest
static void itShouldReturnRecordsWithAllFieldValues()
{
DomainAccounts domain = generateDomain();
System.assert(domain.selectPopulatedRecords().size() == 3);
}
@IsTest
static void itShouldReturnFieldValues()
{
DomainAccounts domain = generateDomain();
System.assert(
domain.getStringFieldValues(Schema.Account.ShippingCountry)
.containsAll(
new Set<Object>{
'USA',
'Ireland',
'UK',
''
}
)
);
}
@IsTest
static void itShouldSetFieldValue()
{
DomainAccounts domain = generateDomain();
String country = 'Holland';
domain.setShippingCountry(country);
System.assert(domain.selectByShippingCountry(country).size() == 6);
}
@IsTest
static void itShouldSetFieldValueByCondition()
{
DomainAccounts domain = generateDomain();
domain.setRatingByShippingCountry(
new Map<Object,Object>
{
'USA' => 'Hot'
}
);
System.assert(domain.selectByRating('Hot').size() == 1);
}
private static DomainAccounts generateDomain()
{
DomainAccounts domain = new DomainAccounts(
new List<Account>
{
new Account(Name = 'A', ShippingCountry = 'USA'),
new Account(Name = 'B', ShippingCountry = 'Ireland'),
new Account(Name = 'C', ShippingCountry = 'UK'),
new Account(Name = 'D', ShippingCountry = ''),
new Account(Name = 'E'),
new Account()
}
);
return domain;
}
private class DomainAccounts extends SObjects
{
public DomainAccounts(List<SObject> records)
{
super(records, Schema.Account.SObjectType);
}
public List<Account> selectByShippingCountry(String country)
{
return (List<Account>) getRecordsByFieldValues(
Schema.Account.ShippingCountry,
new Set<Object>{ country }
);
}
public List<Account> selectByRating(String rating)
{
return (List<Account>) getRecordsByFieldValue(
Schema.Account.Rating,
rating
);
}
public List<Account> selectWithoutShippingCountry()
{
return (List<Account>) getRecordsWithBlankFieldValues(
Schema.Account.ShippingCountry
);
}
public List<Account> selectWithShippingCountry()
{
return (List<Account>) getRecordsWithNotBlankFieldValues(
Schema.Account.ShippingCountry
);
}
public List<Account> selectWithEmptyRecord()
{
return (List<Account>) getRecordsWithAllBlankFieldValues(
new Set<Schema.SObjectField>
{
Schema.Account.Name,
Schema.Account.ShippingCountry
}
);
}
public List<Account> selectPopulatedRecords()
{
return (List<Account>) getRecordsWithAllNotBlankFieldValues(
new Set<Schema.SObjectField>
{
Schema.Account.Name,
Schema.Account.ShippingCountry
}
);
}
public void setShippingCountry(String country)
{
setFieldValue(Schema.Account.ShippingCountry, country);
}
public void setRatingByShippingCountry(Map<Object, Object> ratingByCountry)
{
setFieldValueByMap(
Schema.Account.ShippingCountry,
Schema.Account.Rating,
ratingByCountry);
}
public void addNameError(String message)
{
addError(Schema.Account.Name, message);
}
public void clearShippingCountry()
{
clearField(Schema.Account.ShippingCountry);
}
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>