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 2:
449: if (ctx.getChild(0).getChildCount() > 0) {
450: operator = ctx.getChild(0).getChild(0).getText();
451: } else {
452: attrPointer.setNot(true);
453: }
454: break;
455: case 3:
456: attrPointer.setNot(true);
457: operator = ctx.getChild(0).getChild(0).getText();
458: break;
459: default:
460: attrPointer.setNot(false);
461: }
462: return operator;
463: }
464:
465: private String getOrderingBy(ParserRuleContext ctx) {
466: return ctx.getChildCount() > 1 ? ctx.getChild(1).getText() : "";
467: }
468:
469: private void setObjectIri(SoqlNode node) {
470: if (metamodel == null) {
471: return;
472: }
473: EntityTypeImpl<?> entityType = getEntityType(node.getValue());
474: if (entityType == null) {
475: return;
476: }
477: node.setIri(entityType.getIRI().toString());
478: if (node.hasNextChild()) {
479: setAllNodesIris(entityType, node.getChild());
480: }
481: }
482:
483: private EntityTypeImpl<?> getEntityType(String name) {
484: if (metamodel == null) {
485: return null;
486: }
487: for (EntityType<?> type : metamodel.getEntities()) {
488: EntityTypeImpl<?> entityType = (EntityTypeImpl<?>) type;
489: if (entityType.getName().equals(name)) {
490: return entityType;
491: }
492: }
493: return null;
494: }
495:
496: private EntityTypeImpl<?> getEntityType(Type<?> type) {
497: if (metamodel == null) {
498: return null;
499: }
500: for (EntityType<?> value : metamodel.getEntities()) {
501: EntityTypeImpl<?> entityType = (EntityTypeImpl<?>) value;
502: if (entityType.equals(type)) {
503: return entityType;
504: }
505: }
506: return null;
507: }
508:
509: private void setAllNodesIris(EntityTypeImpl<?> entityType, SoqlNode node) {
510: SingularAttributeImpl<?, ?> abstractAttribute = (SingularAttributeImpl<?, ?>) entityType.getAttribute(node.getValue());
511: //not implemented case of 3 or more fragments (chained SoqlNodes)
512: node.setIri(abstractAttribute.getIRI().toString());
513: if (node.hasNextChild()) {
514: Type<?> type = abstractAttribute.getType();
515: EntityTypeImpl<?> attrEntityType = getEntityType(type);
516: if (attrEntityType == null) {
517: return;
518: }
519: setAllNodesIris(attrEntityType, node.getChild());
520: }
521: }
522:
523: private void setIris(SoqlNode firstNode) {
524: if (!objectTypes.containsKey(firstNode.getValue())) {
525: return;
526: }
527: if (metamodel == null) {
528: return;
529: }
530: String objectName = objectTypes.get(firstNode.getValue());
531: EntityTypeImpl<?> entityType = getEntityType(objectName);
532: if (entityType == null) {
533: return;
534: }
535: if (firstNode.hasNextChild()) {
536: setAllNodesIris(entityType, firstNode.getChild());
537: }
538: }
539:
540: public String getSoqlQuery() {
541: return newQuery;
542: }
543:
544:
545: //Methods to build new Query
546: private void buildString() {
547: if (attributes.isEmpty()) {
548: return;
549: }
550: StringBuilder newQueryBuilder = new StringBuilder(typeDef);
551: if (isSelectedParamCount) {
552: newQueryBuilder.append(getCountPart());
553: } else {
554: if (isSelectedParamDistinct) {
555: newQueryBuilder.append(" ").append("DISTINCT");
556: }
557: newQueryBuilder.append(" ?x ");
558: }
559: newQueryBuilder.append("WHERE { ");
560: newQueryBuilder.append(processSupremeAttributes());
561: if (!objectOfNextOr.isEmpty()) {
562: newQueryBuilder.append("{ ");
563: }
564: newQueryBuilder.append(processAttributes());
565: if (!objectOfNextOr.isEmpty()) {
566: newQueryBuilder.append("} ");
567: }
568: newQueryBuilder.append("}");
569: if (!groupAttributes.isEmpty()) {
570: newQueryBuilder.append(" ").append(buildGrouping());
571: }
572: if (!orderAttributes.isEmpty()) {
573: newQueryBuilder.append(" ").append(buildOrdering());
574: }
575: newQuery = newQueryBuilder.toString();
576: }
577:
578: private StringBuilder getCountPart() {
579: StringBuilder countPart = new StringBuilder(" (COUNT(");
580: if (isSelectedParamDistinct) {
581: countPart.append("distinct ");
582: }
583: countPart.append("?x) AS ?count) ");
584: return countPart;
585: }
586:
587: private StringBuilder processSupremeAttributes() {
588: StringBuilder attributesPart = new StringBuilder();
589: SoqlAttribute pointer = attributes.get(0);
590: while (pointer.isObject() || pointer.isOrderBy() || pointer.isGroupBy()) {
591: attributesPart.append(processAttribute(pointer));
592: attributes.remove(pointer);
593: if (attributes.isEmpty()) {
594: break;
595: } else {
596: pointer = attributes.get(0);
597: }
598: }
599: return attributesPart;
600: }
601:
602: private StringBuilder processAttributes() {
603: StringBuilder attributesPart = new StringBuilder();
604: ArrayList<SoqlAttribute> toFilter = new ArrayList<>();
605: ArrayList<SoqlAttribute> toInvFilter = new ArrayList<>();
606: for (SoqlAttribute myAttr : attributes) {
607: if (objectOfNextOr.contains(myAttr)) {
608: StringBuilder orPart = new StringBuilder();
609: orPart.append(processAllFilters(toFilter, toInvFilter));
610: toFilter.clear();
611: toInvFilter.clear();
612: orPart.append("} UNION { ");
613: attributesPart.append(orPart);
614: }
615: if (myAttr.isNot()) {
616: toInvFilter.add(myAttr);
617: } else {
618: if (myAttr.isFilter()) {
619: toFilter.add(myAttr);
620: }
621: attributesPart.append(processAttribute(myAttr));
622: }
623: }
624: attributesPart.append(processAllFilters(toFilter, toInvFilter));
625: return attributesPart;
626: }
627:
628: private StringBuilder processAllFilters(ArrayList<SoqlAttribute> toFilter, ArrayList<SoqlAttribute> toInvFilter) {
629: StringBuilder part = new StringBuilder();
630: if (!toFilter.isEmpty()) {
631: part.append(processFilter(toFilter));
632: }
633: if (!toInvFilter.isEmpty()) {
634: part.append(processInvFilter(toInvFilter));
635: }
636: return part;
637: }
638:
639: private StringBuilder processFilter(ArrayList<SoqlAttribute> toFilter) {
640: StringBuilder buildFilter = new StringBuilder();
641: if (toFilter.isEmpty()) {
642: return buildFilter;
643: }
644: buildFilter.append("FILTER (");
645: for (SoqlAttribute attr : toFilter) {
646: if (toFilter.indexOf(attr) != 0) {
647: buildFilter.append(" && ");
648: }
649: buildFilter.append(attr.getFilter());
650: }
651: buildFilter.append(") ");
652: return buildFilter;
653: }
654:
655: private StringBuilder processInvFilter(ArrayList<SoqlAttribute> toInvFilter) {
656: StringBuilder buildInvFilter = new StringBuilder();
657: ArrayList<SoqlAttribute> toFilter = new ArrayList<>();
658: if (toInvFilter.isEmpty()) {
659: return buildInvFilter;
660: }
661: buildInvFilter.append("FILTER NOT EXISTS { ");
662: for (SoqlAttribute attr : toInvFilter) {
663: buildInvFilter.append(processAttribute(attr));
664: if (attr.isFilter()) {
665: toFilter.add(attr);
666: }
667: }
668: buildInvFilter.append(processFilter(toFilter)).append("} ");
669: return buildInvFilter;
670: }
671:
672: private StringBuilder processAttribute(SoqlAttribute attr) {
673: return new StringBuilder(attr.getTriplePattern());
674: }
675:
676: private StringBuilder buildOrdering() {
677: StringBuilder sb = new StringBuilder("ORDER BY");
678: for (SoqlOrderParameter orderParam : orderAttributes) {
679: sb.append(" ").append(orderParam.getOrderByPart());
680: }
681: return sb;
682: }
683:
684: private StringBuilder buildGrouping() {
685: StringBuilder sb = new StringBuilder("GROUP BY");
686: for (SoqlGroupParameter groupParam : groupAttributes) {
687: sb.append(" ").append(groupParam.getGroupByPart());
688: }
689: return sb;
690: }
691: }