View Javadoc
1   package de.dlr.shepard.common.search.query;
2   
3   import com.fasterxml.jackson.core.JsonProcessingException;
4   import com.fasterxml.jackson.databind.JsonNode;
5   import com.fasterxml.jackson.databind.ObjectMapper;
6   import de.dlr.shepard.common.exceptions.ShepardParserException;
7   import de.dlr.shepard.common.util.Constants;
8   import java.util.Iterator;
9   import java.util.List;
10  import java.util.NoSuchElementException;
11  
12  public class MongoDBQueryBuilder {
13  
14    private static final List<String> booleanOperators = List.of(
15      Constants.JSON_AND,
16      Constants.JSON_OR,
17      Constants.JSON_NOT
18    );
19    private static final List<String> opAttributes = List.of(
20      Constants.OP_PROPERTY,
21      Constants.OP_VALUE,
22      Constants.OP_OPERATOR
23    );
24  
25    private MongoDBQueryBuilder() {}
26  
27    public static String getMongoDBQueryString(String query) {
28      ObjectMapper objectMapper = new ObjectMapper();
29      JsonNode jsonNode = null;
30      try {
31        jsonNode = objectMapper.readValue(query, JsonNode.class);
32      } catch (JsonProcessingException e) {
33        throw new ShepardParserException("error while reading JSON\n" + e.getMessage());
34      }
35      return getMongoDBQueryString(jsonNode);
36    }
37  
38    private static String getMongoDBQueryString(JsonNode rootNode) {
39      String operator = "";
40      try {
41        operator = rootNode.fieldNames().next();
42      } catch (NoSuchElementException e) {
43        throw new ShepardParserException("error in parsing" + e.getMessage());
44      }
45  
46      if (opAttributes.contains(operator)) {
47        return primitiveClause(rootNode);
48      } else if (booleanOperators.contains(operator)) {
49        return complexClause(rootNode, operator);
50      } else {
51        throw new ShepardParserException("unknown operator: " + operator);
52      }
53    }
54  
55    private static String operatorString(JsonNode node) {
56      String operator = node.textValue();
57      return switch (operator) {
58        case Constants.JSON_GT -> "$gt";
59        case Constants.JSON_LT -> "$lt";
60        case Constants.JSON_GE -> "$gte";
61        case Constants.JSON_LE -> "$lte";
62        case Constants.JSON_EQ -> "$eq";
63        case Constants.JSON_IN -> "$in";
64        case Constants.JSON_NE -> "$ne";
65        default -> throw new ShepardParserException("unknown comparison operator " + operator);
66      };
67    }
68  
69    private static String complexClause(JsonNode node, String operator) {
70      if (operator.equals(Constants.JSON_NOT)) {
71        return negatedClause(node.get(Constants.JSON_NOT));
72      } else {
73        return multaryClause(node, operator);
74      }
75    }
76  
77    private static String negatedClause(JsonNode node) {
78      String operator = node.fieldNames().next();
79      if (opAttributes.contains(operator)) {
80        return negatedPrimitiveClause(node);
81      } else if (booleanOperators.contains(operator)) {
82        return negatedComplexClause(node, operator);
83      } else {
84        throw new ShepardParserException("unknown operator: " + operator);
85      }
86    }
87  
88    private static String negatedComplexClause(JsonNode node, String operator) {
89      if (operator.equals(Constants.JSON_NOT)) return getMongoDBQueryString(node.get(Constants.JSON_NOT));
90      else return negatedMultaryClause(node, operator);
91    }
92  
93    private static String negatedPrimitiveClause(JsonNode node) {
94      String ret = "";
95      ret = ret + node.get(Constants.OP_PROPERTY).textValue() + ": {";
96      ret = ret + "$not: {";
97      ret = ret + operatorString(node.get(Constants.OP_OPERATOR)) + ": ";
98      ret = ret + node.get(Constants.OP_VALUE) + "}}";
99      return ret;
100   }
101 
102   private static String primitiveClause(JsonNode node) {
103     String ret = "";
104     String property = node.get(Constants.OP_PROPERTY).textValue();
105     ret = ret + property + ": {";
106     ret = ret + operatorString(node.get(Constants.OP_OPERATOR)) + ": ";
107     ret = ret + node.get(Constants.OP_VALUE);
108     ret = ret + "}";
109     return ret;
110   }
111 
112   private static String multaryClause(JsonNode node, String operator) {
113     String ret = "";
114     Iterator<JsonNode> argumentsArray = node.get(operator).elements();
115     ret = ret + booleanOperator(operator) + " [{";
116     String firstArgument = getMongoDBQueryString(argumentsArray.next());
117     ret = ret + firstArgument;
118     while (argumentsArray.hasNext()) {
119       ret = ret + "}, {" + getMongoDBQueryString(argumentsArray.next());
120     }
121     ret = ret + "}]";
122     return ret;
123   }
124 
125   private static String negatedMultaryClause(JsonNode node, String operator) {
126     String ret = "";
127     Iterator<JsonNode> argumentsArray = node.get(operator).elements();
128     ret = ret + negatedBooleanOperator(operator) + " [{";
129     String firstArgument = negatedClause(argumentsArray.next());
130     ret = ret + firstArgument;
131     while (argumentsArray.hasNext()) {
132       ret = ret + "}, {" + negatedClause(argumentsArray.next());
133     }
134     ret = ret + "}]";
135     return ret;
136   }
137 
138   private static String booleanOperator(String operator) {
139     return switch (operator) {
140       case Constants.JSON_AND -> "$and:";
141       case Constants.JSON_OR -> "$or:";
142       default -> throw new ShepardParserException("unknown operator: " + operator);
143     };
144   }
145 
146   private static String negatedBooleanOperator(String operator) {
147     return switch (operator) {
148       case Constants.JSON_AND -> "$or:";
149       case Constants.JSON_OR -> "$and:";
150       default -> throw new ShepardParserException("unknown operator: " + operator);
151     };
152   }
153 }