Merge pull request #32 from wimvelzeboer/feature/AddContainsAndLikeToCriteria

Add LIKE and Contains condition to Criteria
This commit is contained in:
William Velzeboer
2022-02-25 11:16:44 +00:00
committed by GitHub
3 changed files with 118 additions and 29 deletions
@@ -33,8 +33,15 @@ public with sharing class fflib_Comparator
public static Boolean compareTo(Object object1, fflib_Operator operator, Object object2) public static Boolean compareTo(Object object1, fflib_Operator operator, Object object2)
{ {
Integer result = compare(object1, object2); if (operator == fflib_Operator.LIKEx)
{
String value1 = String.valueOf(object1);
String value2 = String.valueOf(object2);
if (value1 == null || value2 == null) return false;
return value1.contains(value2);
}
Integer result = compare(object1, object2);
if (operator == fflib_Operator.EQUALS && result == 0) if (operator == fflib_Operator.EQUALS && result == 0)
return true; return true;
else if (operator == fflib_Operator.NOT_EQUALS && result != 0) else if (operator == fflib_Operator.NOT_EQUALS && result != 0)
@@ -323,6 +323,32 @@ public virtual with sharing class fflib_Criteria
} }
} }
/**
* Add a criteria checking if a fields value contains the given value
*
* @param field The sObjectField to evaluate
* @param value The value to be compared to the fields value
*
* @return An instance of itself to enable method chaining
*
* @example
* new fflib_Criteria()
* .equalTo(Account.Name, 'Example')
*
* Evaluates:
* SOQL
* Name LIKE '%Example%'
*
* Condition
* 'My Condition Example'.contains('Example')
*/
public virtual fflib_Criteria contains(Schema.SObjectField field, Object value)
{
evaluators.add(new FieldEvaluator(field, fflib_Operator.LIKEx, value));
return this;
}
/** /**
* Add an equal to criteria comparing a fields value to a given value * Add an equal to criteria comparing a fields value to a given value
* *
@@ -820,15 +846,15 @@ public virtual with sharing class fflib_Criteria
else if (operator == fflib_Operator.GREATER_THAN_OR_EQUAL_TO) else if (operator == fflib_Operator.GREATER_THAN_OR_EQUAL_TO)
return '>='; return '>=';
else if (operator == fflib_Operator.LIKEx) else if (operator == fflib_Operator.LIKEx)
return 'LIKE'; return ' LIKE ';
else if (operator == fflib_Operator.INx) else if (operator == fflib_Operator.INx)
return 'IN'; return ' IN ';
else if (operator == fflib_Operator.NOT_IN) else if (operator == fflib_Operator.NOT_IN)
return 'NOT IN'; return ' NOT IN ';
else if (operator == fflib_Operator.INCLUDES) else if (operator == fflib_Operator.INCLUDES)
return 'INCLUDES'; return ' INCLUDES ';
else if (operator == fflib_Operator.EXCLUDES) else if (operator == fflib_Operator.EXCLUDES)
return 'EXCLUDES'; return ' EXCLUDES ';
else else
return null; return null;
} }
@@ -875,7 +901,9 @@ public virtual with sharing class fflib_Criteria
} }
throw new CriteriaException( throw new CriteriaException(
'invalid value; value must a primitive type (String|Id|Boolean|Integer|Long|Double|Decimal|Date|Datetime)' String.format(
'invalid value \'{0}\'; value must a primitive type (String|Id|Boolean|Integer|Long|Double|Decimal|Date|Datetime)',
new List<String> {String.valueOf(value)})
); );
} }
@@ -906,6 +934,52 @@ public virtual with sharing class fflib_Criteria
String toSOQL(); String toSOQL();
} }
private abstract class ToSOQL
{
protected String toSOQL(Schema.SObjectField sObjectField, fflib_Operator operator, Object value)
{
return toSOQL(sObjectField, operator, toLiteral(value));
}
protected String toSOQL(String fieldName, fflib_Operator operator, Object value)
{
return toSOQL(fieldName, operator, toLiteral(value));
}
protected String toSOQL(Schema.SObjectField sObjectField, fflib_Operator operator, String value)
{
return toSOQL(sObjectField.getDescribe().getName(), operator, value);
}
protected String toSOQL(String fieldName, fflib_Operator operator, String value)
{
if (operator == fflib_Operator.LIKEx)
return toLikeSOQL(fieldName, operator, value);
else
return toNonLikeSOQL(fieldName, operator, value);
}
private String toLikeSOQL(String fieldName, fflib_Operator operator, String value)
{
if (value.startsWith('\'')) value = value.right(value.length() - 1);
if (value.endsWith('\'')) value = value.left(value.length() - 1);
return toNonLikeSOQL(fieldName, operator, '\'%' + value + '%\'');
}
protected String toNonLikeSOQL(String fieldName, fflib_Operator operator, String value)
{
return String.join(
new List<String>
{
fieldName,
operatorToString(operator),
value
},
''
);
}
}
/** /**
* Generic criteria handler for comparing against sets * Generic criteria handler for comparing against sets
*/ */
@@ -935,7 +1009,7 @@ public virtual with sharing class fflib_Criteria
public String toSOQL() public String toSOQL()
{ {
return String.format( return String.format(
'{0} {1} {2}', '{0}{1}{2}',
new List<String> new List<String>
{ {
this.sObjectField.getDescribe().getName(), this.sObjectField.getDescribe().getName(),
@@ -949,7 +1023,7 @@ public virtual with sharing class fflib_Criteria
/** /**
* Generic field Evaluator * Generic field Evaluator
*/ */
private class FieldEvaluator implements Evaluator private class FieldEvaluator extends ToSOQL implements Evaluator
{ {
private Schema.SObjectField sObjectField; private Schema.SObjectField sObjectField;
private Object value; private Object value;
@@ -974,19 +1048,11 @@ public virtual with sharing class fflib_Criteria
public String toSOQL() public String toSOQL()
{ {
return String.join( return toSOQL(this.sObjectField, this.operator, this.value);
new List<String>
{
this.sObjectField.getDescribe().getName(),
operatorToString(this.operator),
toLiteral(this.value)
},
''
);
} }
} }
private abstract class AbstractRelatedFieldEvaluator implements Evaluator private abstract class AbstractRelatedFieldEvaluator extends ToSOQL implements Evaluator
{ {
protected String fieldName; protected String fieldName;
protected fflib_Operator operator; protected fflib_Operator operator;
@@ -1035,15 +1101,7 @@ public virtual with sharing class fflib_Criteria
public String toSOQL() public String toSOQL()
{ {
return String.join( return toSOQL(this.fieldName, operator, this.value);
new List<String>
{
this.fieldName,
operatorToString(this.operator),
toLiteral(this.value)
},
''
);
} }
} }
@@ -1071,7 +1129,7 @@ public virtual with sharing class fflib_Criteria
public String toSOQL() public String toSOQL()
{ {
return String.format( return String.format(
'{0} {1} {2}', '{0}{1}{2}',
new List<String> new List<String>
{ {
this.fieldName, this.fieldName,
@@ -79,6 +79,30 @@ private with sharing class fflib_CriteriaTest
); );
} }
@IsTest
static void itShouldEvaluateAnContainsCondition()
{
fflib_Criteria criteria = new fflib_Criteria()
.contains(Account.Name, A_STRING);
System.assert(criteria.evaluate(new Account(Name = SAME_STRING)));
System.assert(criteria.evaluate(new Account(Name = 'prefix ' + SAME_STRING)));
System.assert(criteria.evaluate(new Account(Name = SAME_STRING + ' suffix')));
System.assert(criteria.evaluate(new Account(Name = 'prefix ' + SAME_STRING + ' suffix')));
System.assertEquals('Name LIKE \'%' + A_STRING + '%\'', criteria.toSOQL());
}
@IsTest
static void itShouldEvaluateAnContainsCondition_nullField()
{
fflib_Criteria criteria = new fflib_Criteria()
.contains(Account.Name, null);
System.assert(false == criteria.evaluate(new Account(Name = SAME_STRING)));
System.assert(false == criteria.evaluate(new Account(Name = 'prefix ' + SAME_STRING)));
System.assert(false == criteria.evaluate(new Account(Name = SAME_STRING + ' suffix')));
System.assert(false == criteria.evaluate(new Account(Name = 'prefix ' + SAME_STRING + ' suffix')));
System.assertEquals('Name LIKE \'%null%\'', criteria.toSOQL());
}
@IsTest @IsTest
static void itShouldEvaluateAnEqualsToCondition() static void itShouldEvaluateAnEqualsToCondition()
{ {