To explain correctly the problem I must start with an example let's say I have a list of users like this
[
{ "name": "John", "surname": "Doe", "age": 22 },
{ "name": "Syrus", "surname": "Black", "age": 20 }
]
And I have also a JSONObject representing a condition that must be matched like this:
{
"OR":[
{ "name": { "eq": "John"} },
{ "AND":[
{ "name": { "eq": "Syrus"} },
{ "age": { "gt": 18 } }
] }
]
}
Which should be translated in:
name = "John" OR (name = "Syrus" AND age > 18)
Now I have to make the code that given the JSONObject condition and the list of the users checks for each users if the condition is matched.
At the moment this is what I have done:
import java.util.Set;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.BiConsumer;
import com.query.Queryable;
import org.json.JSONArray;
import org.json.JSONObject;
public class QueryableTreeMap<K,V extends JSONObject> extends TreeMap<K,V> implements Queryable<JSONObject,JSONObject> {
private static final long serialVersionUID = 2586026774025401270L;
private static boolean test(Set<Map.Entry<String, Object>> condition, JSONObject value){
boolean isValid = true;
Iterator<Map.Entry<String, Object>> iter = condition.iterator();
while(iter.hasNext()){
Map.Entry<String, Object> subcond = iter.next();
if(subcond.getKey().equals("OR")){
//isValid = isValid || test((Set<Map.Entry<String, Object>>) subcond.getValue(), value);
} else if(subcond.getKey().equals("AND")){
//isValid = isValid && test((Set<Map.Entry<String, Object>>) subcond.getValue(), value);
} else if(subcond.getKey().equals("NOT")){
} else {
}
}
return isValid;
}
@Override
public JSONObject query(JSONObject query) {
// the set containing the conditions
Set<Map.Entry<String, Object>> entries = query.toMap().entrySet();
// the JSONArray with containing the records that match the condition
JSONArray array = new JSONArray();
// for each JSONObject inside this structure
this.forEach(new BiConsumer<K,JSONObject>(){
@Override
public void accept(K key, JSONObject value) {
// testing if the current record matches the condition
if(test(entries, value)) array.put(value);
}
});
// returns a JSONObject containing a JSONArray that contains the records that match the condition
return new JSONObject(array);
}
}
I am currently stuck in the test method which should in-fact test if the given object matches the given condition.
I don't mind changing the format of the JSON condition as long as it is a JSONObject.
At the moment i have come up with a partial solution that builds an object called Condition that represents the boolean expression inside the JSONObject (not very efficient but still a possible solution) this is obviously not working at the moment, i need help on what i should do now
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Condition {
private Condition left, right;
private String boolExpr, key, value;
private boolean not;
private int operationType; // greater then, less then, equal to, greater or equal of, less or equal of
public Condition(Map<String, Object> map) {
Set<Map.Entry<String, Object>> set = map.entrySet();
Iterator<Map.Entry<String, Object>> iterator = set.iterator();
while(iterator.hasNext()){
Object entry = iterator.next();
System.out.println(entry);
System.out.println(entry.getClass());
if(entry instanceof Map.Entry) {
String key = (String) ((Map.Entry) entry).getKey();
switch(key){
case "AND":
case "OR":
this.boolExpr = key;
break;
case "eq":
case "gt":
case "lt":
case "gte":
case "lte":
this.operationType = getOperationTypeFromString(key);
break;
case "NOT":
this.not = true;
break;
default:
this.key = key;
break;
}
}
}
}
public int getOperationTypeFromString(String operation) {
switch(operation){
case "eq":
return 0;
case "gt":
return 1;
case "lt":
return 2;
case "gte":
return 3;
case "lte":
return 4;
default:
return 0;
}
}
}
I would prefer not to use the Condition class and just use the JSONObject instead. I am using the org.json JSON-Java parser.