Skip to contentMethod: enterCount(SoqlParser.CountContext)
1: package cz.cvut.kbss.jopa.query.soql;
2:
3: import cz.cvut.kbss.jopa.model.MetamodelImpl;
4: import cz.cvut.kbss.jopa.model.metamodel.EntityType;
5: import cz.cvut.kbss.jopa.model.metamodel.EntityTypeImpl;
6: import cz.cvut.kbss.jopa.model.metamodel.SingularAttributeImpl;
7: import cz.cvut.kbss.jopa.model.metamodel.Type;
8: import org.antlr.v4.runtime.ParserRuleContext;
9: import org.antlr.v4.runtime.tree.ErrorNode;
10: import org.antlr.v4.runtime.tree.ParseTree;
11: import org.antlr.v4.runtime.tree.TerminalNode;
12:
13: import java.util.ArrayList;
14: import java.util.HashMap;
15:
16: public class SoqlQueryListener implements SoqlListener {
17:
18: private final MetamodelImpl metamodel;
19:
20: private String newQuery = "";
21:
22: private String typeDef = "SELECT";
23:
24: // keeps pointer at created object of SoqlAttribute while processing other neccessary rules
25: private SoqlAttribute attrPointer;
26:
27: private final ArrayList<SoqlAttribute> attributes;
28:
29: // keeps index of first object of SoqlAttribute after OR operator
30: private final ArrayList<SoqlAttribute> objectOfNextOr;
31:
32: private final ArrayList<SoqlOrderParameter> orderAttributes;
33:
34: private final ArrayList<SoqlGroupParameter> groupAttributes;
35:
36: private final HashMap<String, String> objectTypes;
37:
38: private boolean isSelectedParamDistinct = false;
39:
40: private boolean isSelectedParamCount = false;
41:
42:
43: public SoqlQueryListener(MetamodelImpl metamodel) {
44: super();
45: this.metamodel = metamodel;
46: this.attributes = new ArrayList<>();
47: this.objectOfNextOr = new ArrayList<>();
48: this.orderAttributes = new ArrayList<>();
49: this.groupAttributes = new ArrayList<>();
50: this.objectTypes = new HashMap<>();
51: }
52:
53: @Override
54: public void enterQuerySentence(SoqlParser.QuerySentenceContext ctx) {
55: }
56:
57: @Override
58: public void exitQuerySentence(SoqlParser.QuerySentenceContext ctx) {
59: buildString();
60: }
61:
62: @Override
63: public void enterSelectStatement(SoqlParser.SelectStatementContext ctx) {
64: }
65:
66: @Override
67: public void exitSelectStatement(SoqlParser.SelectStatementContext ctx) {
68: }
69:
70: @Override
71: public void enterParams(SoqlParser.ParamsContext ctx) {
72: }
73:
74: @Override
75: public void exitParams(SoqlParser.ParamsContext ctx) {
76: }
77:
78: @Override
79: public void enterParam(SoqlParser.ParamContext ctx) {
80: }
81:
82: @Override
83: public void exitParam(SoqlParser.ParamContext ctx) {
84: }
85:
86: @Override
87: public void enterJoinedParams(SoqlParser.JoinedParamsContext ctx) {
88: SoqlAttribute myAttr = new SoqlAttribute();
89: SoqlNode firstNode = new SoqlNode(getOwnerfromParam(ctx));
90: SoqlNode actualNode = firstNode;
91: for (int i = 2; i < ctx.getChildCount(); i += 2) {
92: SoqlNode prevNode = actualNode;
93: actualNode = new SoqlNode(prevNode, ctx.getChild(i).getText());
94: prevNode.setChild(actualNode);
95: }
96: setIris(firstNode);
97: myAttr.setFirstNode(firstNode);
98: attributes.add(myAttr);
99: attrPointer = myAttr;
100: }
101:
102: @Override
103: public void exitJoinedParams(SoqlParser.JoinedParamsContext ctx) {
104: }
105:
106: @Override
107: public void enterParamComma(SoqlParser.ParamCommaContext ctx) {
108: }
109:
110: @Override
111: public void exitParamComma(SoqlParser.ParamCommaContext ctx) {
112: }
113:
114: @Override
115: public void enterDistinctParam(SoqlParser.DistinctParamContext ctx) {
116: }
117:
118: @Override
119: public void exitDistinctParam(SoqlParser.DistinctParamContext ctx) {
120: }
121:
122: @Override
123: public void enterSelectedParam(SoqlParser.SelectedParamContext ctx) {
124: }
125:
126: @Override
127: public void exitSelectedParam(SoqlParser.SelectedParamContext ctx) {
128: }
129:
130: @Override
131: public void enterCount(SoqlParser.CountContext ctx) {
132: isSelectedParamCount = true;
133: }
134:
135: @Override
136: public void exitCount(SoqlParser.CountContext ctx) {
137: }
138:
139: @Override
140: public void enterObject(SoqlParser.ObjectContext ctx) {
141: }
142:
143: @Override
144: public void exitObject(SoqlParser.ObjectContext ctx) {
145: }
146:
147: @Override
148: public void enterObjWithAttr(SoqlParser.ObjWithAttrContext ctx) {
149: String owner = getOwnerfromParam(ctx);
150: String attribute = getAttributefromParam(ctx);
151: SoqlNode firstNode = new SoqlNode(owner);
152: SoqlNode lastNode = new SoqlNode(firstNode, attribute);
153: SoqlAttribute myAttr = new SoqlAttribute();
154: firstNode.setChild(lastNode);
155: setIris(firstNode);
156: myAttr.setFirstNode(firstNode);
157: attributes.add(myAttr);
158: attrPointer = myAttr;
159: }
160:
161: @Override
162: public void exitObjWithAttr(SoqlParser.ObjWithAttrContext ctx) {
163: }
164:
165: @Override
166: public void enterObjWithOutAttr(SoqlParser.ObjWithOutAttrContext ctx) {
167: }
168:
169: @Override
170: public void exitObjWithOutAttr(SoqlParser.ObjWithOutAttrContext ctx) {
171: }
172:
173: @Override
174: public void enterAttribute(SoqlParser.AttributeContext ctx) {
175: }
176:
177: @Override
178: public void exitAttribute(SoqlParser.AttributeContext ctx) {
179: }
180:
181: @Override
182: public void enterTypeDef(SoqlParser.TypeDefContext ctx) {
183: typeDef = ctx.getChild(0).getText();
184: }
185:
186: @Override
187: public void exitTypeDef(SoqlParser.TypeDefContext ctx) {
188: }
189:
190: @Override
191: public void enterDistinct(SoqlParser.DistinctContext ctx) {
192: if ("DISTINCT".equals(ctx.getChild(0).getText())) {
193: isSelectedParamDistinct = true;
194: }
195: }
196:
197: @Override
198: public void exitDistinct(SoqlParser.DistinctContext ctx) {
199: }
200:
201: @Override
202: public void enterLogOp(SoqlParser.LogOpContext ctx) {
203: }
204:
205: @Override
206: public void exitLogOp(SoqlParser.LogOpContext ctx) {
207: }
208:
209: @Override
210: public void enterWhereClauseWrapper(SoqlParser.WhereClauseWrapperContext ctx) {
211: }
212:
213: @Override
214: public void exitWhereClauseWrapper(SoqlParser.WhereClauseWrapperContext ctx) {
215: }
216:
217: @Override
218: public void enterTables(SoqlParser.TablesContext ctx) {
219: }
220:
221: @Override
222: public void exitTables(SoqlParser.TablesContext ctx) {
223: }
224:
225: @Override
226: public void enterTable(SoqlParser.TableContext ctx) {
227: }
228:
229: @Override
230: public void exitTable(SoqlParser.TableContext ctx) {
231: }
232:
233: @Override
234: public void enterTableName(SoqlParser.TableNameContext ctx) {
235: }
236:
237: @Override
238: public void exitTableName(SoqlParser.TableNameContext ctx) {
239: }
240:
241: @Override
242: public void enterTableWithName(SoqlParser.TableWithNameContext ctx) {
243: String table = ctx.getChild(0).getChild(0).getText();
244: String objectName = ctx.getChild(1).getChild(0).getText();
245: objectTypes.put(objectName, table);
246: SoqlAttribute myAttr = new SoqlAttribute();
247: SoqlNode node = new SoqlNode(table);
248: setObjectIri(node);
249: myAttr.setFirstNode(node);
250: myAttr.setOperator("");
251: myAttr.setValue("");
252: attributes.add(myAttr);
253: attrPointer = myAttr;
254: }
255:
256: @Override
257: public void exitTableWithName(SoqlParser.TableWithNameContext ctx) {
258: }
259:
260: @Override
261: public void enterWhereClauses(SoqlParser.WhereClausesContext ctx) {
262: }
263:
264: @Override
265: public void exitWhereClauses(SoqlParser.WhereClausesContext ctx) {
266: }
267:
268: @Override
269: public void enterWhereClauseOps(SoqlParser.WhereClauseOpsContext ctx) {
270: }
271:
272: @Override
273: public void exitWhereClauseOps(SoqlParser.WhereClauseOpsContext ctx) {
274: }
275:
276: @Override
277: public void enterWhereClause(SoqlParser.WhereClauseContext ctx) {
278: }
279:
280: @Override
281: public void exitWhereClause(SoqlParser.WhereClauseContext ctx) {
282: String logicalOperator = getOperators(ctx.getParent());
283: String operator = ctx.getChild(1).getText();
284:
285: ParseTree whereClauseValue = ctx.getChild(2);
286:
287: attrPointer.setOperator(operator);
288: attrPointer.setValue(whereClauseValue.getText());
289:
290: if ("OR".equals(logicalOperator)) {
291: objectOfNextOr.add(attrPointer);
292: }
293: }
294:
295: @Override
296: public void enterWhereClauseValue(SoqlParser.WhereClauseValueContext ctx) {
297: }
298:
299: @Override
300: public void exitWhereClauseValue(SoqlParser.WhereClauseValueContext ctx) {
301: }
302:
303: @Override
304: public void enterWhereClauseParam(SoqlParser.WhereClauseParamContext ctx) {
305: }
306:
307: @Override
308: public void exitWhereClauseParam(SoqlParser.WhereClauseParamContext ctx) {
309: }
310:
311: @Override
312: public void enterOrderByClause(SoqlParser.OrderByClauseContext ctx) {
313: }
314:
315: @Override
316: public void exitOrderByClause(SoqlParser.OrderByClauseContext ctx) {
317: }
318:
319: @Override
320: public void enterOrderByFullFormComma(SoqlParser.OrderByFullFormCommaContext ctx) {
321: }
322:
323: @Override
324: public void exitOrderByFullFormComma(SoqlParser.OrderByFullFormCommaContext ctx) {
325: }
326:
327: @Override
328: public void enterOrderByFullForm(SoqlParser.OrderByFullFormContext ctx) {
329: }
330:
331: @Override
332: public void exitOrderByFullForm(SoqlParser.OrderByFullFormContext ctx) {
333: }
334:
335: @Override
336: public void enterOrderByParam(SoqlParser.OrderByParamContext ctx) {
337: SoqlNode firstNode = new SoqlNode(getOwnerfromParam(ctx));
338: SoqlNode actualNode = firstNode;
339: for (int i = 2; i < ctx.getChildCount(); i += 2) {
340: SoqlNode prevNode = actualNode;
341: actualNode = new SoqlNode(prevNode, ctx.getChild(i).getText());
342: prevNode.setChild(actualNode);
343: }
344: setIris(firstNode);
345: String orderingBy = getOrderingBy(ctx.getParent());
346: SoqlOrderParameter orderParam = new SoqlOrderParameter(firstNode, orderingBy);
347: boolean attrSet = false;
348: for (SoqlAttribute attr : attributes) {
349: if (attr.getAsParam().equals(orderParam.getAsParam())) {
350: orderParam.setAttribute(attr);
351: attrSet = true;
352: }
353: }
354: if (!attrSet) {
355: SoqlAttribute myAttr = new SoqlAttribute();
356: myAttr.setFirstNode(firstNode);
357: myAttr.setOperator("");
358: myAttr.setValue(orderParam.getAsValue());
359: myAttr.setOrderBy(true);
360: attributes.add(1, myAttr);
361: orderParam.setAttribute(myAttr);
362: }
363: orderAttributes.add(orderParam);
364: }
365:
366: @Override
367: public void exitOrderByParam(SoqlParser.OrderByParamContext ctx) {
368: }
369:
370: @Override
371: public void enterGroupByClause(SoqlParser.GroupByClauseContext ctx) {
372: }
373:
374: @Override
375: public void exitGroupByClause(SoqlParser.GroupByClauseContext ctx) {
376: }
377:
378: @Override
379: public void enterGroupByParamComma(SoqlParser.GroupByParamCommaContext ctx) {
380: }
381:
382: @Override
383: public void exitGroupByParamComma(SoqlParser.GroupByParamCommaContext ctx) {
384: }
385:
386: @Override
387: public void enterGroupByParam(SoqlParser.GroupByParamContext ctx) {
388: SoqlNode firstNode = new SoqlNode(getOwnerfromParam(ctx));
389: SoqlNode actualNode = firstNode;
390: for (int i = 2; i < ctx.getChildCount(); i += 2) {
391: SoqlNode prevNode = actualNode;
392: actualNode = new SoqlNode(prevNode, ctx.getChild(i).getText());
393: prevNode.setChild(actualNode);
394: }
395: setIris(firstNode);
396: SoqlGroupParameter groupParam = new SoqlGroupParameter(firstNode);
397: boolean attrSet = false;
398: for (SoqlAttribute attr : attributes) {
399: if (attr.getAsParam().equals(groupParam.getAsParam())) {
400: groupParam.setAttribute(attr);
401: attrSet = true;
402: }
403: }
404: if (!attrSet) {
405: SoqlAttribute myAttr = new SoqlAttribute();
406: myAttr.setFirstNode(firstNode);
407: myAttr.setOperator("");
408: myAttr.setValue(groupParam.getAsValue());
409: myAttr.setGroupBy(true);
410: attributes.add(1, myAttr);
411: groupParam.setAttribute(myAttr);
412: }
413: groupAttributes.add(groupParam);
414: }
415:
416: @Override
417: public void exitGroupByParam(SoqlParser.GroupByParamContext ctx) {
418: }
419:
420: @Override
421: public void visitTerminal(TerminalNode terminalNode) {
422: }
423:
424: @Override
425: public void visitErrorNode(ErrorNode errorNode) {
426: }
427:
428: @Override
429: public void enterEveryRule(ParserRuleContext parserRuleContext) {
430: }
431:
432: @Override
433: public void exitEveryRule(ParserRuleContext parserRuleContext) {
434: }
435:
436: //Methods to help parse tree
437: private String getOwnerfromParam(ParserRuleContext ctx) {
438: return ctx.getChild(0).getChild(0).getText();
439: }
440:
441: private String getAttributefromParam(ParserRuleContext ctx) {
442: return ctx.getChild(2).getChild(0).getText();
443: }
444:
445: private String getOperators(ParserRuleContext ctx) {
446: String operator = "";
447: switch (ctx.getChildCount()) {
448: case 1:
449: attrPointer.setNot(false);
450: break;
451: case 2:
452: if (ctx.getChild(0).getChildCount() > 0) {
453: operator = ctx.getChild(0).getChild(0).getText();
454: } else {
455: attrPointer.setNot(true);
456: }
457: break;
458: case 3:
459: attrPointer.setNot(true);
460: operator = ctx.getChild(0).getChild(0).getText();
461: break;
462: default:
463: attrPointer.setNot(false);
464: }
465: return operator;
466: }
467:
468: private String getOrderingBy(ParserRuleContext ctx) {
469: return ctx.getChildCount() > 1 ? ctx.getChild(1).getText() : "";
470: }
471:
472: private void setObjectIri(SoqlNode node) {
473: if (metamodel == null) {
474: return;
475: }
476: EntityTypeImpl<?> entityType = getEntityType(node.getValue());
477: if (entityType == null) {
478: return;
479: }
480: node.setIri(entityType.getIRI().toString());
481: if (node.hasNextChild()) {
482: setAllNodesIris(entityType, node.getChild());
483: }
484: }
485:
486: private EntityTypeImpl<?> getEntityType(String name) {
487: if (metamodel == null) {
488: return null;
489: }
490: for (EntityType<?> type : metamodel.getEntities()) {
491: EntityTypeImpl<?> entityType = (EntityTypeImpl<?>) type;
492: if (entityType.getName().equals(name)) {
493: return entityType;
494: }
495: }
496: return null;
497: }
498:
499: private EntityTypeImpl<?> getEntityType(Type<?> type) {
500: if (metamodel == null) {
501: return null;
502: }
503: for (EntityType<?> value : metamodel.getEntities()) {
504: EntityTypeImpl<?> entityType = (EntityTypeImpl<?>) value;
505: if (entityType.equals(type)) {
506: return entityType;
507: }
508: }
509: return null;
510: }
511:
512: private void setAllNodesIris(EntityTypeImpl<?> entityType, SoqlNode node) {
513: SingularAttributeImpl abstractAttribute = (SingularAttributeImpl) entityType.getAttribute(node.getValue());
514: //not implemented case of 3 or more fragments (chained SoqlNodes)
515: node.setIri(abstractAttribute.getIRI().toString());
516: if (node.hasNextChild()) {
517: Type<?> type = abstractAttribute.getType();
518: EntityTypeImpl<?> attrEntityType = getEntityType(type);
519: if (attrEntityType == null) {
520: return;
521: }
522: setAllNodesIris(attrEntityType, node.getChild());
523: }
524: }
525:
526: private void setIris(SoqlNode firstNode) {
527: if (!objectTypes.containsKey(firstNode.getValue())) {
528: return;
529: }
530: if (metamodel == null) {
531: return;
532: }
533: String objectName = objectTypes.get(firstNode.getValue());
534: EntityTypeImpl<?> entityType = getEntityType(objectName);
535: if (entityType == null) {
536: return;
537: }
538: if (firstNode.hasNextChild()) {
539: setAllNodesIris(entityType, firstNode.getChild());
540: }
541: }
542:
543: public String getSoqlQuery() {
544: return newQuery;
545: }
546:
547:
548: //Methods to build new Query
549: private void buildString() {
550: if (attributes.isEmpty()) {
551: return;
552: }
553: StringBuilder newQueryBuilder = new StringBuilder(typeDef);
554: if (isSelectedParamCount) {
555: newQueryBuilder.append(getCountPart());
556: } else {
557: if (isSelectedParamDistinct) {
558: newQueryBuilder.append(" ").append("DISTINCT");
559: }
560: newQueryBuilder.append(" ?x ");
561: }
562: newQueryBuilder.append("WHERE { ");
563: newQueryBuilder.append(processSupremeAttributes());
564: if (!objectOfNextOr.isEmpty()) {
565: newQueryBuilder.append("{ ");
566: }
567: newQueryBuilder.append(processAttributes());
568: if (!objectOfNextOr.isEmpty()) {
569: newQueryBuilder.append("} ");
570: }
571: newQueryBuilder.append("}");
572: if (!groupAttributes.isEmpty()) {
573: newQueryBuilder.append(" ").append(buildGrouping());
574: }
575: if (!orderAttributes.isEmpty()) {
576: newQueryBuilder.append(" ").append(buildOrdering());
577: }
578: newQuery = newQueryBuilder.toString();
579: }
580:
581: private StringBuilder getCountPart() {
582: StringBuilder countPart = new StringBuilder(" (COUNT(");
583: if (isSelectedParamDistinct) {
584: countPart.append("distinct ");
585: }
586: countPart.append("?x) AS ?count) ");
587: return countPart;
588: }
589:
590: private StringBuilder processSupremeAttributes() {
591: StringBuilder attributesPart = new StringBuilder();
592: SoqlAttribute pointer = attributes.get(0);
593: while (pointer.isObject() || pointer.isOrderBy() || pointer.isGroupBy()) {
594: attributesPart.append(processAttribute(pointer));
595: attributes.remove(pointer);
596: if (attributes.isEmpty()) {
597: break;
598: } else {
599: pointer = attributes.get(0);
600: }
601: }
602: return attributesPart;
603: }
604:
605: private StringBuilder processAttributes() {
606: StringBuilder attributesPart = new StringBuilder();
607: ArrayList<SoqlAttribute> toFilter = new ArrayList<>();
608: ArrayList<SoqlAttribute> toInvFilter = new ArrayList<>();
609: for (SoqlAttribute myAttr : attributes) {
610: if (objectOfNextOr.contains(myAttr)) {
611: StringBuilder orPart = new StringBuilder();
612: orPart.append(processAllFilters(toFilter, toInvFilter));
613: toFilter.clear();
614: toInvFilter.clear();
615: orPart.append("} UNION { ");
616: attributesPart.append(orPart);
617: }
618: if (myAttr.isNot()) {
619: toInvFilter.add(myAttr);
620: } else {
621: if (myAttr.isFilter()) {
622: toFilter.add(myAttr);
623: }
624: attributesPart.append(processAttribute(myAttr));
625: }
626: }
627: attributesPart.append(processAllFilters(toFilter, toInvFilter));
628: return attributesPart;
629: }
630:
631: private StringBuilder processAllFilters(ArrayList<SoqlAttribute> toFilter, ArrayList<SoqlAttribute> toInvFilter) {
632: StringBuilder part = new StringBuilder();
633: if (!toFilter.isEmpty()) {
634: part.append(processFilter(toFilter));
635: }
636: if (!toInvFilter.isEmpty()) {
637: part.append(processInvFilter(toInvFilter));
638: }
639: return part;
640: }
641:
642: private StringBuilder processFilter(ArrayList<SoqlAttribute> toFilter) {
643: StringBuilder buildFilter = new StringBuilder();
644: if (toFilter.isEmpty()) {
645: return buildFilter;
646: }
647: buildFilter.append("FILTER (");
648: for (SoqlAttribute attr : toFilter) {
649: if (toFilter.indexOf(attr) != 0) {
650: buildFilter.append(" && ");
651: }
652: buildFilter.append(attr.getFilter());
653: }
654: buildFilter.append(") ");
655: return buildFilter;
656: }
657:
658: private StringBuilder processInvFilter(ArrayList<SoqlAttribute> toInvFilter) {
659: StringBuilder buildInvFilter = new StringBuilder();
660: ArrayList<SoqlAttribute> toFilter = new ArrayList<>();
661: if (toInvFilter.isEmpty()) {
662: return buildInvFilter;
663: }
664: buildInvFilter.append("FILTER NOT EXISTS { ");
665: for (SoqlAttribute attr : toInvFilter) {
666: buildInvFilter.append(processAttribute(attr));
667: if (attr.isFilter()) {
668: toFilter.add(attr);
669: }
670: }
671: buildInvFilter.append(processFilter(toFilter)).append("} ");
672: return buildInvFilter;
673: }
674:
675: private StringBuilder processAttribute(SoqlAttribute attr) {
676: return new StringBuilder(attr.getTriplePattern());
677: }
678:
679: private StringBuilder buildOrdering() {
680: StringBuilder sb = new StringBuilder("ORDER BY");
681: for (SoqlOrderParameter orderParam : orderAttributes) {
682: sb.append(" ").append(orderParam.getOrderByPart());
683: }
684: return sb;
685: }
686:
687: private StringBuilder buildGrouping() {
688: StringBuilder sb = new StringBuilder("GROUP BY");
689: for (SoqlGroupParameter groupParam : groupAttributes) {
690: sb.append(" ").append(groupParam.getGroupByPart());
691: }
692: return sb;
693: }
694: }