diff --git a/.gitignore b/.gitignore
index bd20187..790a84f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
\ No newline at end of file
+.project.license
+temp/
+
+# Ignore other fflib packages
+sfdx-source/apex-mocks
+sfdx-source/apex-common
+sfdx-source/apex-extensions-examples
diff --git a/README.md b/README.md
index de0f03e..94f83b0 100644
--- a/README.md
+++ b/README.md
@@ -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:**
+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
+
diff --git a/docs/criteria-based-filter.md b/docs/criteria-based-filter.md
new file mode 100644
index 0000000..cad7adf
--- /dev/null
+++ b/docs/criteria-based-filter.md
@@ -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 selectByCountryWithMinimalNumberOfEmployees(String country, Integer minimalNumberOfEmployees)
+ {
+ return (List) 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!
diff --git a/docs/primitive-domains.md b/docs/primitive-domains.md
new file mode 100644
index 0000000..55a2321
--- /dev/null
+++ b/docs/primitive-domains.md
@@ -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 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.
+
+
+
diff --git a/sfdx-project.json b/sfdx-project.json
index f635075..b2b5c6f 100644
--- a/sfdx-project.json
+++ b/sfdx-project.json
@@ -1,7 +1,7 @@
{
"packageDirectories": [
{
- "path": "sfdx-source/force-app",
+ "path": "sfdx-source/apex-extensions",
"default": true
}
],
diff --git a/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_Comparator.cls b/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_Comparator.cls
new file mode 100644
index 0000000..0f0979a
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_Comparator.cls
@@ -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 && object2 instanceof Date)
+ return ((set) object1).contains((date) object2);
+ else if (object1 instanceof set && object2 instanceof Datetime)
+ return ((set) object1).contains((Datetime) object2);
+ else if (object1 instanceof set && object2 instanceof Double)
+ return ((set) object1).contains((Double) object2);
+ else if (object1 instanceof set && object2 instanceof Id)
+ return ((set) object1).contains((Id) object2);
+ else if (object1 instanceof set && object2 instanceof Integer)
+ return ((set) object1).contains((Integer) object2);
+ else if (object1 instanceof set && object2 instanceof Long)
+ return ((set) object1).contains((Long) object2);
+ else if (object1 instanceof set)
+ return ((set) object1).contains((Object) object2);
+ else if (object1 instanceof set && object2 instanceof Time)
+ return ((set) object1).contains((Time) object2);
+ else if (object1 instanceof set && object2 instanceof String)
+ return ((set) 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 {
+ }
+}
\ No newline at end of file
diff --git a/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_Comparator.cls-meta.xml b/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_Comparator.cls-meta.xml
new file mode 100644
index 0000000..f3bac1f
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_Comparator.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 41.0
+ Active
+
diff --git a/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_Criteria.cls b/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_Criteria.cls
new file mode 100644
index 0000000..ee61925
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_Criteria.cls
@@ -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 evaluators;
+
+ // The type of comparator NONE | AND | OR
+ private String type;
+
+
+ /**
+ * populate private variables with default settings.
+ */
+ public fflib_Criteria()
+ {
+ this.evaluators = new List();
+ 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{'Customer', 'Competitor', 'Partner'})
+ *
+ * Evaluates:
+ * Account.Type IN ('Customer','Competitor','Partner')
+ */
+ public fflib_Criteria inSet(Schema.SObjectField field, Set values)
+ {
+ return inSet(field, new Objects(values));
+ }
+ // Method overrides
+ public fflib_Criteria inSet(Schema.SObjectField field, Set values)
+ {
+ return inSet(field, new Dates(values));
+ }
+ public fflib_Criteria inSet(Schema.SObjectField field, Set values)
+ {
+ return inSet(field, new DateTimes(values));
+ }
+ public fflib_Criteria inSet(Schema.SObjectField field, Set values)
+ {
+ return inSet(field, new Decimals(values));
+ }
+ public fflib_Criteria inSet(Schema.SObjectField field, Set values)
+ {
+ return inSet(field, new Doubles(values));
+ }
+ public fflib_Criteria inSet(Schema.SObjectField field, Set values)
+ {
+ return inSet(field, new Ids(values));
+ }
+ public fflib_Criteria inSet(Schema.SObjectField field, Set values)
+ {
+ return inSet(field, new Integers(values));
+ }
+ public fflib_Criteria inSet(Schema.SObjectField field, Set values)
+ {
+ return inSet(field, new Longs(values));
+ }
+ public fflib_Criteria inSet(Schema.SObjectField field, Set 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{'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{'Customer', 'Competitor', 'Partner'})
+ *
+ * Evaluates:
+ * Account.Type NOT IN ('Customer','Competitor','Partner')
+ */
+ public fflib_Criteria notInSet(Schema.SObjectField field, Set values)
+ {
+ return notInSet(field, new Dates(values));
+ }
+ public fflib_Criteria notInSet(Schema.SObjectField field, Set values)
+ {
+ return notInSet(field, new DateTimes(values));
+ }
+ public fflib_Criteria notInSet(Schema.SObjectField field, Set values)
+ {
+ return notInSet(field, new Decimals(values));
+ }
+ public fflib_Criteria notInSet(Schema.SObjectField field, Set values)
+ {
+ return notInSet(field, new Doubles(values));
+ }
+ public fflib_Criteria notInSet(Schema.SObjectField field, Set values)
+ {
+ return notInSet(field, new Ids(values));
+ }
+ public fflib_Criteria notInSet(Schema.SObjectField field, Set values)
+ {
+ return notInSet(field, new Integers(values));
+ }
+ public fflib_Criteria notInSet(Schema.SObjectField field, Set values)
+ {
+ return notInSet(field, new Longs(values));
+ }
+ public fflib_Criteria notInSet(Schema.SObjectField field, Set values)
+ {
+ return notInSet(field, new Strings(values));
+ }
+ public fflib_Criteria notInSet(Schema.SObjectField field, Set 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{'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
+ {
+ 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
+ {
+ 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 valueByPropertyName =
+ (Map) JSON.deserializeUntyped(serializedJSON);
+ return valueByPropertyName.get(propertyName);
+ }
+ }
+
+ /**
+ * Class exception handler
+ */
+ public class CriteriaException extends Exception
+ {
+ }
+}
\ No newline at end of file
diff --git a/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_Criteria.cls-meta.xml b/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_Criteria.cls-meta.xml
new file mode 100644
index 0000000..f3bac1f
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_Criteria.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 41.0
+ Active
+
diff --git a/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_Operator.cls b/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_Operator.cls
new file mode 100644
index 0000000..e1e2a62
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_Operator.cls
@@ -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
+}
\ No newline at end of file
diff --git a/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_Operator.cls-meta.xml b/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_Operator.cls-meta.xml
new file mode 100644
index 0000000..f3bac1f
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_Operator.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 41.0
+ Active
+
diff --git a/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_OperatorUtils.cls b/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_OperatorUtils.cls
new file mode 100644
index 0000000..d45611d
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_OperatorUtils.cls
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_OperatorUtils.cls-meta.xml b/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_OperatorUtils.cls-meta.xml
new file mode 100644
index 0000000..f3bac1f
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/criteria/fflib_OperatorUtils.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 41.0
+ Active
+
diff --git a/sfdx-source/apex-extensions/main/default/classes/domains/DateTimes.cls b/sfdx-source/apex-extensions/main/default/classes/domains/DateTimes.cls
new file mode 100644
index 0000000..5c3f00c
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/domains/DateTimes.cls
@@ -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 dateTimes)
+ {
+ super(new List(dateTimes));
+ }
+
+ public DateTimes(List dateTimes)
+ {
+ super((List) dateTimes);
+ }
+
+ public DateTimes(List elements)
+ {
+ super(elements);
+ }
+
+ public Set getDateTimeSet()
+ {
+ return new Set(getDateTimes());
+ }
+
+ public List getDateTimes()
+ {
+ return (List) getObjects();
+ }
+}
\ No newline at end of file
diff --git a/sfdx-source/apex-extensions/main/default/classes/domains/DateTimes.cls-meta.xml b/sfdx-source/apex-extensions/main/default/classes/domains/DateTimes.cls-meta.xml
new file mode 100644
index 0000000..db9bf8c
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/domains/DateTimes.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 48.0
+ Active
+
diff --git a/sfdx-source/apex-extensions/main/default/classes/domains/Dates.cls b/sfdx-source/apex-extensions/main/default/classes/domains/Dates.cls
new file mode 100644
index 0000000..ea0b123
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/domains/Dates.cls
@@ -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 dates)
+ {
+ super(new List(dates));
+ }
+
+ public Dates(List dates)
+ {
+ super((List) dates);
+ }
+
+ public Dates(List elements)
+ {
+ super(elements);
+ }
+
+ public Set getDateSet()
+ {
+ return new Set(getDates());
+ }
+
+ public List getDates()
+ {
+ return (List) getObjects();
+ }
+}
\ No newline at end of file
diff --git a/sfdx-source/apex-extensions/main/default/classes/domains/Dates.cls-meta.xml b/sfdx-source/apex-extensions/main/default/classes/domains/Dates.cls-meta.xml
new file mode 100644
index 0000000..db9bf8c
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/domains/Dates.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 48.0
+ Active
+
diff --git a/sfdx-source/apex-extensions/main/default/classes/domains/Decimals.cls b/sfdx-source/apex-extensions/main/default/classes/domains/Decimals.cls
new file mode 100644
index 0000000..b8f5561
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/domains/Decimals.cls
@@ -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 decimals)
+ {
+ super(new List(decimals));
+ }
+
+ public Decimals(List decimals)
+ {
+ super((List) decimals);
+ }
+
+ public Decimals(List elements)
+ {
+ super(elements);
+ }
+
+ public Set getDecimalSet()
+ {
+ return new Set(getDecimals());
+ }
+
+ public List getDecimals()
+ {
+ return (List) getObjects();
+ }
+}
\ No newline at end of file
diff --git a/sfdx-source/apex-extensions/main/default/classes/domains/Decimals.cls-meta.xml b/sfdx-source/apex-extensions/main/default/classes/domains/Decimals.cls-meta.xml
new file mode 100644
index 0000000..db9bf8c
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/domains/Decimals.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 48.0
+ Active
+
diff --git a/sfdx-source/apex-extensions/main/default/classes/domains/Doubles.cls b/sfdx-source/apex-extensions/main/default/classes/domains/Doubles.cls
new file mode 100644
index 0000000..d69ac14
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/domains/Doubles.cls
@@ -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 doubles)
+ {
+ super(new List(doubles));
+ }
+
+ public Doubles(List doubles)
+ {
+ super((List) doubles);
+ }
+
+ public Doubles(List elements)
+ {
+ super(elements);
+ }
+
+ public Set getDoubleSet()
+ {
+ return new Set(getDoubles());
+
+ }
+
+ public List getDoubles()
+ {
+ return (List) getObjects();
+ }
+}
\ No newline at end of file
diff --git a/sfdx-source/apex-extensions/main/default/classes/domains/Doubles.cls-meta.xml b/sfdx-source/apex-extensions/main/default/classes/domains/Doubles.cls-meta.xml
new file mode 100644
index 0000000..db9bf8c
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/domains/Doubles.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 48.0
+ Active
+
diff --git a/sfdx-source/apex-extensions/main/default/classes/domains/Ids.cls b/sfdx-source/apex-extensions/main/default/classes/domains/Ids.cls
new file mode 100644
index 0000000..0d2384a
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/domains/Ids.cls
@@ -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 idSet)
+ {
+ super(new List(idSet));
+ }
+
+ public Ids(List ids)
+ {
+ super((List) ids);
+ }
+
+ public Ids(List elements)
+ {
+ super(elements);
+ }
+
+ public Ids(Objects objects)
+ {
+ super(getIdList(objects));
+ }
+
+ public Set getIds()
+ {
+ return new Set(getIdList());
+ }
+
+ public List getIdList()
+ {
+ return (List) getObjects();
+ }
+
+ private static List getIdList(Objects objects)
+ {
+ List result = new List();
+ for (Object obj : objects.getObjects())
+ {
+ if (!(obj instanceof Id)) continue;
+
+ result.add((Id) obj);
+ }
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/sfdx-source/apex-extensions/main/default/classes/domains/Ids.cls-meta.xml b/sfdx-source/apex-extensions/main/default/classes/domains/Ids.cls-meta.xml
new file mode 100644
index 0000000..db9bf8c
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/domains/Ids.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 48.0
+ Active
+
diff --git a/sfdx-source/apex-extensions/main/default/classes/domains/Integers.cls b/sfdx-source/apex-extensions/main/default/classes/domains/Integers.cls
new file mode 100644
index 0000000..5391646
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/domains/Integers.cls
@@ -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 integerSet)
+ {
+ super(new List(integerSet));
+ }
+
+ public Integers(List integerList)
+ {
+ super((List) integerList);
+ }
+
+ public Integers(List elements)
+ {
+ super(elements);
+ }
+
+ public Set getIntegerSet()
+ {
+ return new Set(getIntegers());
+ }
+
+ public List getIntegers()
+ {
+ return (List) getObjects();
+ }
+}
\ No newline at end of file
diff --git a/sfdx-source/apex-extensions/main/default/classes/domains/Integers.cls-meta.xml b/sfdx-source/apex-extensions/main/default/classes/domains/Integers.cls-meta.xml
new file mode 100644
index 0000000..db9bf8c
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/domains/Integers.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 48.0
+ Active
+
diff --git a/sfdx-source/apex-extensions/main/default/classes/domains/Longs.cls b/sfdx-source/apex-extensions/main/default/classes/domains/Longs.cls
new file mode 100644
index 0000000..d3772e6
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/domains/Longs.cls
@@ -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 longs)
+ {
+ super(new List(longs));
+ }
+
+ public Longs(List longs)
+ {
+ super((List) longs);
+ }
+
+ public Longs(List elements)
+ {
+ super(elements);
+ }
+
+ public Set getLongSet()
+ {
+ return new Set(getLongs());
+ }
+
+ public List getLongs()
+ {
+ return (List) getObjects();
+ }
+}
\ No newline at end of file
diff --git a/sfdx-source/apex-extensions/main/default/classes/domains/Longs.cls-meta.xml b/sfdx-source/apex-extensions/main/default/classes/domains/Longs.cls-meta.xml
new file mode 100644
index 0000000..db9bf8c
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/domains/Longs.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 48.0
+ Active
+
diff --git a/sfdx-source/apex-extensions/main/default/classes/domains/Objects.cls b/sfdx-source/apex-extensions/main/default/classes/domains/Objects.cls
new file mode 100644
index 0000000..e672ec2
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/domains/Objects.cls
@@ -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 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{ obj });
+ }
+
+ /**
+ * Class constructor
+ *
+ * @param objects The objects to contain inside the domain
+ */
+ public Objects(Set objects)
+ {
+ this(new List(objects));
+ }
+
+ /**
+ * Class constructor
+ *
+ * @param objects The objects to contain inside the domain
+ */
+ public Objects(List 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 objects, Object objectType)
+ {
+ super(objects);
+ this.objectType = this.objectType;
+ }
+
+ /**
+ * @return Returns a unique set of objects which are contained in the domain
+ */
+ public Set getObjectsSet()
+ {
+ return new Set(getObjects());
+ }
+}
\ No newline at end of file
diff --git a/sfdx-source/apex-extensions/main/default/classes/domains/Objects.cls-meta.xml b/sfdx-source/apex-extensions/main/default/classes/domains/Objects.cls-meta.xml
new file mode 100644
index 0000000..db9bf8c
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/domains/Objects.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 48.0
+ Active
+
diff --git a/sfdx-source/apex-extensions/main/default/classes/domains/SObjects.cls b/sfdx-source/apex-extensions/main/default/classes/domains/SObjects.cls
new file mode 100644
index 0000000..1430791
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/domains/SObjects.cls
@@ -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 objects)
+ {
+ // todo - assert of objects of type SObject
+ this((List) objects);
+ }
+
+ /**
+ * Class constructor
+ *
+ * @param records The records to contain inside the domain
+ */
+ public SObjects(List 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 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{ sObjectField });
+ }
+
+ /**
+ * Clear the field values on all the records of the domain
+ * @param sObjectFields The fields to nullify
+ */
+ @TestVisible
+ protected void clearFields(Set 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 result = new Set();
+ 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 result = new Set();
+ 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 result = new Set();
+ 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 result = new Set();
+ 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 result = new Set();
+ 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 result = new Set();
+ 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 result = new Set();
+ 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 getRecords(fflib_Criteria criteria)
+ {
+ List result = new List();
+ 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 result = new Set();
+ 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);
+ }
+}
\ No newline at end of file
diff --git a/sfdx-source/apex-extensions/main/default/classes/domains/SObjects.cls-meta.xml b/sfdx-source/apex-extensions/main/default/classes/domains/SObjects.cls-meta.xml
new file mode 100644
index 0000000..db9bf8c
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/domains/SObjects.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 48.0
+ Active
+
diff --git a/sfdx-source/apex-extensions/main/default/classes/domains/Strings.cls b/sfdx-source/apex-extensions/main/default/classes/domains/Strings.cls
new file mode 100644
index 0000000..7eec101
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/domains/Strings.cls
@@ -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 stringSet)
+ {
+ super(new List(stringSet));
+ }
+
+ public Strings(List stringList)
+ {
+ super((List) stringList);
+ }
+
+ public Strings(List elements)
+ {
+ super(elements);
+ }
+
+ /**
+ * @return Returns a set with unique values of the Strings contained in this domain
+ */
+ public Set getStringSet()
+ {
+ return new Set(getStrings());
+ }
+
+ /**
+ * @return Returns all values of the Strings contained in this domain, including duplicate values
+ */
+ public List getStrings()
+ {
+ return (List) getObjects();
+ }
+}
\ No newline at end of file
diff --git a/sfdx-source/apex-extensions/main/default/classes/domains/Strings.cls-meta.xml b/sfdx-source/apex-extensions/main/default/classes/domains/Strings.cls-meta.xml
new file mode 100644
index 0000000..db9bf8c
--- /dev/null
+++ b/sfdx-source/apex-extensions/main/default/classes/domains/Strings.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 48.0
+ Active
+
diff --git a/sfdx-source/apex-extensions/tests/classes/criteria/fflib_ComparatorTest.cls b/sfdx-source/apex-extensions/tests/classes/criteria/fflib_ComparatorTest.cls
new file mode 100644
index 0000000..cf596f4
--- /dev/null
+++ b/sfdx-source/apex-extensions/tests/classes/criteria/fflib_ComparatorTest.cls
@@ -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(), null));
+ }
+
+ private static testMethod void assertContainsDate()
+ {
+ Date myDate = Date.newInstance(1976, 6, 1);
+ System.assert(fflib_Comparator.contains(new Set {myDate}, myDate));
+ }
+
+ private static testMethod void assertContainsDateTime()
+ {
+ Datetime myDateTime = DateTime.newInstance(1976, 6, 1, 11, 55, 0);
+ System.assert(fflib_Comparator.contains(new Set {myDateTime}, myDateTime));
+ }
+
+ private static testMethod void assertContainsDouble()
+ {
+ Double myDouble = Double.valueOf(123);
+ System.assert(fflib_Comparator.contains(new Set {myDouble}, myDouble));
+ }
+
+ private static testMethod void assertContainsId()
+ {
+ Id id = fflib_IDGenerator.generate(Account.SObjectType);
+ System.assert(fflib_Comparator.contains(new Set {id}, id));
+ }
+
+ private static testMethod void assertContainsInteger()
+ {
+ Set integerSet = new Set
+ {
+ 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 {myLong}, myLong));
+ }
+
+ private static testMethod void assertContainsObject()
+ {
+ Object obj = (Object) '134';
+ System.assert(fflib_Comparator.contains(new Set{obj}, obj));
+ }
+
+ private static testMethod void assertContainsTime()
+ {
+ Time myTime = Time.newInstance(11, 55, 0, 0);
+ System.assert(fflib_Comparator.contains(new Set {myTime}, myTime));
+ }
+
+ private static testMethod void assertContainsString()
+ {
+ System.assert(fflib_Comparator.contains(new Set {'Test'}, 'Test'));
+ }
+
+ private static testMethod void assertContainsSObject()
+ {
+ Account myAccount = new Account();
+ Boolean exceptionThrown = false;
+ try
+ {
+ fflib_Comparator.contains(new Set {myAccount}, myAccount);
+ } catch (fflib_Comparator.IllegalArgumentException e)
+ {
+ exceptionThrown = true;
+ }
+ System.assert(exceptionThrown);
+
+ }
+}
\ No newline at end of file
diff --git a/sfdx-source/apex-extensions/tests/classes/criteria/fflib_ComparatorTest.cls-meta.xml b/sfdx-source/apex-extensions/tests/classes/criteria/fflib_ComparatorTest.cls-meta.xml
new file mode 100644
index 0000000..f3bac1f
--- /dev/null
+++ b/sfdx-source/apex-extensions/tests/classes/criteria/fflib_ComparatorTest.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 41.0
+ Active
+
diff --git a/sfdx-source/apex-extensions/tests/classes/criteria/fflib_CriteriaTest.cls b/sfdx-source/apex-extensions/tests/classes/criteria/fflib_CriteriaTest.cls
new file mode 100644
index 0000000..34a6250
--- /dev/null
+++ b/sfdx-source/apex-extensions/tests/classes/criteria/fflib_CriteriaTest.cls
@@ -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 {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 {idOne, idTwo})
+ .evaluate(new Account(Id = idOne))
+ );
+ }
+
+ @IsTest
+ static void itShouldEvaluateInSetCondition_Integer()
+ {
+ System.assert(
+ new fflib_Criteria()
+ .inSet(Account.NumberOfEmployees, new Set {1, 10})
+ .evaluate(new Account(NumberOfEmployees = 1))
+ );
+ }
+
+ @IsTest
+ static void itShouldEvaluateInSetCondition()
+ {
+ System.assert(
+ new fflib_Criteria()
+ .inSet(Account.Type, new Set {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 {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 {A_STRING, HELLO_WORLD})
+ .evaluate(new Account())
+ == FAILING
+ );
+ }
+
+ @IsTest
+ static void itShouldEvaluateNotInSetCondition()
+ {
+ System.assert(
+ new fflib_Criteria()
+ .notInSet(Account.Name, new Set {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 {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 {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 {idOne, idTwo})
+ .evaluate(new Account(Id = idThree))
+ );
+ }
+
+ @IsTest
+ static void itShouldEvaluateNotInSetCondition_Integer()
+ {
+ System.assert(
+ new fflib_Criteria()
+ .notInSet(Account.NumberOfEmployees, new Set {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()
+ );
+ }
+}
\ No newline at end of file
diff --git a/sfdx-source/apex-extensions/tests/classes/criteria/fflib_CriteriaTest.cls-meta.xml b/sfdx-source/apex-extensions/tests/classes/criteria/fflib_CriteriaTest.cls-meta.xml
new file mode 100644
index 0000000..f3bac1f
--- /dev/null
+++ b/sfdx-source/apex-extensions/tests/classes/criteria/fflib_CriteriaTest.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 41.0
+ Active
+
diff --git a/sfdx-source/apex-extensions/tests/classes/domains/SObjectsTest.cls b/sfdx-source/apex-extensions/tests/classes/domains/SObjectsTest.cls
new file mode 100644
index 0000000..9c1215a
--- /dev/null
+++ b/sfdx-source/apex-extensions/tests/classes/domains/SObjectsTest.cls
@@ -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 {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())
+ .getType(),
+ 'Unexpected Domain Type'
+ );
+ System.assertEquals(
+ Schema.Account.SObjectType,
+ new DomainAccounts(new List())
+ .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
+ {
+ new Account(Id = idA),
+ new Account(Id = idB),
+ new Account(Id = idC)
+ }
+ );
+
+ Set recordIds = new Set {idA, idB, idC};
+ System.assert(
+ domain.getRecordIds().containsAll(recordIds),
+ 'The domain should return all the record Ids'
+ );
+ }
+
+ @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{
+ '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
+ {
+ 'USA' => 'Hot'
+ }
+ );
+
+ System.assert(domain.selectByRating('Hot').size() == 1);
+ }
+
+ private static DomainAccounts generateDomain()
+ {
+ DomainAccounts domain = new DomainAccounts(
+ new List
+ {
+ 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 records)
+ {
+ super(records, Schema.Account.SObjectType);
+ }
+
+ public List selectByShippingCountry(String country)
+ {
+ return (List) getRecordsByFieldValues(
+ Schema.Account.ShippingCountry,
+ new Set{ country }
+ );
+ }
+
+ public List selectByRating(String rating)
+ {
+ return (List) getRecordsByFieldValue(
+ Schema.Account.Rating,
+ rating
+ );
+ }
+
+ public List selectWithoutShippingCountry()
+ {
+ return (List) getRecordsWithBlankFieldValues(
+ Schema.Account.ShippingCountry
+ );
+ }
+
+ public List selectWithShippingCountry()
+ {
+ return (List) getRecordsWithNotBlankFieldValues(
+ Schema.Account.ShippingCountry
+ );
+ }
+
+ public List selectWithEmptyRecord()
+ {
+ return (List) getRecordsWithAllBlankFieldValues(
+ new Set
+ {
+ Schema.Account.Name,
+ Schema.Account.ShippingCountry
+ }
+ );
+ }
+
+ public List selectPopulatedRecords()
+ {
+ return (List) getRecordsWithAllNotBlankFieldValues(
+ new Set
+ {
+ Schema.Account.Name,
+ Schema.Account.ShippingCountry
+ }
+ );
+ }
+
+ public void setShippingCountry(String country)
+ {
+ setFieldValue(Schema.Account.ShippingCountry, country);
+ }
+
+ public void setRatingByShippingCountry(Map 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);
+ }
+ }
+}
\ No newline at end of file
diff --git a/sfdx-source/apex-extensions/tests/classes/domains/SObjectsTest.cls-meta.xml b/sfdx-source/apex-extensions/tests/classes/domains/SObjectsTest.cls-meta.xml
new file mode 100644
index 0000000..d75b058
--- /dev/null
+++ b/sfdx-source/apex-extensions/tests/classes/domains/SObjectsTest.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 51.0
+ Active
+