Tweet |
Image created by ChatGPT4o based on a prompt by Bob Buzzard
Introduction
Like zip handling in Apex, the ability to evaluate dynamic formulas in Apex is Generally Available in the Spring '25 release of Salesforce. Unlike zip handling, which we've all been wanting/battling with for years, this might not be such an obvious win. It's definitely something I could have used a few times in my Salesforce career, mostly around rule engines. I've written several of these in my time, to do things like apply a discount to a price based on a number of attributes of a customer, their spend, and whether they have a contract with us.
In order to avoid everyone having to become an Apex or Flow expert, rules are configured through custom settings or custom metadata types, but defining the criteria to execute rules is a bit more tricky to surface for Administrator configuration, especially if you need to look at the values contained by a specific record. Then it's a toss up between express it in pro/low code and make it less configurable, or write something to validate and parse boolean style expressions including records and fields. Neither are great.
With the ability to evaluate formula fields in Apex, Admins can express criteria in a familiar format and this can easily be evaluated by the engine to decide whether to apply the rule.
The Sample
The examples I'd seen to date were mostly querying a record from the database and evaluating a formula to concatenate some fields against it, but I didn't find that overly exciting. Instead I went a different route - as I'm envisaging an Administrator creating the formula as plain text in a configuration record, so it would be useful to allow them to check it works before settling on it. I guess it could also be used to test someone's ability to create valid formulas without needing to go into Setup and create a field. So many possibilities!
The page itself is a pretty simple:
There's a picklist to choose the sobject type (limited to Account, Opportunity and Contact - this is a demo after all), another picklist to choose the formula return type, and a lookup to select the record to use when evaluating the formula. In this case my test record is in the Technology business and doing pretty well with annual revenue of ten million:
My rule should fire if the candidate account is in the technology business and making less than fifty million a year, so lets try that out:
And it works. But this is hardly an exhaustive test, so lets check what happens if I change the revenue target to less than nine million a year:
Which also works. But why is the result displayed in green regardless of whether it is true or false? Because the formula evaluated successfully of course - if I introduce an error into my formula, and try to compare the website to a numeric value, the result is red :
Show Me The Code!
You can find the code in my Spring '25 samples Github repository. The method to evaluate the formula is as follows:
@AuraEnabled public static String CheckFormula(String formulaStr, String sobjectType, String returnTypeStr, Id recordId) { FormulaEval.FormulaReturnType returnType= FormulaEval.FormulaReturnType.valueof(returnTypeStr); FormulaEval.FormulaInstance formulaInstance = Formula.builder() .withType(Type.forName(sobjectType)) .withReturnType(returnType) .withFormula(formulaStr) .build(); String fieldNameList = String.join(formulaInstance.getReferencedFields(),','); String queryStr = 'select ' + fieldNameList + ' from ' + sobjectType + ' where id=:recordId LIMIT 1'; SObject s = Database.query(queryStr); Object formulaResult=formulaInstance.evaluate(s); return formulaResult.toString(); }
The information populated by the user through the various inputs is passed through verbatim and uses to build the formula instance. One aspect that has changed since I used the original beta is the ability to have the formula instance tell me which fields I need to query from the record via the getReferencedFields method, so I can drop them into my dynamic query with minimal effort:
String fieldNameList = String.join(formulaInstance.getReferencedFields(),','); String queryStr = 'select ' + fieldNameList + ' from ' + sobjectType + ' where id=:recordId LIMIT 1'; SObject s = Database.query(queryStr);
More Information
- Repo with sample code
- Release notes for this feature
- FormulaEval Namespace in the Apex Reference Guide