A pure apex based Boolean Engine to evaluate sObject records without any formula field

A pure apex based Boolean Engine to evaluate sObject records without any formula field

Have you come across a coding design challenge where you want to check if an sObject record (either newly instantiated or queried - updated - but yet to be committed) satisfies a condition before committing the record? And the condition is required to be fetched dynamically from a configuration. The first thought that comes to our mind is of having a formula field only to later realize that the formula fields doesn't evaluate during an sObject initialization and even for a queried record the formula doesn't reflect an updated value even when the constituent field(s) of the expression is updated - and yet to be committed for a re-query.

We do have Formula class to force that evaluation to be done before committing the record but even then, we might end up creating n formula fields for n different condition check. And therefore this necessity is what led to the mini invention of a Boolean Engine that can help us evaluate a condition in the form of a Boolean expression.

The Design

Boolean Engine Design

Usage

The main class is BooleanEngine with a zero argument constructor and the below methods.

Namespace

inteygratemf

BooleanEngine Methods

The following are methods for BooleanEngine.

  • compile(expression)
    Tokenizes the String expression and builds a Boolean expression using Composite Design Pattern. The method returns the same instance of BooleanEngine that is used to invoke the method, and can be chained with other methods i.e. evaluate() and filter(). The list of operators allowed are ==, !=, <,>,<=,>=
  • evaluate(sObject)
    Evaluates the sObject against the compiled expression done using compile() method and returns true if it satisfies the condition else false. If the expression compilation doesn't produce any result then this method will return NULL
  • evaluate(sObjectMap)
    Evaluates the records in sObjectMap against the compiled expression done using compile() method and returns a Boolean map with keys same as passed to the method.  If the sObject record satisfies the condition it sets true against its key else false. If the expression compilation doesn't produce any result then the values for all keys will be NULL
  • filter(sObjectList)
    Evaluates the records in sObjectList against the compiled expression done using compile() method and returns the filtered list of only those sObject records that satisfies the condition; thus acting as an UN-SOQL: query language for uncommitted records.

Examples

Opportunity o1 = new Opportunity
                        (Name='Inteygrate',
                         ExtId__c='inteygrate_ext_id1',
                         Amount=100000,
                         StageName='Prospecting'
                        );

Opportunity o2 = new Opportunity
                        (Name='Test',
                         ExtId__c='Test_ext_id',
                         Amount=100000,
                         StageName='Prospecting'
                        );
                        
inteygratemf.BooleanEngine be = new inteygratemf.BooleanEngine();

String expr1 = '(Name == "Inteygrate" && Amount > 10) || (Name == "test 2"&&Amount < 10)';
System.debug(be.compile(expr1).evaluate(new Map<String,Opportunity>{o1.ExtId__c=>o1,o2.ExtId__c=>o2}));
/*OUTPUT:{inteygrate_ext_id1=true, Test_ext_id=false}*/

String expr2 = 'Name != "Test" && Amount >= 50';

System.debug(be.compile(expr2).filter(new List<Opportunity>{o1,o2}));
/*OUTPUT:(Opportunity:{Name=Inteygrate, Amount=100000, StageName=Prospecting})*/

String expr3 = 'Name != "Test" && Amount <= 90';
System.debug(be.compile(expr3).evaluate(o1));
/*OUTPUT:false*/

String expr4 = 'Name != "Test" && Amount >= 90';
System.debug(be.compile(expr4).evaluate(o1));
/*OUTPUT:true*/

How is it different from a simple if - else statement?

With an if-else statement we cannot have a configured condition evaluated dynamically. On the other hand a configured query expression will only work on committed records to be queried using SOQL. But what if you have a new list of sObject records which are yet to be committed?

Or try the Beta

Below is the link of the beta package that can be installed in any of your org to try out the engine. Leave your feedback/suggestions in the comments if any.

https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001wMfp

Note: Currently there is no support for comparing dates. Could be added in future updates
About the author
Muralidhar Sampathirao

Muralidhar Sampathirao

Sr Technical Consultant @ Salesforce • With thrdz I am designing the building blocks for Enterprise Applications • Articles, opinions and resources expressed/shared are entirely my personal views.

THR(EA)DZ

DZining the building blocks for Enterprise Applications

THR(EA)DZ

Great! You’ve successfully signed up.

Welcome back! You've successfully signed in.

You've successfully subscribed to THR(EA)DZ.

Success! Check your email for magic link to sign-in.

Success! Your billing info has been updated.

Your billing was not updated.