Add comparing to related (parent) record field values
This commit is contained in:
@@ -20,20 +20,32 @@ Adds a sub criteria with OR comparator
|
||||
Adds a sub criteria with AND comparator
|
||||
- <<equalTo, equalTo(Schema.SObjectField field, Object value)>> +
|
||||
Add an equal to criteria comparing a fields value to a given value
|
||||
- <<equalTo2, equalTo(String relatedField, Object value)>> +
|
||||
Add an equal to criteria comparing a related fields value to a given value
|
||||
- <<evaluate, evaluate(Object record)>> +
|
||||
Evaluates the stored criteria based on the given SObject
|
||||
- <<greaterOrEqualTo, greaterOrEqualTo(Schema.SObjectField field, Object value)>> +
|
||||
Compares the fields values to be greater or equal to the given value
|
||||
- <<greaterOrEqualTo2, greaterOrEqualTo(String relatedField, Object value)>> +
|
||||
Compares the related field values to be greater or equal to the given value
|
||||
- <<greaterThan, greaterThan(Schema.SObjectField field, Object value)>> +
|
||||
Compares the fields values to be greater or equal to the given value
|
||||
- <<greaterThan2, greaterThan(String relatedField, Object value)>> +
|
||||
Compares the related field values to be greater or equal to the given value
|
||||
- <<inSet, inSet(Schema.SObjectField field, Set<Object> values)>> +
|
||||
Checks if the given sets contains the fields values
|
||||
- <<lessOrEqualTo, lessOrEqualTo(Schema.SObjectField field, Object value)>> +
|
||||
Compares the fields values to be less or equal to the given value
|
||||
- <<lessOrEqualTo2, lessOrEqualTo(String relatedField, Object value)>> +
|
||||
Compares the related field values to be less or equal to the given value
|
||||
- <<lessThan, lessThan(Schema.SObjectField field, Object value)>> +
|
||||
Compares the fields values to be greater or equal to the given value
|
||||
- <<lessThan2, lessThan(String relatedField, Object value)>> +
|
||||
Compares the related field values to be greater or equal to the given value
|
||||
- <<notEqualTo, notEqualTo(Schema.SObjectField field, Object value)>> +
|
||||
Add an equal to criteria comparing a fields value to a given value
|
||||
- <<notEqualTo2, notEqualTo(String relatedField, Object value)>> +
|
||||
Add an equal to criteria comparing a related fields value to a given value
|
||||
- <<notInSet, notInSet(Schema.SObjectField field, Set<Date> values)>> +
|
||||
Checks if the given sets does not contain the fields values
|
||||
- <<toSQL, toSOQL()>> +
|
||||
@@ -67,8 +79,6 @@ new fflib_Criteria()
|
||||
___
|
||||
|
||||
|
||||
|
||||
|
||||
[[andCriteria]]
|
||||
=== andCriteria()
|
||||
Changes the default comparator for each criteria to AND. +
|
||||
@@ -181,6 +191,36 @@ new fflib_Criteria()
|
||||
// Name = 'Example'
|
||||
```
|
||||
___
|
||||
[[equalTo2]]
|
||||
=== equalTo(String relatedField, Object value)
|
||||
Add an equal to criteria comparing a related fields value to a given value
|
||||
|
||||
==== _Signature_
|
||||
```java
|
||||
public virtual fflib_Criteria equalTo(String relatedField, Object value)
|
||||
```
|
||||
==== _Parameters_
|
||||
|
||||
_**relatedField**_ +
|
||||
The related field to evaluate
|
||||
|
||||
_**value**_ +
|
||||
The value to be compared to the fields value
|
||||
|
||||
==== _Returns_
|
||||
An instance of itself to enable method chaining
|
||||
|
||||
==== _Example_
|
||||
```java
|
||||
Contact record = [SELECT Id, Account.Name FROM Contact LIMIT 1];
|
||||
new fflib_Criteria()
|
||||
.equalTo('Account.Name', 'Example')
|
||||
.evaluate(record)
|
||||
|
||||
// Evaluates:
|
||||
// Account.Name = 'Example'
|
||||
```
|
||||
___
|
||||
[[evaluate]]
|
||||
=== evaluate(Object record)
|
||||
Evaluates the stored criteria based on the given SObject
|
||||
@@ -237,6 +277,38 @@ new fflib_Criteria()
|
||||
// AnnualRevenue >= 54321
|
||||
```
|
||||
|
||||
___
|
||||
[[greaterOrEqualTo2]]
|
||||
=== greaterOrEqualTo(String relatedField, Object value)
|
||||
Compares the fields values to be greater or equal to the given value.
|
||||
Evaluates to false if the field value is null.
|
||||
|
||||
==== _Signature_
|
||||
```java
|
||||
public virtual fflib_Criteria greaterOrEqualTo(String relatedField, Object value)
|
||||
```
|
||||
==== _Parameters_
|
||||
|
||||
_**relatedField**_ +
|
||||
The relatedField name to use its value
|
||||
|
||||
_**value**_ +
|
||||
The value to be compared to the fields value
|
||||
|
||||
==== _Returns_
|
||||
An instance of itself to enable method chaining
|
||||
|
||||
==== _Example_
|
||||
```java
|
||||
Contact record = [SELECT Id, Account.AnnualRevenue FROM Contact LIMIT 1];
|
||||
new fflib_Criteria()
|
||||
.greaterOrEqualTo('Account.AnnualRevenue', 54321)
|
||||
.evaluate(record);
|
||||
|
||||
// Evaluates:
|
||||
// Account.AnnualRevenue >= 54321
|
||||
```
|
||||
|
||||
___
|
||||
[[greaterThan]]
|
||||
=== greaterThan(Schema.SObjectField field, Object value)
|
||||
@@ -267,6 +339,38 @@ new fflib_Criteria()
|
||||
// AnnualRevenue > 54321
|
||||
```
|
||||
|
||||
___
|
||||
[[greaterThan2]]
|
||||
=== greaterThan(String relatedField, Object value)
|
||||
Compares the fields values to be greater or equal to the given value
|
||||
Evaluates to false if the field value is null
|
||||
|
||||
==== _Signature_
|
||||
```java
|
||||
public virtual fflib_Criteria greaterThan(String relatedField, Object value)
|
||||
```
|
||||
==== _Parameters_
|
||||
|
||||
_**relatedField**_ +
|
||||
The relatedField name to use its value
|
||||
|
||||
_**value**_ +
|
||||
The value to be compared to the fields value
|
||||
|
||||
==== _Returns_
|
||||
An instance of itself to enable method chaining
|
||||
|
||||
==== _Example_
|
||||
```java
|
||||
Contact record = [SELECT Id, Account.AnnualRevenue FROM Contact LIMIT 1];
|
||||
new fflib_Criteria()
|
||||
.greaterThan('Account.AnnualRevenue', 54321)
|
||||
.evaluate(record);
|
||||
|
||||
// Evaluates:
|
||||
// Account.AnnualRevenue > 54321
|
||||
```
|
||||
|
||||
___
|
||||
|
||||
[[inSet]]
|
||||
@@ -327,6 +431,37 @@ new fflib_Criteria()
|
||||
// AnnualRevenue > 54321
|
||||
```
|
||||
|
||||
___
|
||||
[[lessOrEqualTo2]]
|
||||
=== lessOrEqualTo(String relatedField, Object value)
|
||||
Compares the related fields values to be less or equal to the given value
|
||||
Evaluates to true if the field value is null
|
||||
|
||||
==== _Signature_
|
||||
```java
|
||||
public virtual fflib_Criteria lessOrEqualTo(String relatedField, Object value)
|
||||
```
|
||||
==== _Parameters_
|
||||
|
||||
_**relatedField**_ +
|
||||
The relatedField name to use its value
|
||||
|
||||
_**value**_ +
|
||||
The value to be compared to the fields value
|
||||
|
||||
==== _Returns_
|
||||
An instance of itself to enable method chaining
|
||||
|
||||
==== _Example_
|
||||
```java
|
||||
Contact record = [SELECT Id, Account.AnnualRevenue FROM Contact LIMIT 1];
|
||||
new fflib_Criteria()
|
||||
.lessOrEqualTo('Account.AnnualRevenue', 54321)
|
||||
.evaluate(record);
|
||||
// Evaluates:
|
||||
// Account.AnnualRevenue > 54321
|
||||
```
|
||||
|
||||
___
|
||||
|
||||
[[lessThan]]
|
||||
@@ -358,6 +493,37 @@ new fflib_Criteria()
|
||||
// AnnualRevenue < 54321
|
||||
```
|
||||
|
||||
[[lessThan2]]
|
||||
=== lessThan(String relatedField, Object value)
|
||||
Compares the related fields values to be less or equal to the given value
|
||||
Evaluates to true if the field value is null
|
||||
|
||||
==== _Signature_
|
||||
```java
|
||||
public virtual fflib_Criteria lessThan(String relatedField, Object value)
|
||||
```
|
||||
==== _Parameters_
|
||||
|
||||
_**relatedField**_ +
|
||||
The relatedField name to use its value
|
||||
|
||||
_**value**_ +
|
||||
The value to be compared to the fields value
|
||||
|
||||
==== _Returns_
|
||||
An instance of itself to enable method chaining
|
||||
|
||||
==== _Example_
|
||||
```java
|
||||
Contact record = [SELECT Id, Account.AnnualRevenue FROM Contact LIMIT 1];
|
||||
new fflib_Criteria()
|
||||
.lessThan('Account.AnnualRevenue', 54321)
|
||||
.evaluate(record);
|
||||
|
||||
// Evaluates:
|
||||
// AnnualRevenue < 54321
|
||||
```
|
||||
|
||||
___
|
||||
|
||||
[[notEqualTo]]
|
||||
@@ -388,6 +554,36 @@ new fflib_Criteria()
|
||||
// Name != 'Example'
|
||||
```
|
||||
___
|
||||
[[notEqualTo2]]
|
||||
=== notEqualTo(String relatedField, Object value)
|
||||
Add a not equal to criteria comparing a related fields value to a given value
|
||||
|
||||
==== _Signature_
|
||||
```java
|
||||
public virtual fflib_Criteria notEqualTo(String relatedField, Object value)
|
||||
```
|
||||
==== _Parameters_
|
||||
|
||||
_**relatedField**_ +
|
||||
The relatedField name to evaluate
|
||||
|
||||
_**value**_ +
|
||||
The value to be compared to the fields value
|
||||
|
||||
==== _Returns_
|
||||
An instance of itself to enable method chaining
|
||||
|
||||
==== _Example_
|
||||
```java
|
||||
Contact record = [SELECT Id, Account.Name FROM Contact LIMIT 1];
|
||||
new fflib_Criteria()
|
||||
.notEqualTo('Account.Name', 'Example')
|
||||
.evaluate(record);
|
||||
|
||||
// Evaluates:
|
||||
// Account.Name != 'Example'
|
||||
```
|
||||
___
|
||||
|
||||
[[notInSet]]
|
||||
=== notInSet(Schema.SObjectField field, Set<Object> values)
|
||||
|
||||
@@ -166,6 +166,12 @@ public virtual with sharing class fflib_Criteria
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual fflib_Criteria equalTo(String relatedField, Object value)
|
||||
{
|
||||
evaluators.add(new RelatedFieldEvaluator(relatedField, fflib_Operator.EQUALS, value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a not equal to criteria while comparing a fields value to a given value
|
||||
*
|
||||
@@ -187,6 +193,12 @@ public virtual with sharing class fflib_Criteria
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual fflib_Criteria notEqualTo(String relatedField, Object value)
|
||||
{
|
||||
evaluators.add(new RelatedFieldEvaluator(relatedField, fflib_Operator.NOT_EQUALS, value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the stored criteria based on the given SObject
|
||||
*
|
||||
@@ -236,6 +248,12 @@ public virtual with sharing class fflib_Criteria
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual fflib_Criteria greaterOrEqualTo(String relatedField, Object value)
|
||||
{
|
||||
evaluators.add(new RelatedFieldEvaluator(relatedField, 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
|
||||
@@ -257,6 +275,11 @@ public virtual with sharing class fflib_Criteria
|
||||
evaluators.add(new FieldEvaluator(field, fflib_Operator.GREATER_THAN, value));
|
||||
return this;
|
||||
}
|
||||
public virtual fflib_Criteria greaterThan(String relatedField, Object value)
|
||||
{
|
||||
evaluators.add(new RelatedFieldEvaluator(relatedField, fflib_Operator.GREATER_THAN, value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the fields values to be less or equal to the given value
|
||||
@@ -279,6 +302,11 @@ public virtual with sharing class fflib_Criteria
|
||||
evaluators.add(new FieldEvaluator(field, fflib_Operator.LESS_THAN_OR_EQUAL_TO, value));
|
||||
return this;
|
||||
}
|
||||
public virtual fflib_Criteria lessOrEqualTo(String relatedField, Object value)
|
||||
{
|
||||
evaluators.add(new RelatedFieldEvaluator(relatedField, fflib_Operator.LESS_THAN_OR_EQUAL_TO, value));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -302,6 +330,11 @@ public virtual with sharing class fflib_Criteria
|
||||
evaluators.add(new FieldEvaluator(field, fflib_Operator.LESS_THAN, value));
|
||||
return this;
|
||||
}
|
||||
public virtual fflib_Criteria lessThan(String relatedField, Object value)
|
||||
{
|
||||
evaluators.add(new RelatedFieldEvaluator(relatedField, fflib_Operator.LESS_THAN, value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given sets contains the fields values
|
||||
@@ -568,10 +601,16 @@ public virtual with sharing class fflib_Criteria
|
||||
return result + ')';
|
||||
}
|
||||
|
||||
private interface Evaluator
|
||||
{
|
||||
Boolean evaluate(Object obj);
|
||||
String toSOQL();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic criteria handler for comparing against sets
|
||||
*/
|
||||
private class FieldSetEvaluator implements Evaluator
|
||||
private virtual class FieldSetEvaluator implements Evaluator
|
||||
{
|
||||
private Schema.SObjectField sObjectField;
|
||||
private fflib_Objects values;
|
||||
@@ -608,12 +647,6 @@ public virtual with sharing class fflib_Criteria
|
||||
}
|
||||
}
|
||||
|
||||
private interface Evaluator
|
||||
{
|
||||
Boolean evaluate(Object obj);
|
||||
String toSOQL();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic field Evaluator
|
||||
*/
|
||||
@@ -654,6 +687,99 @@ public virtual with sharing class fflib_Criteria
|
||||
}
|
||||
}
|
||||
|
||||
private abstract class AbstractRelatedFieldEvaluator implements Evaluator
|
||||
{
|
||||
protected String fieldName;
|
||||
protected fflib_Operator operator;
|
||||
|
||||
protected Object getFieldValue(Object record)
|
||||
{
|
||||
if (!fieldName.contains('.'))
|
||||
{
|
||||
return ((SObject) record).get(fieldName);
|
||||
}
|
||||
|
||||
List<String> fieldPath = fieldName.split('\\.');
|
||||
SObject relatedObject = (SObject) record;
|
||||
for (Integer i = 0; i < fieldPath.size() - 1; i++)
|
||||
{
|
||||
relatedObject = relatedObject.getSObject(fieldPath.get(i));
|
||||
}
|
||||
return relatedObject.get(fieldPath.get(fieldPath.size()-1));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class RelatedFieldEvaluator extends AbstractRelatedFieldEvaluator
|
||||
{
|
||||
private Object value;
|
||||
|
||||
public RelatedFieldEvaluator(String fieldName, fflib_Operator operator, Object value)
|
||||
{
|
||||
this.fieldName = fieldName;
|
||||
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 = getFieldValue(record);
|
||||
|
||||
return fflib_Comparator.compareTo(fieldValue, operator, this.value);
|
||||
}
|
||||
|
||||
public String toSOQL()
|
||||
{
|
||||
return String.join(
|
||||
new List<String>
|
||||
{
|
||||
this.fieldName,
|
||||
operatorToString(this.operator),
|
||||
toLiteral(this.value)
|
||||
},
|
||||
''
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private class RelatedFieldSetEvaluator extends AbstractRelatedFieldEvaluator
|
||||
{
|
||||
private fflib_Objects values;
|
||||
|
||||
public RelatedFieldSetEvaluator(String fieldName, fflib_Operator operator, fflib_Objects values)
|
||||
{
|
||||
this.fieldName = fieldName;
|
||||
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 = getFieldValue(record);
|
||||
Boolean isIn = this.values.contains(fieldValue);
|
||||
return ((operator == fflib_Operator.INx && isIn) || (operator == fflib_Operator.NOT_IN && !isIn));
|
||||
}
|
||||
|
||||
public String toSOQL()
|
||||
{
|
||||
return String.format(
|
||||
'{0} {2} {3}',
|
||||
new List<String>
|
||||
{
|
||||
this.fieldName,
|
||||
operatorToString(this.operator),
|
||||
toLiteral(this.values)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private class PropertyEvaluator implements Evaluator
|
||||
{
|
||||
private Object property;
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* File Name: fflib_MockSObjectUtil
|
||||
*
|
||||
* @author: architect ir. Wilhelmus G.J. Velzeboer
|
||||
*/
|
||||
@IsTest
|
||||
public with sharing class fflib_MockSObjectUtil
|
||||
{
|
||||
public static SObject addRelatedParentObject(SObject childObject, SObject parentObject, String relationshipField)
|
||||
{
|
||||
String original = JSON.serialize(childObject);
|
||||
return (SObject) JSON.deserialize(
|
||||
original.left(original.length() - 1) +
|
||||
',"' + relationshipField + '":' +
|
||||
JSON.serialize(parentObject) + '}',
|
||||
SObject.class);
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||
<apiVersion>51.0</apiVersion>
|
||||
<status>Active</status>
|
||||
</ApexClass>
|
||||
@@ -550,4 +550,23 @@ private with sharing class fflib_CriteriaTest
|
||||
.toSOQL()
|
||||
);
|
||||
}
|
||||
|
||||
@IsTest
|
||||
static void itShouldEvaluateValuesOnRelatedObject()
|
||||
{
|
||||
// GIVEN a Contact record with related Account records
|
||||
Contact contact = new Contact(LastName = 'Smith');
|
||||
Account account = new Account(
|
||||
Id = fflib_IDGenerator.generate(Account.SObjectType),
|
||||
Name = 'Dummy'
|
||||
);
|
||||
SObject record = fflib_MockSObjectUtil.addRelatedParentObject(contact, account, 'Account');
|
||||
|
||||
// WHEN we run a criteria con the contact record validating related data on the parent Account
|
||||
System.assert(
|
||||
new fflib_Criteria()
|
||||
.equalTo('Account.Name', 'Dummy')
|
||||
.evaluate(record)
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user