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 }