
automately.core.data.predicates.JsonQueryPredicate Maven / Gradle / Ivy
package automately.core.data.predicates;
import com.hazelcast.query.Predicate;
import io.jsync.json.JsonArray;
import io.jsync.json.JsonElement;
import io.jsync.json.JsonObject;
import io.jsync.json.impl.Json;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Map;
/**
* A simple Hazelcast Predicate that allows you to filter data using
* queries in the form of a JsonObject.
*/
public class JsonQueryPredicate implements Serializable, Predicate {
private JsonElement query;
public JsonQueryPredicate(JsonElement query) {
if(query == null){
throw new RuntimeException("Your query cannot be null");
}
this.query = query;
}
@Override
public boolean apply(Map.Entry entry) {
Object obj = entry.getValue();
if(obj instanceof JsonObject && query.isObject()){
// Since the entry is a single JsonObject we will match a single
return processJsonObjectQuery((JsonObject) obj, query.asObject());
} else if(obj instanceof JsonObject && query.isArray()){
// We can loop through the query array to check each query against the value
for(Object q : query.asArray()){
// Since the query is an actual JsonObject we can treat it as a Json Query
if(q instanceof JsonObject){
JsonObject jsonQuery = (JsonObject) q;
if(processJsonObjectQuery((JsonObject) obj, jsonQuery)){
return true;
}
}
}
} else if(obj instanceof JsonArray){
// Loop through all the values in this entry
// If any value matches we will return this entry
for(Object inObj : (JsonArray) obj){
// If the value is a json object we will process it with the query array
if(inObj instanceof JsonObject){
JsonObject jsonVal = (JsonObject) inObj;
if(query.isObject()){
if(processJsonObjectQuery(jsonVal, query.asObject())){
return true;
}
} else {
// We can loop through the query array to check each query against the value
for(Object q : query.asArray()){
// Since the query is an actual JsonObject we can treat it as a Json Query
if(q instanceof JsonObject){
JsonObject jsonQuery = (JsonObject) q;
if(processJsonObjectQuery(jsonVal, jsonQuery)){
return true;
}
}
}
}
}
}
}
// If no JsonObjects were found we will return false by default since we are looking for Json Data
return false;
}
private boolean processJsonObjectQuery(JsonObject value, JsonObject query){
// An empty query is the same as a wildcard but without a value
if(query.size() == 0){
return true;
}
// We return false for sure because that doesn't even make sense
if(query.size() > value.size()){
return false;
}
JsonObject valueObj = value;
boolean success = false;
for(String field : query.getFieldNames()){
Object queryValue = query.getValue(field);
if(field.contains(".")){
String[] subFields = field.split("\\.");
JsonObject newValue = null;
String newField = null;
for(String sub : subFields){
if(newValue == null){
if(value.containsField(sub) && value.getValue(sub) instanceof JsonObject){
newValue = value.getObject(sub);
continue;
}
break;
}
newField = sub;
if(newValue.containsField(sub) && newValue.getValue(sub) instanceof JsonObject){
newValue = newValue.getObject(sub);
}
}
if(newValue != null && newField != null && field.endsWith("." + newField)){
valueObj = newValue;
field = newField;
}
}
// If it doesn't contain the field we cannot match it.
if(!valueObj.containsField(field)){
return false;
}
// This is the object we are checking
Object value2 = valueObj.getValue(field);
if(value2 instanceof JsonArray){
JsonArray array = (JsonArray) value2;
for(Object val : array.toArray()){
if(checkValue(queryValue, val)){
success = true;
}
}
// if it's an array let's loop through it
} else {
if(checkValue(queryValue, value2)){
success = true;
} else {
return false;
}
}
}
// An empty query is the same as a wildcard but without a value
return success;
}
private static boolean checkValue(Object queryVal, Object value2){
if(queryVal.equals(value2)){
return true;
} else if(queryVal instanceof String && queryVal.toString().equals("*")){
return true;
} else if(queryVal instanceof String && queryVal.toString().matches("^v>\\d+$") && value2 instanceof Number){
Number numb1 = Long.parseLong(queryVal.toString().split(">")[1]);
Number numb2 = (Number) value2;
if(compareTo(numb2, numb1) > 0){
return true;
}
} else if(queryVal instanceof String && queryVal.toString().matches("^v<\\d+$") && value2 instanceof Number){
Number numb1 = Long.parseLong(queryVal.toString().split("<")[1]);
Number numb2 = (Number) value2;
if(compareTo(numb2, numb1) < 0){
return true;
}
} else if(queryVal instanceof String && queryVal.toString().matches("^v>=\\d+$") && value2 instanceof Number){
Number numb1 = Long.parseLong(queryVal.toString().split(">=")[1]);
Number numb2 = (Number) value2;
if(compareTo(numb2, numb1) >= 0){
return true;
}
} else if(queryVal instanceof String && queryVal.toString().matches("^v<=\\d+$") && value2 instanceof Number){
Number numb1 = Long.parseLong(queryVal.toString().split("<=")[1]);
Number numb2 = (Number) value2;
if(compareTo(numb2, numb1) <= 0){
return true;
}
} else if(queryVal instanceof String && queryVal.toString().matches("^v=\\d+$") && value2 instanceof Number){
Number numb1 = Long.parseLong(queryVal.toString().split("=")[1]);
Number numb2 = (Number) value2;
if(compareTo(numb2, numb1) == 0){
return true;
}
} else if(queryVal instanceof String && queryVal.toString().matches("^v==\\d+$") && value2 instanceof Number){
Number numb1 = Long.parseLong(queryVal.toString().split("==")[1]);
Number numb2 = (Number) value2;
if(compareTo(numb2, numb1) == 0){
return true;
}
} else if(queryVal instanceof String && queryVal.toString().matches("^v!=\\d+$") && value2 instanceof Number){
Number numb1 = Long.parseLong(queryVal.toString().split("!=")[1]);
Number numb2 = (Number) value2;
if(compareTo(numb2, numb1) != 0){
return true;
}
} else if(queryVal instanceof Boolean && value2 instanceof Boolean){
if(queryVal == value2){
return true;
}
} else if(queryVal instanceof String && value2 instanceof String){
if(((String) value2).matches((String) queryVal)){
return true;
}
} else if(queryVal instanceof JsonArray){
JsonArray queryArray = (JsonArray) queryVal;
// We check the value against an array of query stuff
for(Object qv : queryArray){
if(checkValue(qv, value2)){
return true;
}
}
} else if(queryVal instanceof JsonObject){
// JSON objects are more like mongo queries
JsonObject queryObj = (JsonObject) queryVal;
// By default an empty query value
boolean success = false;
for(String newF : queryObj.getFieldNames()){
Object obj = queryObj.getValue(newF);
if(obj != null){
// We already know they key exists or we would not be doing this
if(newF.equals("$exists") && obj instanceof Boolean){
success = (boolean) obj;
} else if(newF.equals("$eq")){
success = value2.equals(obj);
} else if(newF.equals("$gt") && obj instanceof Number && value2 instanceof Number){
success = checkValue("v>" + ((Number) obj).longValue(), value2);
} else if(newF.equals("$gte") && obj instanceof Number && value2 instanceof Number){
success = checkValue("v>=" + ((Number) obj).longValue(), value2);
} else if(newF.equals("$lt") && obj instanceof Number && value2 instanceof Number){
success = checkValue("v<" + ((Number) obj).longValue(), value2);
} else if(newF.equals("$lte") && obj instanceof Number && value2 instanceof Number){
success = checkValue("v<=" + ((Number) obj).longValue(), value2);
} else if(newF.equals("$ne") && obj instanceof Number && value2 instanceof Number){
success = checkValue("v!=" + ((Number) obj).longValue(), value2);
} else if(newF.equals("$in") && obj instanceof JsonArray){
JsonArray values = (JsonArray) obj;
for(Object value : values){
if(value2.equals(value)){
success = true;
break;
} else if(value2.toString().matches(value.toString())){
success = true;
break;
}
}
} else if(newF.equals("$nin") && obj instanceof JsonArray){
// None of the values can exist
success = true; // Let's say it's successful
JsonArray values = (JsonArray) obj;
for(Object value : values){
if(value2.equals(value)){
success = false;
break;
} else if(value2.toString().matches(value.toString())){
success = false;
break;
}
}
}
}
}
return success;
}
// If it doesn't match that means the query didn't line up
return false;
}
private static int compareTo(Number n1, Number n2) {
// ignoring null handling
BigDecimal b1 = new BigDecimal(n1.doubleValue());
BigDecimal b2 = new BigDecimal(n2.doubleValue());
return b1.compareTo(b2);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy