blob: adc3d585101d964f8061db0c2746c76597fd0e7f [file] [log] [blame]
Michael Hanl2b573f72013-12-06 21:07:19 +00001package de.ids_mannheim.korap.query.serialize;
2
3import com.fasterxml.jackson.core.JsonFactory;
4import com.fasterxml.jackson.core.JsonParser;
5import com.fasterxml.jackson.core.JsonProcessingException;
6import com.fasterxml.jackson.databind.JsonNode;
7import com.fasterxml.jackson.databind.ObjectMapper;
8import com.google.common.collect.ArrayListMultimap;
9import com.google.common.collect.Multimap;
10
11import java.io.IOException;
12import java.util.*;
13
14/**
15 * @author hanl
16 * @date 06/12/2013
17 */
18public class MetaQuery {
19
20 private JsonFactory factory;
21 private MetaTypes types;
22 private ObjectMapper serialzer;
23 private List<Map> rq;
24 private List<Map> mfil;
25 private List<Map> mext;
Michael Hanl2b573f72013-12-06 21:07:19 +000026
27 public MetaQuery() {
28 this.serialzer = new ObjectMapper();
29 this.rq = new ArrayList<>();
30 this.mfil = new ArrayList<>();
31 this.mext = new ArrayList<>();
32 this.factory = serialzer.getFactory();
33 this.types = new MetaTypes();
Michael Hanl698da8c2013-12-08 21:12:36 +000034 }
35
Michael Hanlb64fdce2013-12-08 23:17:19 +000036 /**
37 * temporary solution, since there is no other place for this right now!
38 *
39 * @param request
40 * @param page
41 * @param num
42 * @param cli
43 * @param cri
44 * @param cls
45 * @param crs
46 * @return
47 */
Michael Hanl698da8c2013-12-08 21:12:36 +000048 public static Map addParameters(Map request, int page, int num, String cli, String cri,
49 int cls, int crs) {
50 Map ctx = new LinkedHashMap();
51 List left = new ArrayList();
52 left.add(cli);
53 left.add(cls);
54 List right = new ArrayList();
55 right.add(cri);
56 right.add(crs);
57 ctx.put("left", left);
58 ctx.put("right", right);
59
60 request.put("startPage", page);
61 request.put("count", num);
62 request.put("context", ctx);
63
64 return request;
Michael Hanl2b573f72013-12-06 21:07:19 +000065 }
66
Michael Hanl04bb2b92013-12-06 23:18:14 +000067 public MetaQuery addResource(String query) {
68 try {
Michael Hanl2b573f72013-12-06 21:07:19 +000069 JsonParser jp = factory.createParser(query);
70 JsonNode m = jp.readValueAsTree();
71 for (JsonNode n : m)
72 this.rq.add(serialzer.treeToValue(n, Map.class));
Michael Hanl04bb2b92013-12-06 23:18:14 +000073 } catch (IOException e) {
74 e.printStackTrace();
75 throw new IllegalArgumentException("Conversion went wrong!");
Michael Hanl2b573f72013-12-06 21:07:19 +000076 }
77 return this;
78 }
79
Michael Hanl04bb2b92013-12-06 23:18:14 +000080 public MetaQuery addResources(List<String> queries) {
81 for (String query : queries)
82 addResource(query);
83 return this;
84 }
85
Michael Hanlb64fdce2013-12-08 23:17:19 +000086 private List createValue(Multimap<String, String> map) {
Michael Hanl2b573f72013-12-06 21:07:19 +000087 List value = new ArrayList<>();
Michael Hanlb64fdce2013-12-08 23:17:19 +000088 String[] dates = new String[3];
89 for (String key : map.keySet()) {
90 if (key.equals("pubDate")) {
91 dates = processDates((List<String>) map.get(key));
Michael Hanl2b573f72013-12-06 21:07:19 +000092 continue;
93 }
94
Michael Hanlb64fdce2013-12-08 23:17:19 +000095 if (map.get(key).size() == 1) {
96 Map term = types.createTerm(key, null, map.get(key).toArray(new String[0])[0], null);
97 value.add(term);
98 } else {
99 List g = new ArrayList();
100 for (String v : map.get(key))
101 g.add(types.createTerm(null, v, null));
102 Map group = types.createGroup("and", key, g);
103 value.add(group);
104 }
105
Michael Hanl2b573f72013-12-06 21:07:19 +0000106 }
107
Michael Hanl2b573f72013-12-06 21:07:19 +0000108 int idx = 3;
Michael Hanlb64fdce2013-12-08 23:17:19 +0000109 if (dates[0] != null && dates[0].equals("r")) {
110 Map term1 = types.createTerm(null, dates[1], "korap:date");
111 Map term2 = types.createTerm(null, dates[2], "korap:date");
Michael Hanl2b573f72013-12-06 21:07:19 +0000112 Map group = types.createGroup("between", "pubDate", Arrays.asList(term1, term2));
113 value.add(group);
Michael Hanlb64fdce2013-12-08 23:17:19 +0000114 } else if (dates[1] != null) {
115 Map term1 = types.createTerm(null, dates[1], "korap:date");
Michael Hanl2b573f72013-12-06 21:07:19 +0000116 Map group = types.createGroup("since", "pubDate", Arrays.asList(term1));
117 value.add(group);
Michael Hanlb64fdce2013-12-08 23:17:19 +0000118 } else if (dates[2] != null) {
119 Map term1 = types.createTerm(null, dates[2], "korap:date");
Michael Hanl2b573f72013-12-06 21:07:19 +0000120 Map group = types.createGroup("until", "pubDate", Arrays.asList(term1));
121 value.add(group);
122 }
123
124
Michael Hanlb64fdce2013-12-08 23:17:19 +0000125 for (int i = idx; i < dates.length; i++) {
126 if (dates[i] != null) {
127 Map term1 = types.createTerm(dates[i], "korap:date");
128 Map group = types.createGroup("exact", "pubDate", Arrays.asList(term1));
Michael Hanl2b573f72013-12-06 21:07:19 +0000129 value.add(group);
130 }
131 }
Michael Hanlb64fdce2013-12-08 23:17:19 +0000132 return value;
133 }
Michael Hanl2b573f72013-12-06 21:07:19 +0000134
Michael Hanlb64fdce2013-12-08 23:17:19 +0000135 // map can only have one key, value pair. thus, text class can only be added once. Multiple types are not possible!
136 public MetaQuery addMetaFilter(String queries) {
137 Multimap<String, String> m = resEq(queries);
138 boolean multypes = m.keys().size() > 1;
139 String def_key = null;
140
141 if (!multypes)
142 def_key = m.keys().toArray(new String[0])[0];
143
144 List value = this.createValue(m);
Michael Hanl2b573f72013-12-06 21:07:19 +0000145 // todo: missing: - takes only one resource, but resources can be chained!
Michael Hanlb64fdce2013-12-08 23:17:19 +0000146 if (m.values().size() == 1)
Michael Hanl2b573f72013-12-06 21:07:19 +0000147 Collections.addAll(this.mfil, types.createMetaFilter((Map) value.get(0)));
148 else {
149 Map group;
150 if (!multypes)
151 group = types.createGroup("and", def_key, value);
152 else
153 group = types.createGroup("and", null, value);
154 Collections.addAll(this.mfil, types.createMetaFilter(group));
155 }
156 return this;
157 }
158
Michael Hanlb64fdce2013-12-08 23:17:19 +0000159 public MetaQuery addMetaExtend(String queries) {
160 Multimap<String, String> m = resEq(queries);
161 boolean multypes = m.keys().size() > 1;
Michael Hanl2b573f72013-12-06 21:07:19 +0000162 String def_key = null;
Michael Hanl2b573f72013-12-06 21:07:19 +0000163
Michael Hanlb64fdce2013-12-08 23:17:19 +0000164 if (!multypes)
165 def_key = m.keys().toArray(new String[0])[0];
Michael Hanl2b573f72013-12-06 21:07:19 +0000166
Michael Hanlb64fdce2013-12-08 23:17:19 +0000167 List value = this.createValue(m);
Michael Hanl2b573f72013-12-06 21:07:19 +0000168 // todo: missing: - takes only one resource, but resources can be chained!
Michael Hanlb64fdce2013-12-08 23:17:19 +0000169 if (m.values().size() == 1)
Michael Hanl2b573f72013-12-06 21:07:19 +0000170 Collections.addAll(this.mext, types.createMetaExtend((Map) value.get(0)));
171 else {
172 Map group;
173 if (!multypes)
174 group = types.createGroup("and", def_key, value);
175 else
176 group = types.createGroup("and", null, value);
177 Collections.addAll(this.mext, types.createMetaExtend(group));
178 }
Michael Hanl2b573f72013-12-06 21:07:19 +0000179 return this;
180 }
181
182 public MetaQuery addMetaFilter(String attr, String val) {
Michael Hanlb64fdce2013-12-08 23:17:19 +0000183 return addMetaFilter(attr + ":" + val);
Michael Hanl2b573f72013-12-06 21:07:19 +0000184 }
185
186 public MetaQuery addMetaExtend(String attr, String val) {
Michael Hanlb64fdce2013-12-08 23:17:19 +0000187 return addMetaExtend(attr + ":" + val);
Michael Hanl2b573f72013-12-06 21:07:19 +0000188 }
189
190 private String[] processDates(List<String> dates) {
191 if (dates.isEmpty())
192 return new String[3];
193 boolean range = false;
194 String[] el = new String[dates.size() + 3];
195 int idx = 3;
196 for (String value : dates) {
197 if (value.contains("<")) {
198 String[] sp = value.split("<");
199 el[1] = types.formatDate(Long.valueOf(sp[1]), MetaTypes.YMD);
200 } else if (value.contains(">")) {
201 String[] sp = value.split(">");
202 el[2] = types.formatDate(Long.valueOf(sp[1]), MetaTypes.YMD);
Michael Hanl2b573f72013-12-06 21:07:19 +0000203 } else {
204 el[idx] = types.formatDate(Long.valueOf(value), MetaTypes.YMD);
205 idx++;
206 }
207 }
Michael Hanlb64fdce2013-12-08 23:17:19 +0000208 if (el[1] != null && el[2] != null)
Michael Hanl2b573f72013-12-06 21:07:19 +0000209 el[0] = "r";
210 return el;
211 }
212
213 public void clear() {
214 this.rq.clear();
215 this.mfil.clear();
Michael Hanl27e50582013-12-07 18:04:13 +0000216 this.mext.clear();
Michael Hanl2b573f72013-12-06 21:07:19 +0000217 }
218
Michael Hanl04bb2b92013-12-06 23:18:14 +0000219 private List<Map> join() {
Michael Hanl2b573f72013-12-06 21:07:19 +0000220 List<Map> cursor = new ArrayList<>(this.rq);
221 cursor.addAll(this.mfil);
222 cursor.addAll(this.mext);
223 return cursor;
224 }
225
Michael Hanl04bb2b92013-12-06 23:18:14 +0000226 private List<Map> getMetaOnly() {
227 List<Map> cursor = new ArrayList<>(this.mfil);
228 cursor.addAll(this.mext);
229 return cursor;
230 }
231
232 /**
233 * returns the meta query only and does not contain parent dependencies
Michael Hanl698da8c2013-12-08 21:12:36 +0000234 *
Michael Hanl04bb2b92013-12-06 23:18:14 +0000235 * @return
236 */
Michael Hanl2b573f72013-12-06 21:07:19 +0000237 public String stringify() {
Michael Hanlb64fdce2013-12-08 23:17:19 +0000238 List meta = getMetaOnly();
239 if (meta.isEmpty())
240 return "";
241
Michael Hanl2b573f72013-12-06 21:07:19 +0000242 try {
Michael Hanlb64fdce2013-12-08 23:17:19 +0000243 return serialzer.writeValueAsString(meta);
Michael Hanl2b573f72013-12-06 21:07:19 +0000244 } catch (JsonProcessingException e) {
245 e.printStackTrace();
246 return "";
247 }
248 }
249
250 public JsonNode jsonify() {
Michael Hanl04bb2b92013-12-06 23:18:14 +0000251 return serialzer.valueToTree(join());
Michael Hanl2b573f72013-12-06 21:07:19 +0000252 }
253
Michael Hanl04bb2b92013-12-06 23:18:14 +0000254 /**
255 * returns the List<Map> that contains all the meta queries and resource queries
256 * added to the meta query container
Michael Hanl698da8c2013-12-08 21:12:36 +0000257 *
Michael Hanl04bb2b92013-12-06 23:18:14 +0000258 * @return
259 */
260 public List<Map> raw() {
261 return join();
262 }
263
264 /**
265 * returns a JSON String representation that contains all information
266 * (meta query and resource meta queries alike) in a root meta JSON node
267 *
268 * @return
269 */
Michael Hanl2b573f72013-12-06 21:07:19 +0000270 public String toMeta() {
271 Map meta = new LinkedHashMap();
Michael Hanl04bb2b92013-12-06 23:18:14 +0000272 meta.put("meta", join());
Michael Hanl2b573f72013-12-06 21:07:19 +0000273
274 try {
275 return serialzer.writeValueAsString(meta);
276 } catch (JsonProcessingException e) {
277 e.printStackTrace();
278 return "";
279 }
280 }
281
Michael Hanlb64fdce2013-12-08 23:17:19 +0000282 /**
283 * resolves all queries as equal (hierarchy) AND relations
284 * @param queries
285 * @return
286 */
287 private Multimap<String, String> resEq(String queries) {
288 Multimap<String, String> qmap = ArrayListMultimap.create();
Michael Hanl698da8c2013-12-08 21:12:36 +0000289 String[] spl = queries.split(" AND ");
290 for (String query : spl) {
291 String[] q = query.split(":");
292 String attr = q[0];
293 String val = q[1];
294 qmap.put(attr, val);
295 }
296 return qmap;
297
298 }
299
Michael Hanl2b573f72013-12-06 21:07:19 +0000300
301}