diff --git a/src/main/java/com/netgrif/application/engine/pfql/domain/antlr4/QueryLang.g4 b/src/main/java/com/netgrif/application/engine/pfql/domain/antlr4/QueryLang.g4 index 2c7918dfb5..55867f5289 100644 --- a/src/main/java/com/netgrif/application/engine/pfql/domain/antlr4/QueryLang.g4 +++ b/src/main/java/com/netgrif/application/engine/pfql/domain/antlr4/QueryLang.g4 @@ -98,6 +98,7 @@ userAttribute: ID ; // resource comparisons +// todo: authorComparison for process? processComparisons: idComparison | identifierComparison | versionComparison @@ -228,12 +229,12 @@ tasksUserIdComparison: tasksUserId SPACE stringComparison # tasksUserIdBasic ; // basic comparisons -objectIdComparison: (NOT SPACE?)? op=(EQ | NEQ) SPACE STRING ; -stringComparison: (NOT SPACE?)? op=(EQ | NEQ | CONTAINS | LT | GT | LTE | GTE) SPACE STRING ; +objectIdComparison: (NOT SPACE?)? op=(EQ | NEQ) SPACE (STRING | LOGGED_USER_ID) ; +stringComparison: (NOT SPACE?)? op=(EQ | NEQ | CONTAINS | LT | GT | LTE | GTE) SPACE (STRING | loggedUserStringAttribute) ; numberComparison: (NOT SPACE?)? op=(EQ | NEQ | LT | GT | LTE | GTE) SPACE number=(INT | DOUBLE) ; dateComparison: (NOT SPACE?)? op=(EQ | NEQ | LT | GT | LTE | GTE) SPACE DATE ; dateTimeComparison: (NOT SPACE?)? op=(EQ | NEQ | LT | GT | LTE | GTE) SPACE DATETIME ; -booleanComparison: (NOT SPACE?)? op=(EQ | NEQ) SPACE BOOLEAN ; +booleanComparison: (NOT SPACE?)? op=(EQ | NEQ) SPACE (BOOLEAN | LOGGED_USER_ANONYMOUS) ; // in list/in range comparisons inListStringComparison: (NOT SPACE?)? op=IN SPACE? stringList ; @@ -326,13 +327,13 @@ ASC: A S C ; DESC: D E S C ; // basic types -stringList: '(' SPACE? (STRING SPACE? (',' SPACE? STRING SPACE? )* )? SPACE? ')' ; +stringList: '(' SPACE? ((STRING | loggedUserStringAttribute) SPACE? (',' SPACE? (STRING | loggedUserStringAttribute) SPACE? )* )? SPACE? ')' ; intList: '(' SPACE? (INT SPACE? (',' SPACE? INT SPACE? )* )? SPACE? ')' ; doubleList: '(' SPACE? (DOUBLE SPACE? (',' SPACE? DOUBLE SPACE? )* )? SPACE? ')' ; dateList: '(' SPACE? (DATE SPACE? (',' SPACE? DATE SPACE? )* )? SPACE? ')' ; dateTimeList: '(' SPACE? (DATETIME SPACE? (',' SPACE? DATETIME SPACE? )* )? SPACE? ')' ; versionList: '(' SPACE? (VERSION_NUMBER SPACE? (',' SPACE? VERSION_NUMBER SPACE? )* )? SPACE? ')' ; -stringRange: leftEndpoint=('(' | '[') SPACE? STRING SPACE? ':' SPACE? STRING SPACE? rightEndpoint=(')' | ']') ; +stringRange: leftEndpoint=('(' | '[') SPACE? (STRING | loggedUserStringAttribute) SPACE? ':' SPACE? (STRING | loggedUserStringAttribute) SPACE? rightEndpoint=(')' | ']') ; intRange: leftEndpoint=('(' | '[') SPACE? INT SPACE? ':' SPACE? INT SPACE? rightEndpoint=(')' | ']') ; doubleRange: leftEndpoint=('(' | '[') SPACE? DOUBLE SPACE? ':' SPACE? DOUBLE SPACE? rightEndpoint=(')' | ']') ; dateRange: leftEndpoint=('(' | '[') SPACE? DATE SPACE? ':' SPACE? DATE SPACE? rightEndpoint=(')' | ']') ; @@ -350,6 +351,13 @@ JAVA_ID: [a-zA-Z$_] [a-zA-Z0-9$_]* ; SPACE: [ ]+ ; ANY: . ; +// place holders +loggedUserStringAttribute: (LOGGED_USER_ID | LOGGED_USER_USERNAME | LOGGED_USER_FULLNAME); +LOGGED_USER_ID: L O G G E D U S E R '.' I D ; +LOGGED_USER_FULLNAME: L O G G E D U S E R '.' F U L L N A M E ; +LOGGED_USER_USERNAME: L O G G E D U S E R '.' U S E R N A M E ; +LOGGED_USER_ANONYMOUS: L O G G E D U S E R '.' A N O N Y M O U S ; + // fragments fragment A : [aA]; fragment B : [bB]; diff --git a/src/main/java/com/netgrif/application/engine/pfql/service/QueryLangEvaluator.java b/src/main/java/com/netgrif/application/engine/pfql/service/QueryLangEvaluator.java index 27cf81a042..1124c8a3e1 100644 --- a/src/main/java/com/netgrif/application/engine/pfql/service/QueryLangEvaluator.java +++ b/src/main/java/com/netgrif/application/engine/pfql/service/QueryLangEvaluator.java @@ -1,6 +1,8 @@ package com.netgrif.application.engine.pfql.service; +import com.netgrif.application.engine.auth.domain.LoggedUser; import com.netgrif.application.engine.auth.domain.QUser; +import com.netgrif.application.engine.auth.service.interfaces.IUserService; import com.netgrif.application.engine.petrinet.domain.QPetriNet; import com.netgrif.application.engine.pfql.domain.antlr4.QueryLangBaseListener; import com.netgrif.application.engine.pfql.domain.antlr4.QueryLangParser; @@ -23,6 +25,7 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; +import org.springframework.data.util.Pair; import java.sql.Timestamp; import java.time.LocalDateTime; @@ -38,6 +41,8 @@ public class QueryLangEvaluator extends QueryLangBaseListener { private final ParseTreeProperty elasticQuery = new ParseTreeProperty<>(); private final ParseTreeProperty mongoQuery = new ParseTreeProperty<>(); + private final IUserService userService; + @Getter private QueryType resourceType; @Getter @@ -57,6 +62,10 @@ public class QueryLangEvaluator extends QueryLangBaseListener { private int pageSize = 20; private final List sortOrders = new ArrayList<>(); + public QueryLangEvaluator(IUserService userService) { + this.userService = userService; + } + public void setElasticQuery(ParseTree node, String query) { elasticQuery.put(node, query); } @@ -136,6 +145,123 @@ private void processConditionGroup(ParseTree child, ParseTree current, Boolean n setElasticQuery(current, elasticQuery); } + private String handleStringComparisonWithPlaceholders(QueryLangParser.StringComparisonContext ctx) { + if (ctx.STRING() != null) { + return getStringValue(ctx.STRING().getText()); + } + + if (ctx.loggedUserStringAttribute() != null) { + return handleLoggedUserStringAttribute(ctx.loggedUserStringAttribute()); + } + + throw new IllegalArgumentException("Wrong or missing query value on string comparison"); + } + + private ObjectId handleObjectIdComparisonWithPlaceholders(QueryLangParser.ObjectIdComparisonContext ctx) { + if (ctx.STRING() != null) { + return getObjectIdValue(ctx.STRING().getText()); + } + if (ctx.LOGGED_USER_ID() != null) { + LoggedUser loggedUser = this.userService.getLoggedOrSystem().transformToLoggedUser(); + return getObjectIdValue(loggedUser.getId()); + } + + throw new IllegalArgumentException("Wrong or missing query value on object id comparison"); + } + + private List handleStringListComparison(QueryLangParser.StringListContext ctx) { + List result = new ArrayList<>(); + + if (ctx.STRING() != null && !ctx.STRING().isEmpty()) { + result.addAll(ctx.STRING().stream() + .map(node -> getStringValue(node.getText())) + .collect(Collectors.toList())); + } + if (ctx.loggedUserStringAttribute() != null && !ctx.loggedUserStringAttribute().isEmpty()) { + result.addAll(ctx.loggedUserStringAttribute().stream() + .map(this::handleLoggedUserStringAttribute) + .collect(Collectors.toList())); + } + + return result; + } + + private List handleObjectIdListComparison(QueryLangParser.StringListContext ctx) { + List result = new ArrayList<>(); + + if (ctx.STRING() != null && !ctx.STRING().isEmpty()) { + result.addAll(ctx.STRING().stream() + .map(node -> getObjectIdValue(node.getText())) + .collect(Collectors.toList())); + } + if (ctx.loggedUserStringAttribute() != null && !ctx.loggedUserStringAttribute().isEmpty()) { + boolean hasIdAttribute = ctx.loggedUserStringAttribute().stream() + .anyMatch(loggedUserCtx -> loggedUserCtx.LOGGED_USER_ID() != null); + if (hasIdAttribute) { + LoggedUser loggedUser = this.userService.getLoggedOrSystem().transformToLoggedUser(); + result.add(getObjectIdValue(loggedUser.getId())); + } + } + + return result; + } + + private String handleLoggedUserStringAttribute(QueryLangParser.LoggedUserStringAttributeContext ctx) { + LoggedUser loggedUser = this.userService.getLoggedOrSystem().transformToLoggedUser(); + if (ctx.LOGGED_USER_ID() != null) { + return loggedUser.getId(); + } + if (ctx.LOGGED_USER_USERNAME() != null) { + return loggedUser.getUsername(); + } + if (ctx.LOGGED_USER_FULLNAME() != null) { + return loggedUser.getFullName(); + } + return ""; + } + + /// returns pair, where the first element is left value and the second element is right value + private Pair handleInRangeStringComparison(QueryLangParser.StringRangeContext ctx) { + List filteredChildren = ctx.children.stream() + .filter(node -> node instanceof TerminalNode && ((TerminalNode) node).getSymbol().getType() == QueryLangParser.STRING + || node instanceof QueryLangParser.LoggedUserStringAttributeContext) + .collect(Collectors.toList()); + + if (filteredChildren.size() < 2) { + throw new IllegalArgumentException("Wrong in range values"); + } + + String left; + ParseTree leftNode = filteredChildren.get(0); + if (leftNode instanceof TerminalNode) { + left = getStringValue(leftNode.getText()); + } else { + left = handleLoggedUserStringAttribute((QueryLangParser.LoggedUserStringAttributeContext) leftNode); + } + + String right; + ParseTree rightNode = filteredChildren.get(1); + if (rightNode instanceof TerminalNode) { + right = getStringValue(rightNode.getText()); + } else { + right = handleLoggedUserStringAttribute((QueryLangParser.LoggedUserStringAttributeContext) rightNode); + } + + return Pair.of(left, right); + } + + private String handleBooleanComparison(QueryLangParser.BooleanComparisonContext ctx) { + if (ctx.BOOLEAN() != null) { + return ctx.BOOLEAN().getText(); + } + if (ctx.LOGGED_USER_ANONYMOUS() != null) { + LoggedUser loggedUser = this.userService.getLoggedOrSystem().transformToLoggedUser(); + return String.valueOf(loggedUser.isAnonymous()); + } + + throw new IllegalArgumentException("Wrong or missing query value on boolean comparison"); + } + private Predicate getEmptyMongoQuery() { return new BooleanBuilder(); } @@ -399,7 +525,7 @@ public void exitIdBasic(QueryLangParser.IdBasicContext ctx) { Token op = ctx.objectIdComparison().op; boolean not = ctx.objectIdComparison().NOT() != null; checkOp(ComparisonType.ID, op); - ObjectId objectId = getObjectIdValue(ctx.objectIdComparison().STRING().getText()); + ObjectId objectId = handleObjectIdComparisonWithPlaceholders(ctx.objectIdComparison()); switch (resourceType) { case PROCESS: @@ -428,12 +554,7 @@ public void exitIdList(QueryLangParser.IdListContext ctx) { Token op = ctx.inListStringComparison().op; boolean not = ctx.inListStringComparison().NOT() != null; checkOp(ComparisonType.ID, op); - List objectIdList = ctx.inListStringComparison().stringList().STRING().stream() - .map(node -> getObjectIdValue(node.getText())) - .collect(Collectors.toList()); - List stringIdList = ctx.inListStringComparison().stringList().STRING().stream() - .map(node -> getStringValue(node.getText())) - .collect(Collectors.toList()); + List objectIdList = handleObjectIdListComparison(ctx.inListStringComparison().stringList()); switch (resourceType) { case PROCESS: @@ -441,6 +562,7 @@ public void exitIdList(QueryLangParser.IdListContext ctx) { break; case CASE: qObjectId = QCase.case$._id; + List stringIdList = objectIdList.stream().map(ObjectId::toString).collect(Collectors.toList()); setElasticQuery(ctx, buildElasticQueryInList("stringId", stringIdList, not)); break; case TASK: @@ -461,7 +583,7 @@ public void exitTitleBasic(QueryLangParser.TitleBasicContext ctx) { StringPath stringPath; Token op = ctx.stringComparison().op; boolean not = ctx.stringComparison().NOT() != null; - String string = getStringValue(ctx.stringComparison().STRING().getText()); + String string = handleStringComparisonWithPlaceholders(ctx.stringComparison()); switch (resourceType) { case PROCESS: @@ -485,7 +607,7 @@ public void exitTitleBasic(QueryLangParser.TitleBasicContext ctx) { public void exitTitleList(QueryLangParser.TitleListContext ctx) { StringPath stringPath; boolean not = ctx.inListStringComparison().NOT() != null; - List stringList = ctx.inListStringComparison().stringList().STRING().stream().map(node -> getStringValue(node.getText())).collect(Collectors.toList()); + List stringList = handleStringListComparison(ctx.inListStringComparison().stringList()); switch (resourceType) { case PROCESS: @@ -511,8 +633,7 @@ public void exitTitleRange(QueryLangParser.TitleRangeContext ctx) { boolean not = ctx.inRangeStringComparison().NOT() != null; boolean leftEndpointOpen = ctx.inRangeStringComparison().stringRange().leftEndpoint.getText().equals(LEFT_OPEN_ENDPOINT); boolean rightEndpointOpen = ctx.inRangeStringComparison().stringRange().rightEndpoint.getText().equals(RIGHT_OPEN_ENDPOINT); - String leftString = getStringValue(ctx.inRangeStringComparison().stringRange().STRING(0).getText()); - String rightString = getStringValue(ctx.inRangeStringComparison().stringRange().STRING(1).getText()); + Pair leftAndRightStrings = handleInRangeStringComparison(ctx.inRangeStringComparison().stringRange()); switch (resourceType) { case PROCESS: @@ -520,7 +641,8 @@ public void exitTitleRange(QueryLangParser.TitleRangeContext ctx) { break; case CASE: stringPath = QCase.case$.title; - setElasticQuery(ctx, buildElasticQueryInRange("title", leftString, leftEndpointOpen, rightString, rightEndpointOpen, not)); + setElasticQuery(ctx, buildElasticQueryInRange("title", leftAndRightStrings.getFirst(), + leftEndpointOpen, leftAndRightStrings.getSecond(), rightEndpointOpen, not)); break; case TASK: stringPath = QTask.task.title.defaultValue; @@ -529,7 +651,8 @@ public void exitTitleRange(QueryLangParser.TitleRangeContext ctx) { throw new IllegalArgumentException("Unknown query type: " + resourceType); } - setMongoQuery(ctx, buildStringPredicateInRange(stringPath, leftString, leftEndpointOpen, rightString, rightEndpointOpen, not)); + setMongoQuery(ctx, buildStringPredicateInRange(stringPath, leftAndRightStrings.getFirst(), leftEndpointOpen, + leftAndRightStrings.getSecond(), rightEndpointOpen, not)); } @Override @@ -537,7 +660,7 @@ public void exitIdentifierBasic(QueryLangParser.IdentifierBasicContext ctx) { StringPath stringPath = QPetriNet.petriNet.identifier; Token op = ctx.stringComparison().op; boolean not = ctx.stringComparison().NOT() != null; - String string = getStringValue(ctx.stringComparison().STRING().getText()); + String string = handleStringComparisonWithPlaceholders(ctx.stringComparison()); setMongoQuery(ctx, buildStringPredicate(stringPath, op.getType(), string, not)); } @@ -546,7 +669,7 @@ public void exitIdentifierBasic(QueryLangParser.IdentifierBasicContext ctx) { public void exitIdentifierList(QueryLangParser.IdentifierListContext ctx) { StringPath stringPath = QPetriNet.petriNet.identifier; boolean not = ctx.inListStringComparison().NOT() != null; - List stringList = ctx.inListStringComparison().stringList().STRING().stream().map(node -> getStringValue(node.getText())).collect(Collectors.toList()); + List stringList = handleStringListComparison(ctx.inListStringComparison().stringList()); setMongoQuery(ctx, buildStringPredicateInList(stringPath, stringList, not)); } @@ -557,10 +680,10 @@ public void exitIdentifierRange(QueryLangParser.IdentifierRangeContext ctx) { boolean not = ctx.inRangeStringComparison().NOT() != null; boolean leftEndpointOpen = ctx.inRangeStringComparison().stringRange().leftEndpoint.getText().equals(LEFT_OPEN_ENDPOINT); boolean rightEndpointOpen = ctx.inRangeStringComparison().stringRange().rightEndpoint.getText().equals(RIGHT_OPEN_ENDPOINT); - String leftString = getStringValue(ctx.inRangeStringComparison().stringRange().STRING(0).getText()); - String rightString = getStringValue(ctx.inRangeStringComparison().stringRange().STRING(1).getText()); + Pair leftAndRightStrings = handleInRangeStringComparison(ctx.inRangeStringComparison().stringRange()); - setMongoQuery(ctx, buildStringPredicateInRange(stringPath, leftString, leftEndpointOpen, rightString, rightEndpointOpen, not)); + setMongoQuery(ctx, buildStringPredicateInRange(stringPath, leftAndRightStrings.getFirst(), leftEndpointOpen, + leftAndRightStrings.getSecond(), rightEndpointOpen, not)); } @Override @@ -702,7 +825,7 @@ public void exitProcessIdBasic(QueryLangParser.ProcessIdBasicContext ctx) { StringPath stringPath = QTask.task.processId; Token op = ctx.stringComparison().op; boolean not = ctx.stringComparison().NOT() != null; - String string = getStringValue(ctx.stringComparison().STRING().getText()); + String string = handleStringComparisonWithPlaceholders(ctx.stringComparison()); setMongoQuery(ctx, buildStringPredicate(stringPath, op.getType(), string, not)); } @@ -711,9 +834,7 @@ public void exitProcessIdBasic(QueryLangParser.ProcessIdBasicContext ctx) { public void exitProcessIdList(QueryLangParser.ProcessIdListContext ctx) { StringPath stringPath = QTask.task.processId; boolean not = ctx.inListStringComparison().NOT() != null; - List stringList = ctx.inListStringComparison().stringList().STRING().stream() - .map(node -> getStringValue(node.getText())) - .collect(Collectors.toList()); + List stringList = handleStringListComparison(ctx.inListStringComparison().stringList()); setMongoQuery(ctx, buildStringPredicateInList(stringPath, stringList, not)); } @@ -723,7 +844,7 @@ public void exitProcessIdObjIdBasic(QueryLangParser.ProcessIdObjIdBasicContext c QObjectId qObjectId = QCase.case$.petriNetObjectId; Token op = ctx.objectIdComparison().op; boolean not = ctx.objectIdComparison().NOT() != null; - ObjectId objectId = getObjectIdValue(ctx.objectIdComparison().STRING().getText()); + ObjectId objectId = handleObjectIdComparisonWithPlaceholders(ctx.objectIdComparison()); setMongoQuery(ctx, buildObjectIdPredicate(qObjectId, op.getType(), objectId, not)); setElasticQuery(ctx, buildElasticQuery("processId", op.getType(), objectId.toString(), not)); @@ -733,12 +854,8 @@ public void exitProcessIdObjIdBasic(QueryLangParser.ProcessIdObjIdBasicContext c public void exitProcessIdObjIdList(QueryLangParser.ProcessIdObjIdListContext ctx) { QObjectId qObjectId = QCase.case$.petriNetObjectId; boolean not = ctx.inListStringComparison().NOT() != null; - List objectIdList = ctx.inListStringComparison().stringList().STRING().stream() - .map(node -> getObjectIdValue(node.getText())) - .collect(Collectors.toList()); - List stringList = ctx.inListStringComparison().stringList().STRING().stream() - .map(node -> getStringValue(node.getText())) - .collect(Collectors.toList()); + List objectIdList = handleObjectIdListComparison(ctx.inListStringComparison().stringList()); + List stringList = handleStringListComparison(ctx.inListStringComparison().stringList()); setMongoQuery(ctx, buildObjectIdPredicateInList(qObjectId, objectIdList, not)); setElasticQuery(ctx, buildElasticQueryInList("processId", stringList, not)); @@ -749,7 +866,7 @@ public void exitProcessIdentifierBasic(QueryLangParser.ProcessIdentifierBasicCon StringPath stringPath = QCase.case$.processIdentifier; Token op = ctx.stringComparison().op; boolean not = ctx.stringComparison().NOT() != null; - String string = getStringValue(ctx.stringComparison().STRING().getText()); + String string = handleStringComparisonWithPlaceholders(ctx.stringComparison()); setMongoQuery(ctx, buildStringPredicate(stringPath, op.getType(), string, not)); setElasticQuery(ctx, buildElasticQuery("processIdentifier", op.getType(), string, not)); @@ -759,7 +876,7 @@ public void exitProcessIdentifierBasic(QueryLangParser.ProcessIdentifierBasicCon public void exitProcessIdentifierList(QueryLangParser.ProcessIdentifierListContext ctx) { StringPath stringPath = QCase.case$.processIdentifier; boolean not = ctx.inListStringComparison().NOT() != null; - List stringList = ctx.inListStringComparison().stringList().STRING().stream().map(node -> getStringValue(node.getText())).collect(Collectors.toList()); + List stringList = handleStringListComparison(ctx.inListStringComparison().stringList()); setMongoQuery(ctx, buildStringPredicateInList(stringPath, stringList, not)); setElasticQuery(ctx, buildElasticQueryInList("processIdentifier", stringList, not)); @@ -771,11 +888,12 @@ public void exitProcessIdentifierRange(QueryLangParser.ProcessIdentifierRangeCon boolean not = ctx.inRangeStringComparison().NOT() != null; boolean leftEndpointOpen = ctx.inRangeStringComparison().stringRange().leftEndpoint.getText().equals(LEFT_OPEN_ENDPOINT); boolean rightEndpointOpen = ctx.inRangeStringComparison().stringRange().rightEndpoint.getText().equals(RIGHT_OPEN_ENDPOINT); - String leftString = getStringValue(ctx.inRangeStringComparison().stringRange().STRING(0).getText()); - String rightString = getStringValue(ctx.inRangeStringComparison().stringRange().STRING(1).getText()); + Pair leftAndRightStrings = handleInRangeStringComparison(ctx.inRangeStringComparison().stringRange()); - setMongoQuery(ctx, buildStringPredicateInRange(stringPath, leftString, leftEndpointOpen, rightString, rightEndpointOpen, not)); - setElasticQuery(ctx, buildElasticQueryInRange("processIdentifier", leftString, leftEndpointOpen, rightString, rightEndpointOpen, not)); + setMongoQuery(ctx, buildStringPredicateInRange(stringPath, leftAndRightStrings.getFirst(), leftEndpointOpen, + leftAndRightStrings.getSecond(), rightEndpointOpen, not)); + setElasticQuery(ctx, buildElasticQueryInRange("processIdentifier", leftAndRightStrings.getFirst(), + leftEndpointOpen, leftAndRightStrings.getSecond(), rightEndpointOpen, not)); } @Override @@ -783,7 +901,7 @@ public void exitAuthorBasic(QueryLangParser.AuthorBasicContext ctx) { StringPath stringPath = QCase.case$.author.id; Token op = ctx.stringComparison().op; boolean not = ctx.stringComparison().NOT() != null; - String string = getStringValue(ctx.stringComparison().STRING().getText()); + String string = handleStringComparisonWithPlaceholders(ctx.stringComparison()); setMongoQuery(ctx, buildStringPredicate(stringPath, op.getType(), string, not)); setElasticQuery(ctx, buildElasticQuery("author", op.getType(), string, not)); @@ -793,9 +911,7 @@ public void exitAuthorBasic(QueryLangParser.AuthorBasicContext ctx) { public void exitAuthorList(QueryLangParser.AuthorListContext ctx) { StringPath stringPath = QCase.case$.author.id; boolean not = ctx.inListStringComparison().NOT() != null; - List stringList = ctx.inListStringComparison().stringList().STRING().stream() - .map(node -> getStringValue(node.getText())) - .collect(Collectors.toList()); + List stringList = handleStringListComparison(ctx.inListStringComparison().stringList()); setMongoQuery(ctx, buildStringPredicateInList(stringPath, stringList, not)); setElasticQuery(ctx, buildElasticQueryInList("author", stringList, not)); @@ -806,7 +922,7 @@ public void exitTransitionIdBasic(QueryLangParser.TransitionIdBasicContext ctx) StringPath stringPath = QTask.task.transitionId; Token op = ctx.stringComparison().op; boolean not = ctx.stringComparison().NOT() != null; - String string = getStringValue(ctx.stringComparison().STRING().getText()); + String string = handleStringComparisonWithPlaceholders(ctx.stringComparison()); setMongoQuery(ctx, buildStringPredicate(stringPath, op.getType(), string, not)); } @@ -815,7 +931,7 @@ public void exitTransitionIdBasic(QueryLangParser.TransitionIdBasicContext ctx) public void exitTransitionIdList(QueryLangParser.TransitionIdListContext ctx) { StringPath stringPath = QTask.task.transitionId; boolean not = ctx.inListStringComparison().NOT() != null; - List stringList = ctx.inListStringComparison().stringList().STRING().stream().map(node -> getStringValue(node.getText())).collect(Collectors.toList()); + List stringList = handleStringListComparison(ctx.inListStringComparison().stringList()); setMongoQuery(ctx, buildStringPredicateInList(stringPath, stringList, not)); } @@ -826,10 +942,10 @@ public void exitTransitionIdRange(QueryLangParser.TransitionIdRangeContext ctx) boolean not = ctx.inRangeStringComparison().NOT() != null; boolean leftEndpointOpen = ctx.inRangeStringComparison().stringRange().leftEndpoint.getText().equals(LEFT_OPEN_ENDPOINT); boolean rightEndpointOpen = ctx.inRangeStringComparison().stringRange().rightEndpoint.getText().equals(RIGHT_OPEN_ENDPOINT); - String leftString = getStringValue(ctx.inRangeStringComparison().stringRange().STRING(0).getText()); - String rightString = getStringValue(ctx.inRangeStringComparison().stringRange().STRING(1).getText()); + Pair leftAndRightStrings = handleInRangeStringComparison(ctx.inRangeStringComparison().stringRange()); - setMongoQuery(ctx, buildStringPredicateInRange(stringPath, leftString, leftEndpointOpen, rightString, rightEndpointOpen, not)); + setMongoQuery(ctx, buildStringPredicateInRange(stringPath, leftAndRightStrings.getFirst(), leftEndpointOpen, + leftAndRightStrings.getSecond(), rightEndpointOpen, not)); } @Override @@ -850,7 +966,7 @@ public void exitUserIdBasic(QueryLangParser.UserIdBasicContext ctx) { StringPath stringPath = QTask.task.userId; Token op = ctx.stringComparison().op; boolean not = ctx.stringComparison().NOT() != null; - String string = getStringValue(ctx.stringComparison().STRING().getText()); + String string = handleStringComparisonWithPlaceholders(ctx.stringComparison()); setMongoQuery(ctx, buildStringPredicate(stringPath, op.getType(), string, not)); } @@ -859,9 +975,7 @@ public void exitUserIdBasic(QueryLangParser.UserIdBasicContext ctx) { public void exitUserIdList(QueryLangParser.UserIdListContext ctx) { StringPath stringPath = QTask.task.userId; boolean not = ctx.inListStringComparison().NOT() != null; - List stringList = ctx.inListStringComparison().stringList().STRING().stream() - .map(node -> getStringValue(node.getText())) - .collect(Collectors.toList()); + List stringList = handleStringListComparison(ctx.inListStringComparison().stringList()); setMongoQuery(ctx, buildStringPredicateInList(stringPath, stringList, not)); } @@ -871,7 +985,7 @@ public void exitCaseIdBasic(QueryLangParser.CaseIdBasicContext ctx) { StringPath stringPath = QTask.task.caseId; Token op = ctx.stringComparison().op; boolean not = ctx.stringComparison().NOT() != null; - String string = getStringValue(ctx.stringComparison().STRING().getText()); + String string = handleStringComparisonWithPlaceholders(ctx.stringComparison()); setMongoQuery(ctx, buildStringPredicate(stringPath, op.getType(), string, not)); } @@ -880,9 +994,7 @@ public void exitCaseIdBasic(QueryLangParser.CaseIdBasicContext ctx) { public void exitCaseIdList(QueryLangParser.CaseIdListContext ctx) { StringPath stringPath = QTask.task.caseId; boolean not = ctx.inListStringComparison().NOT() != null; - List stringList = ctx.inListStringComparison().stringList().STRING().stream() - .map(node -> getStringValue(node.getText())) - .collect(Collectors.toList()); + List stringList = handleStringListComparison(ctx.inListStringComparison().stringList()); setMongoQuery(ctx, buildStringPredicateInList(stringPath, stringList, not)); } @@ -1006,7 +1118,7 @@ public void exitNameBasic(QueryLangParser.NameBasicContext ctx) { StringPath stringPath = QUser.user.name; Token op = ctx.stringComparison().op; boolean not = ctx.stringComparison().NOT() != null; - String string = getStringValue(ctx.stringComparison().STRING().getText()); + String string = handleStringComparisonWithPlaceholders(ctx.stringComparison()); setMongoQuery(ctx, buildStringPredicate(stringPath, op.getType(), string, not)); } @@ -1015,7 +1127,7 @@ public void exitNameBasic(QueryLangParser.NameBasicContext ctx) { public void exitNameList(QueryLangParser.NameListContext ctx) { StringPath stringPath = QUser.user.name; boolean not = ctx.inListStringComparison().NOT() != null; - List stringList = ctx.inListStringComparison().stringList().STRING().stream().map(node -> getStringValue(node.getText())).collect(Collectors.toList()); + List stringList = handleStringListComparison(ctx.inListStringComparison().stringList()); setMongoQuery(ctx, buildStringPredicateInList(stringPath, stringList, not)); } @@ -1026,10 +1138,10 @@ public void exitNameRange(QueryLangParser.NameRangeContext ctx) { boolean not = ctx.inRangeStringComparison().NOT() != null; boolean leftEndpointOpen = ctx.inRangeStringComparison().stringRange().leftEndpoint.getText().equals(LEFT_OPEN_ENDPOINT); boolean rightEndpointOpen = ctx.inRangeStringComparison().stringRange().rightEndpoint.getText().equals(RIGHT_OPEN_ENDPOINT); - String leftString = getStringValue(ctx.inRangeStringComparison().stringRange().STRING(0).getText()); - String rightString = getStringValue(ctx.inRangeStringComparison().stringRange().STRING(1).getText()); + Pair leftAndRightStrings = handleInRangeStringComparison(ctx.inRangeStringComparison().stringRange()); - setMongoQuery(ctx, buildStringPredicateInRange(stringPath, leftString, leftEndpointOpen, rightString, rightEndpointOpen, not)); + setMongoQuery(ctx, buildStringPredicateInRange(stringPath, leftAndRightStrings.getFirst(), leftEndpointOpen, + leftAndRightStrings.getSecond(), rightEndpointOpen, not)); } @Override @@ -1037,7 +1149,7 @@ public void exitSurnameBasic(QueryLangParser.SurnameBasicContext ctx) { StringPath stringPath = QUser.user.surname; Token op = ctx.stringComparison().op; boolean not = ctx.stringComparison().NOT() != null; - String string = getStringValue(ctx.stringComparison().STRING().getText()); + String string = handleStringComparisonWithPlaceholders(ctx.stringComparison()); setMongoQuery(ctx, buildStringPredicate(stringPath, op.getType(), string, not)); } @@ -1046,7 +1158,7 @@ public void exitSurnameBasic(QueryLangParser.SurnameBasicContext ctx) { public void exitSurnameList(QueryLangParser.SurnameListContext ctx) { StringPath stringPath = QUser.user.surname; boolean not = ctx.inListStringComparison().NOT() != null; - List stringList = ctx.inListStringComparison().stringList().STRING().stream().map(node -> getStringValue(node.getText())).collect(Collectors.toList()); + List stringList = handleStringListComparison(ctx.inListStringComparison().stringList()); setMongoQuery(ctx, buildStringPredicateInList(stringPath, stringList, not)); } @@ -1057,10 +1169,10 @@ public void exitSurnameRange(QueryLangParser.SurnameRangeContext ctx) { boolean not = ctx.inRangeStringComparison().NOT() != null; boolean leftEndpointOpen = ctx.inRangeStringComparison().stringRange().leftEndpoint.getText().equals(LEFT_OPEN_ENDPOINT); boolean rightEndpointOpen = ctx.inRangeStringComparison().stringRange().rightEndpoint.getText().equals(RIGHT_OPEN_ENDPOINT); - String leftString = getStringValue(ctx.inRangeStringComparison().stringRange().STRING(0).getText()); - String rightString = getStringValue(ctx.inRangeStringComparison().stringRange().STRING(1).getText()); + Pair leftAndRightStrings = handleInRangeStringComparison(ctx.inRangeStringComparison().stringRange()); - setMongoQuery(ctx, buildStringPredicateInRange(stringPath, leftString, leftEndpointOpen, rightString, rightEndpointOpen, not)); + setMongoQuery(ctx, buildStringPredicateInRange(stringPath, leftAndRightStrings.getFirst(), leftEndpointOpen, + leftAndRightStrings.getSecond(), rightEndpointOpen, not)); } @Override @@ -1068,7 +1180,7 @@ public void exitEmailBasic(QueryLangParser.EmailBasicContext ctx) { StringPath stringPath = QUser.user.email; Token op = ctx.stringComparison().op; boolean not = ctx.stringComparison().NOT() != null; - String string = getStringValue(ctx.stringComparison().STRING().getText()); + String string = handleStringComparisonWithPlaceholders(ctx.stringComparison()); setMongoQuery(ctx, buildStringPredicate(stringPath, op.getType(), string, not)); } @@ -1077,7 +1189,7 @@ public void exitEmailBasic(QueryLangParser.EmailBasicContext ctx) { public void exitEmailList(QueryLangParser.EmailListContext ctx) { StringPath stringPath = QUser.user.email; boolean not = ctx.inListStringComparison().NOT() != null; - List stringList = ctx.inListStringComparison().stringList().STRING().stream().map(node -> getStringValue(node.getText())).collect(Collectors.toList()); + List stringList = handleStringListComparison(ctx.inListStringComparison().stringList()); setMongoQuery(ctx, buildStringPredicateInList(stringPath, stringList, not)); } @@ -1088,10 +1200,10 @@ public void exitEmailRange(QueryLangParser.EmailRangeContext ctx) { boolean not = ctx.inRangeStringComparison().NOT() != null; boolean leftEndpointOpen = ctx.inRangeStringComparison().stringRange().leftEndpoint.getText().equals(LEFT_OPEN_ENDPOINT); boolean rightEndpointOpen = ctx.inRangeStringComparison().stringRange().rightEndpoint.getText().equals(RIGHT_OPEN_ENDPOINT); - String leftString = getStringValue(ctx.inRangeStringComparison().stringRange().STRING(0).getText()); - String rightString = getStringValue(ctx.inRangeStringComparison().stringRange().STRING(1).getText()); + Pair leftAndRightStrings = handleInRangeStringComparison(ctx.inRangeStringComparison().stringRange()); - setMongoQuery(ctx, buildStringPredicateInRange(stringPath, leftString, leftEndpointOpen, rightString, rightEndpointOpen, not)); + setMongoQuery(ctx, buildStringPredicateInRange(stringPath, leftAndRightStrings.getFirst(), leftEndpointOpen, + leftAndRightStrings.getSecond(), rightEndpointOpen, not)); } @Override @@ -1100,7 +1212,7 @@ public void exitDataString(QueryLangParser.DataStringContext ctx) { Token op = ctx.stringComparison().op; checkOp(ComparisonType.STRING, op); boolean not = ctx.stringComparison().NOT() != null; - String string = getStringValue(ctx.stringComparison().STRING().getText()); + String string = handleStringComparisonWithPlaceholders(ctx.stringComparison()); setMongoQuery(ctx, null); setElasticQuery(ctx, buildElasticQuery("dataSet." + fieldId + ".textValue", op.getType(), string, not)); @@ -1111,7 +1223,7 @@ public void exitDataString(QueryLangParser.DataStringContext ctx) { public void exitDataStringList(QueryLangParser.DataStringListContext ctx) { String fieldId = ctx.dataValue().fieldId.getText(); boolean not = ctx.inListStringComparison().NOT() != null; - List stringList = ctx.inListStringComparison().stringList().STRING().stream().map(node -> getStringValue(node.getText())).collect(Collectors.toList()); + List stringList = handleStringListComparison(ctx.inListStringComparison().stringList()); setMongoQuery(ctx, null); setElasticQuery(ctx, buildElasticQueryInList("dataSet." + fieldId + ".textValue", stringList, not)); @@ -1124,11 +1236,11 @@ public void exitDataStringRange(QueryLangParser.DataStringRangeContext ctx) { boolean not = ctx.inRangeStringComparison().NOT() != null; boolean leftEndpointOpen = ctx.inRangeStringComparison().stringRange().leftEndpoint.getText().equals(LEFT_OPEN_ENDPOINT); boolean rightEndpointOpen = ctx.inRangeStringComparison().stringRange().rightEndpoint.getText().equals(RIGHT_OPEN_ENDPOINT); - String leftString = getStringValue(ctx.inRangeStringComparison().stringRange().STRING(0).getText()); - String rightString = getStringValue(ctx.inRangeStringComparison().stringRange().STRING(1).getText()); + Pair leftAndRightStrings = handleInRangeStringComparison(ctx.inRangeStringComparison().stringRange()); setMongoQuery(ctx, null); - setElasticQuery(ctx, buildElasticQueryInRange("dataSet." + fieldId + ".textValue", leftString, leftEndpointOpen, rightString, rightEndpointOpen, not)); + setElasticQuery(ctx, buildElasticQueryInRange("dataSet." + fieldId + ".textValue", leftAndRightStrings.getFirst(), + leftEndpointOpen, leftAndRightStrings.getSecond(), rightEndpointOpen, not)); this.searchWithElastic = true; } @@ -1254,7 +1366,7 @@ public void exitDataBoolean(QueryLangParser.DataBooleanContext ctx) { Token op = ctx.booleanComparison().op; checkOp(ComparisonType.BOOLEAN, op); boolean not = ctx.booleanComparison().NOT() != null; - String booleanValue = ctx.booleanComparison().BOOLEAN().getText(); + String booleanValue = handleBooleanComparison(ctx.booleanComparison()); setMongoQuery(ctx, null); setElasticQuery(ctx, buildElasticQuery("dataSet." + fieldId + ".booleanValue", op.getType(), booleanValue, not)); @@ -1267,7 +1379,7 @@ public void exitDataOptionsBasic(QueryLangParser.DataOptionsBasicContext ctx) { Token op = ctx.stringComparison().op; checkOp(ComparisonType.STRING, op); boolean not = ctx.stringComparison().NOT() != null; - String string = getStringValue(ctx.stringComparison().STRING().getText()); + String string = handleStringComparisonWithPlaceholders(ctx.stringComparison()); setMongoQuery(ctx, null); setElasticQuery(ctx, buildElasticQuery("dataSet." + fieldId + ".options", op.getType(), string, not)); @@ -1278,7 +1390,7 @@ public void exitDataOptionsBasic(QueryLangParser.DataOptionsBasicContext ctx) { public void exitDataOptionsList(QueryLangParser.DataOptionsListContext ctx) { String fieldId = ctx.dataOptions().fieldId.getText(); boolean not = ctx.inListStringComparison().NOT() != null; - List stringList = ctx.inListStringComparison().stringList().STRING().stream().map(node -> getStringValue(node.getText())).collect(Collectors.toList()); + List stringList = handleStringListComparison(ctx.inListStringComparison().stringList()); setMongoQuery(ctx, null); setElasticQuery(ctx, buildElasticQueryInList("dataSet." + fieldId + ".options", stringList, not)); @@ -1291,11 +1403,11 @@ public void exitDataOptionsRange(QueryLangParser.DataOptionsRangeContext ctx) { boolean not = ctx.inRangeStringComparison().NOT() != null; boolean leftEndpointOpen = ctx.inRangeStringComparison().stringRange().leftEndpoint.getText().equals(LEFT_OPEN_ENDPOINT); boolean rightEndpointOpen = ctx.inRangeStringComparison().stringRange().rightEndpoint.getText().equals(RIGHT_OPEN_ENDPOINT); - String leftString = getStringValue(ctx.inRangeStringComparison().stringRange().STRING(0).getText()); - String rightString = getStringValue(ctx.inRangeStringComparison().stringRange().STRING(1).getText()); + Pair leftAndRightStrings = handleInRangeStringComparison(ctx.inRangeStringComparison().stringRange()); setMongoQuery(ctx, null); - setElasticQuery(ctx, buildElasticQueryInRange("dataSet." + fieldId + ".options", leftString, leftEndpointOpen, rightString, rightEndpointOpen, not)); + setElasticQuery(ctx, buildElasticQueryInRange("dataSet." + fieldId + ".options", leftAndRightStrings.getFirst(), + leftEndpointOpen, leftAndRightStrings.getSecond(), rightEndpointOpen, not)); this.searchWithElastic = true; } @@ -1369,7 +1481,7 @@ public void exitTasksUserIdBasic(QueryLangParser.TasksUserIdBasicContext ctx) { Token op = ctx.stringComparison().op; checkOp(ComparisonType.STRING, op); boolean not = ctx.stringComparison().NOT() != null; - String string = getStringValue(ctx.stringComparison().STRING().getText()); + String string = handleStringComparisonWithPlaceholders(ctx.stringComparison()); setMongoQuery(ctx, null); setElasticQuery(ctx, buildElasticQuery("tasks." + taskId + ".userId", op.getType(), string, not)); @@ -1380,9 +1492,7 @@ public void exitTasksUserIdBasic(QueryLangParser.TasksUserIdBasicContext ctx) { public void exitTasksUserIdList(QueryLangParser.TasksUserIdListContext ctx) { String taskId = ctx.tasksUserId().taskId.getText(); boolean not = ctx.inListStringComparison().NOT() != null; - List stringList = ctx.inListStringComparison().stringList().STRING().stream() - .map(node -> getStringValue(node.getText())) - .collect(Collectors.toList()); + List stringList = handleStringListComparison(ctx.inListStringComparison().stringList()); setMongoQuery(ctx, null); setElasticQuery(ctx, buildElasticQueryInList("tasks." + taskId + ".userId", stringList, not)); diff --git a/src/main/java/com/netgrif/application/engine/pfql/service/utils/SearchUtils.java b/src/main/java/com/netgrif/application/engine/pfql/service/utils/SearchUtils.java index a9af2f6a57..4a4f5ddf04 100644 --- a/src/main/java/com/netgrif/application/engine/pfql/service/utils/SearchUtils.java +++ b/src/main/java/com/netgrif/application/engine/pfql/service/utils/SearchUtils.java @@ -1,5 +1,7 @@ package com.netgrif.application.engine.pfql.service.utils; +import com.netgrif.application.engine.auth.service.interfaces.IUserService; +import com.netgrif.application.engine.configuration.ApplicationContextProvider; import com.netgrif.application.engine.petrinet.domain.QPetriNet; import com.netgrif.application.engine.petrinet.domain.version.QVersion; import com.netgrif.application.engine.petrinet.domain.version.Version; @@ -161,7 +163,8 @@ private static QueryLangBaseListener evaluateQueryInternal(String input, boolean return explainQueryInternal(walker, query, errorListener); } - QueryLangEvaluator evaluator = new QueryLangEvaluator(); + IUserService userService = (IUserService) ApplicationContextProvider.getBean(IUserService.class); + QueryLangEvaluator evaluator = new QueryLangEvaluator(userService); walker.walk(evaluator, query); return evaluator; diff --git a/src/test/java/com/netgrif/application/engine/pfql/QueryLangTest.java b/src/test/java/com/netgrif/application/engine/pfql/QueryLangTest.java index 929f7e242a..451d7334b1 100644 --- a/src/test/java/com/netgrif/application/engine/pfql/QueryLangTest.java +++ b/src/test/java/com/netgrif/application/engine/pfql/QueryLangTest.java @@ -1,8 +1,11 @@ package com.netgrif.application.engine.pfql; import com.netgrif.application.engine.TestHelper; +import com.netgrif.application.engine.auth.domain.IUser; +import com.netgrif.application.engine.auth.domain.LoggedUser; import com.netgrif.application.engine.auth.domain.QUser; import com.netgrif.application.engine.auth.domain.User; +import com.netgrif.application.engine.auth.service.interfaces.IUserService; import com.netgrif.application.engine.petrinet.domain.PetriNet; import com.netgrif.application.engine.petrinet.domain.QPetriNet; import com.netgrif.application.engine.petrinet.domain.version.Version; @@ -19,7 +22,6 @@ import com.querydsl.core.types.dsl.StringPath; import org.bson.Document; import org.bson.types.ObjectId; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -61,10 +63,12 @@ public class QueryLangTest { @Autowired private TestHelper testHelper; + @Autowired + private IUserService userService; + @Test @SuppressWarnings("unchecked") - @Disabled - public void testSearchService() { + public void testSearchService() throws InterruptedException { testHelper.truncateDbs(); Optional optionalPetriNet = helper.createNet("/pfql.xml"); @@ -81,6 +85,8 @@ public void testSearchService() { helper.createCase(String.format("Test %02d", i), process, params); } + Thread.sleep(2000); + Object cases = searchService.search("cases: processIdentifier eq 'query_test' page 1 size 5 sort by title desc"); assertNotNull(cases); assertEquals(PageImpl.class, cases.getClass()); @@ -107,6 +113,9 @@ public void testSearchService() { cases = searchService.search("cases: processIdentifier eq 'query_test' and data.boolean_0.value == true and data.text_0.value != '4'"); assertEquals(4, ((Page) cases).getTotalElements()); + + cases = searchService.search("cases: processIdentifier eq 'query_test' and author eq loggedUser.id"); + assertEquals(10, ((Page) cases).getTotalElements()); } @Test @@ -238,6 +247,12 @@ public void testComplexMongodbProcessQuery() { compareMongoQueries(mongoDbUtils, actual, expected); + IUser systemUser = userService.getSystem(); + actual = evaluateQuery("process: id neq loggedUser.id").getFullMongoQuery(); + expected = QPetriNet.petriNet._id.eq(new ObjectId(systemUser.getStringId())).not(); + + compareMongoQueries(mongoDbUtils, actual, expected); + // and comparison actual = evaluateQuery(String.format("process: id eq '%s' and title eq 'test'", GENERIC_OBJECT_ID)).getFullMongoQuery(); expected = QPetriNet.petriNet._id.eq(GENERIC_OBJECT_ID).and(QPetriNet.petriNet.title.defaultValue.eq("test")); @@ -304,7 +319,20 @@ public void testSimpleMongodbCaseQuery() { compareMongoQueries(mongoDbUtils, actual, expected); - actual = evaluateQuery(String.format("case: id in ('%s', '%s')", GENERIC_OBJECT_ID, GENERIC_OBJECT_ID)).getFullMongoQuery(); + LoggedUser systemUser = userService.getSystem().transformToLoggedUser(); + actual = evaluateQuery("case: id neq loggedUser.id").getFullMongoQuery(); + expected = QCase.case$._id.eq(new ObjectId(systemUser.getId())).not(); + + compareMongoQueries(mongoDbUtils, actual, expected); + + actual = evaluateQuery(String.format("case: id in ('%s', '%s', loggedUser.id, loggedUser.username, loggedUser.fullName)", + GENERIC_OBJECT_ID, GENERIC_OBJECT_ID)).getFullMongoQuery(); + expected = QCase.case$._id.in(GENERIC_OBJECT_ID, GENERIC_OBJECT_ID, new ObjectId(systemUser.getId())); + + compareMongoQueries(mongoDbUtils, actual, expected); + + actual = evaluateQuery(String.format("case: id in ('%s', '%s', loggedUser.username, loggedUser.fullName)", + GENERIC_OBJECT_ID, GENERIC_OBJECT_ID)).getFullMongoQuery(); expected = QCase.case$._id.in(GENERIC_OBJECT_ID, GENERIC_OBJECT_ID); compareMongoQueries(mongoDbUtils, actual, expected); @@ -335,16 +363,37 @@ public void testSimpleMongodbCaseQuery() { compareMongoQueries(mongoDbUtils, actual, expected); + actual = evaluateQuery("case: author eq loggedUser.id").getFullMongoQuery(); + expected = QCase.case$.author.id.eq(systemUser.getId()); + + compareMongoQueries(mongoDbUtils, actual, expected); + actual = evaluateQuery("case: author contains 'test'").getFullMongoQuery(); expected = QCase.case$.author.id.contains("test"); compareMongoQueries(mongoDbUtils, actual, expected); - actual = evaluateQuery("case: author in ('test', 'test1')").getFullMongoQuery(); - expected = QCase.case$.author.id.in("test", "test1"); + actual = evaluateQuery("case: author in ('test', 'test1', loggedUser.id, loggedUser.username, loggedUser.fullName)").getFullMongoQuery(); + expected = QCase.case$.author.id.in("test", "test1", systemUser.getId(), systemUser.getUsername(), systemUser.getFullName()); compareMongoQueries(mongoDbUtils, actual, expected); + actual = evaluateQuery("cases: title in ('test1' : loggedUser.username)").getFullMongoQuery(); + expected = QCase.case$.title.gt("test1").and(QCase.case$.title.lt(systemUser.getUsername())); + + compareMongoQueries(mongoDbUtils, actual, expected); + + actual = evaluateQuery("cases: title in (loggedUser.username : 'test1')").getFullMongoQuery(); + expected = QCase.case$.title.gt(systemUser.getUsername()).and(QCase.case$.title.lt("test1")); + + compareMongoQueries(mongoDbUtils, actual, expected); + + actual = evaluateQuery("cases: title in (loggedUser.username : loggedUser.fullName)").getFullMongoQuery(); + expected = QCase.case$.title.gt(systemUser.getUsername()).and(QCase.case$.title.lt(systemUser.getFullName())); + + compareMongoQueries(mongoDbUtils, actual, expected); + + // only available for elastic query // places comparison actual = evaluateQuery("case: places.p1.marking eq 1").getFullMongoQuery(); @@ -459,8 +508,11 @@ public void testComplexMongodbCaseQuery() { compareMongoQueries(mongoDbUtils, actual, expected); // parenthesis comparison - actual = evaluateQuery(String.format("case: id eq '%s' and (title eq 'test' or title eq 'test1')", GENERIC_OBJECT_ID)).getFullMongoQuery(); - expected = QCase.case$._id.eq(GENERIC_OBJECT_ID).and(QCase.case$.title.eq("test").or(QCase.case$.title.eq("test1"))); + LoggedUser systemUser = userService.getSystem().transformToLoggedUser(); + actual = evaluateQuery(String.format("case: id eq '%s' and (title eq 'test' or title eq 'test1' or title eq loggedUser.username)", + GENERIC_OBJECT_ID)).getFullMongoQuery(); + expected = QCase.case$._id.eq(GENERIC_OBJECT_ID) + .and(QCase.case$.title.eq("test").or(QCase.case$.title.eq("test1")).or(QCase.case$.title.eq(systemUser.getUsername()))); compareMongoQueries(mongoDbUtils, actual, expected); @@ -489,8 +541,9 @@ public void testSimpleMongodbTaskQuery() { compareMongoQueries(mongoDbUtils, actual, expected); - actual = evaluateQuery(String.format("task: id in ('%s', '%s')", GENERIC_OBJECT_ID, GENERIC_OBJECT_ID)).getFullMongoQuery(); - expected = QTask.task._id.in(GENERIC_OBJECT_ID, GENERIC_OBJECT_ID); + LoggedUser systemUser = userService.getSystem().transformToLoggedUser(); + actual = evaluateQuery(String.format("task: id in ('%s', '%s', loggedUser.id)", GENERIC_OBJECT_ID, GENERIC_OBJECT_ID)).getFullMongoQuery(); + expected = QTask.task._id.in(GENERIC_OBJECT_ID, GENERIC_OBJECT_ID, new ObjectId(systemUser.getId())); compareMongoQueries(mongoDbUtils, actual, expected); @@ -654,8 +707,14 @@ public void testSimpleMongodbUserQuery() { compareMongoQueries(mongoDbUtils, actual, expected); - actual = evaluateQuery(String.format("user: id in ('%s', '%s')", GENERIC_OBJECT_ID, GENERIC_OBJECT_ID)).getFullMongoQuery(); - expected = QUser.user._id.in(GENERIC_OBJECT_ID, GENERIC_OBJECT_ID); + LoggedUser systemUser = userService.getSystem().transformToLoggedUser(); + actual = evaluateQuery("user: id eq loggedUser.id").getFullMongoQuery(); + expected = QUser.user._id.eq(new ObjectId(systemUser.getId())); + + compareMongoQueries(mongoDbUtils, actual, expected); + + actual = evaluateQuery(String.format("user: id in ('%s', '%s', loggEduser.id)", GENERIC_OBJECT_ID, GENERIC_OBJECT_ID)).getFullMongoQuery(); + expected = QUser.user._id.in(GENERIC_OBJECT_ID, GENERIC_OBJECT_ID, new ObjectId(systemUser.getId())); compareMongoQueries(mongoDbUtils, actual, expected); @@ -690,6 +749,12 @@ public void testComplexMongodbUserQuery() { compareMongoQueries(mongoDbUtils, actual, expected); + LoggedUser systemUser = userService.getSystem().transformToLoggedUser(); + actual = evaluateQuery(String.format("user: id eq '%s' and email eq loggedUser.username", GENERIC_OBJECT_ID)).getFullMongoQuery(); + expected = QUser.user._id.eq(GENERIC_OBJECT_ID).and(QUser.user.email.eq(systemUser.getUsername())); + + compareMongoQueries(mongoDbUtils, actual, expected); + // and not comparison actual = evaluateQuery(String.format("user: id eq '%s' and email not eq 'test'", GENERIC_OBJECT_ID)).getFullMongoQuery(); expected = QUser.user._id.eq(GENERIC_OBJECT_ID).and(QUser.user.email.eq("test").not()); @@ -865,7 +930,18 @@ public void testSimpleElasticCaseQuery() { expected = String.format("stringId:%s", GENERIC_OBJECT_ID); assertEquals(expected, actual); - actual = evaluateQuery(String.format("case: id in ('%s', '%s')", GENERIC_OBJECT_ID, GENERIC_OBJECT_ID)).getFullElasticQuery(); + LoggedUser systemUser = userService.getSystem().transformToLoggedUser(); + actual = evaluateQuery("case: id neq loggedUser.id").getFullElasticQuery(); + expected = String.format("NOT stringId:%s", systemUser.getId()); + assertEquals(expected, actual); + + actual = evaluateQuery(String.format("case: id in ('%s', '%s', loggedUser.id, loggedUser.username, loggedUser.fullname)", + GENERIC_OBJECT_ID, GENERIC_OBJECT_ID)).getFullElasticQuery(); + expected = String.format("stringId:(%s OR %s OR %s)", GENERIC_OBJECT_ID, GENERIC_OBJECT_ID, systemUser.getId()); + assertEquals(expected, actual); + + actual = evaluateQuery(String.format("case: id in ('%s', '%s', loggedUser.username, loggedUser.fullname)", + GENERIC_OBJECT_ID, GENERIC_OBJECT_ID)).getFullElasticQuery(); expected = String.format("stringId:(%s OR %s)", GENERIC_OBJECT_ID, GENERIC_OBJECT_ID); assertEquals(expected, actual); @@ -892,12 +968,21 @@ public void testSimpleElasticCaseQuery() { expected = "author:test"; assertEquals(expected, actual); + actual = evaluateQuery("case: author eq loggedUser.id").getFullElasticQuery(); + expected = String.format("author:%s", systemUser.getId()); + assertEquals(expected, actual); + actual = evaluateQuery("case: author contains 'test'").getFullElasticQuery(); expected = "author:*test*"; assertEquals(expected, actual); - actual = evaluateQuery(String.format("case: author in ('%s', '%s')", GENERIC_OBJECT_ID, GENERIC_OBJECT_ID)).getFullElasticQuery(); - expected = String.format("author:(%s OR %s)", GENERIC_OBJECT_ID, GENERIC_OBJECT_ID); + actual = evaluateQuery("case: author contains loggedUser.id").getFullElasticQuery(); + expected = String.format("author:*%s*", systemUser.getId()); + assertEquals(expected, actual); + + actual = evaluateQuery(String.format("case: author in ('%s', '%s', loggedUser.id)", GENERIC_OBJECT_ID, + GENERIC_OBJECT_ID)).getFullElasticQuery(); + expected = String.format("author:(%s OR %s OR %s)", GENERIC_OBJECT_ID, GENERIC_OBJECT_ID, new ObjectId(systemUser.getId())); assertEquals(expected, actual); // places comparison @@ -936,12 +1021,31 @@ public void testSimpleElasticCaseQuery() { expected = "dataSet.field1.booleanValue:true"; assertEquals(expected, actual); + actual = evaluateQuery("case: data.field1.value eq loggedUser.anonymous").getFullElasticQuery(); + expected = "dataSet.field1.booleanValue:false"; + assertEquals(expected, actual); + actual = evaluateQuery("case: data.field1.value eq false").getFullElasticQuery(); expected = "dataSet.field1.booleanValue:false"; assertEquals(expected, actual); // data options comparison checkStringComparisonElastic("case", "data.field1.options", "dataSet.field1.options"); + + actual = evaluateQuery("cases: title in ('test1' : loggedUser.username)").getFullElasticQuery(); + expected = String.format("(title:>test1 AND title:<%s)", systemUser.getUsername()); + + assertEquals(expected, actual); + + actual = evaluateQuery("cases: title in (loggedUser.username : 'test1')").getFullElasticQuery(); + expected = String.format("(title:>%s AND title:%s AND title:<%s)", systemUser.getUsername(), systemUser.getFullName()); + + assertEquals(expected, actual); } @Test @@ -1715,6 +1819,8 @@ public void testCaseQueriesFail() { assertThrows(IllegalArgumentException.class, () -> evaluateQuery("case email eq 'test'")); assertThrows(IllegalArgumentException.class, () -> evaluateQuery("case page 2")); assertThrows(IllegalArgumentException.class, () -> evaluateQuery("case:")); + assertThrows(IllegalArgumentException.class, () -> evaluateQuery("case: creationDate eq loggedUser.id")); + assertThrows(IllegalArgumentException.class, () -> evaluateQuery("case: processIdentifier eq loggedUser.anonymous")); } @Test