0

Is it possible to implement this function in apex?

where_str Value should be

'(Mobile__c = null OR Store__r.Name = null) AND Name != null'

String filter_str = '(1 OR 2) AND 3';
String json_str = '[{"keyVal":1,"field":"Mobile__c","condition":"=","value":"null"},{"keyVal":2,"field":"Store__r.Name","condition":"=","value":"null"},{"keyVal":3,"field":"Name","condition":"!=","value":"null"}]';

List<optWrapper> opts = (List<optWrapper>)JSON.deserialize(json_str, List<optWrapper>.class);
for (Integer i = 0; i < opts.size(); i++) {
    System.debug(LoggingLevel.INFO, 'i = ' + i);
    if (opts[i].keyVal == i+1) {
        filter_str = filter_str.replace(String.valueOf(i+1), opts[i].field + opts[i].condition + opts[i].value);
    }
}
System.debug(LoggingLevel.INFO, 'filter_str = ' + filter_str);

public class optWrapper{
    public Integer keyVal;
    public String field;
    public String condition;
    public String value;
}
3
  • Yes you can parse JSON and build strings in Apex. Keep going - just needs a bit of time investing. And if you are at all familiar with unit tests, I recommended using unit tests to provide your logic is working as you add to it.
    – Keith C
    Commented Nov 9, 2020 at 9:56
  • 2
    I agree with Keith C but would ask why you are doing it this way? And if you do continue this way, I recommend you use regex matching for the numeric placeholders to ensure you consider "word break" characters otherwise you might have false matches (e.g. "1" might falsely match the "10" in "(10 OR 9) AND (8 OR 7)...")
    – Phil W
    Commented Nov 9, 2020 at 10:15
  • ** Pattern regex = Pattern.compile('[0-9]'); Matcher regexMatcher = regex.matcher('(1 OR 2) AND 3'); while (regexMatcher.find() == true) { System.debug(LoggingLevel.INFO, '***' + regexMatcher.group()); } ** Through your tips, I did this step. Still stuck on the replacement, can you give me an example?
    – Zhang Ou
    Commented Nov 10, 2020 at 2:49

1 Answer 1

0

I suggest you to run through the pattern string and extract full numeric values on run, then replace them with suitable condition and move further (I have stored condition parts in Map, so there will be no misconception, if any keyVal may be omitted):

private static Map<String, Integer> getKeyValMap(List<Integer> patternChars, Integer startingPos) {
    String keyVal = String.fromCharArray(new List<Integer>{patternChars[startingPos]});
    Integer lastPos = startingPos;
    for (Integer i = startingPos + 1, n = patternChars.size(); i < n; i++) {
        String currentChar = String.fromCharArray(new List<Integer>{patternChars[i]});
        if (currentChar.isNumeric()) {
            keyVal += currentChar;
            lastPos = i;
        } else {
            break;
        }
    }
    return new Map<String, Integer>{
            'keyVal' => Integer.valueOf(keyVal),
            'lastPos' => lastPos
    };
}

public static String getCondition(String pattern, Map<Integer, String> conditionParts) {
    String condition = '';

    List<Integer> patternChars = pattern.getChars();
    for (Integer i = 0, n = patternChars.size(); i < n; i++) {
        String currentChar = String.fromCharArray(new List<Integer>{patternChars[i]});
        if (currentChar.isNumeric()) {
            Map<String, Integer> keyValMap = getKeyValMap(patternChars, i);
            condition += conditionParts.get(keyValMap.get('keyVal'));
            i = keyValMap.get('lastPos');
        } else {
            condition += currentChar;
        }
    }

    return condition;
}

You may get conditionParts map with this method:

public static Map<Integer, String> getConditionParts(String jsonString) {
    Map<Integer, String> conditionParts = new Map<Integer, String>();
    for (Object tmp : (List<Object>) JSON.deserializeUntyped(jsonString)) {
        Map<String, Object> conditionPart = (Map<String, Object>) tmp;
        conditionParts.put(
                (Integer) conditionPart.get('keyVal'),
                (String) conditionPart.get('field') + (String) conditionPart.get('condition') + (String) conditionPart.get('value')
        );
    }
    return conditionParts;
}

I have tested it on several examples and it looks fine:

@IsTest
static void test_getCondition() {
    String jsonString = '[{"keyVal":1,"field":"Mobile__c","condition":"=","value":"null"},{"keyVal":2,"field":"Store__r.Name","condition":"=","value":"null"},{"keyVal":3,"field":"Name","condition":"!=","value":"null"}]';
    Map<Integer, String> conditionParts = ConditionBuilder.getConditionParts(jsonString);
    String pattern = '(1 OR 2) AND 3';
    String condition = ConditionBuilder.getCondition(pattern, conditionParts);
    System.assertEquals('(Mobile__c=null OR Store__r.Name=null) AND Name!=null', condition);

    jsonString = '[{"keyVal":10,"field":"A","condition":"=","value":"2"},{"keyVal":2,"field":"B","condition":"=","value":"\'x\'"}]';
    conditionParts = ConditionBuilder.getConditionParts(jsonString);
    pattern = '10 AND 2';
    condition = ConditionBuilder.getCondition(pattern, conditionParts);
    System.assertEquals('A=2 AND B=\'x\'', condition);
}

Also, if you may know any better way to operate with chars in Apex Stings, please, tell me, I'm wondering if it is one though.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .