1

In a workflow you can define logic like

( (1 AND 2) OR 3 ) AND 4

I need to build configurable criteria that will do something similar in structure, but with more complex criteria. For example, I'd have an sObject called Rule__c that is a master to an sObject called Criteria__c. Each Criteria__c row would contain an Enum that would be used to run a Boolean function in Apex as well as a number to be used in the logic. Where I get stuck is translating a configurable string like ( (1 AND 2) OR 3 ) AND 4 into dynamic code.

Salesforce does it, tools like FormAssembly and Wufoo do it, so I don't think it's an outrageous task, but but I have no idea where to start or what to even search for in Google. Any tips?

  • 1
    I haven't tried to use it but came across this SFDCRules a while ago. I assume it is open source but best to check with the author to be sure if you wanted to use it. There are probably other open source expression parsers you could consider too. Or write yourself, – Keith C Dec 17 '17 at 16:07
  • Expression parser! @KeithC, that's exactly what I need to get going, thank you! – Sean Dec 17 '17 at 16:12
2

I think you are looking for the Composite Apex Design Pattern. You are familiar with this pattern already for its implementation in the Selector library.

I highly recommend to any developer to read through the entire Apex Design Patterns article.

I took a different tack than the Selector library in my implementation of Predicate logic I built out for a fluent query builder. I've stripped out the parts related to query building as you would need to take it in a different direction:

public virtual class Predicate
{
    final List<Predicate> children;

    Predicate(Predicate left, Predicate right)
    {
        children = new List<Predicate>();
        if (!sharesType(left)) children.add(left);
        else children.addAll(left.children);
        if (!sharesType(right)) children.add(right);
        else children.addAll(right.children);
    }

    @TestVisible virtual String getDelimiter() { return null; }
    @TestVisible virtual Boolean sharesType(Predicate that) { return false; }

    public Predicate andX(Predicate that) { return new AndPredicate(this, that); }
    public Predicate andX(Expression expression) { return andX(new Predicate(expression)); }
    public Predicate orX(Predicate that) { return new OrPredicate(this, that); }
    public Predicate orX(Expression expression) { return orX(new Predicate(expression)); }

    class AndPredicate extends Predicate
    {
        AndPredicate(Predicate left, Predicate right) { super(left, right); }
        override Boolean sharesType(Predicate that) { return that instanceOf AndPredicate; }
        override String getDelimiter() { return ' AND '; }
    }
    class OrPredicate extends Predicate
    {
        OrPredicate(Predicate left, Predicate right) { super(left, right); }
        override Boolean sharesType(Predicate that) { return that instanceOf OrPredicate; }
        override String getDelimiter() { return ' OR '; }
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.