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