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?

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.

This post is for subscribers only

Sign up now to read the post and get access to the full library of posts for subscribers only.

Sign up now Already have an account? Sign in
You’ve successfully subscribed to inteygrate
Welcome back! You’ve successfully signed in.
Great! You’ve successfully signed up.
Your link has expired
Success! Check your email for magic link to sign-in.