This commit is contained in:
Alexander Chevelev 2011-04-14 13:22:26 +00:00
parent f09a6091a8
commit 0a668b03d0
63 changed files with 12817 additions and 6919 deletions

View File

@ -29,14 +29,14 @@ public class QueryTransformerRegexTest extends TestCase
transformer = new QueryTransformerRegex(
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.group = ?1 " +
"group by c.level order by c.level having c.level > 0",
"group by c.level having c.level > 0 order by c.level",
"sec$GroupHierarchy");
transformer.addWhere("a.createdBy = :par1");
res = transformer.getResult();
assertEquals(
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.group = ?1 " +
"and h.createdBy = :par1 group by c.level order by c.level having c.level > 0",
"and h.createdBy = :par1 group by c.level having c.level > 0 order by c.level",
res);
Set<String> set = transformer.getAddedParams();
assertEquals(1, set.size());
@ -46,7 +46,7 @@ public class QueryTransformerRegexTest extends TestCase
res = transformer.getResult();
assertEquals(
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.group = ?1 " +
"and h.createdBy = :par1 and (h.updatedBy = :par2 and h.groupId = :par3) group by c.level order by c.level having c.level > 0",
"and h.createdBy = :par1 and (h.updatedBy = :par2 and h.groupId = :par3) group by c.level having c.level > 0 order by c.level",
res);
set = transformer.getAddedParams();
assertEquals(3, set.size());
@ -57,7 +57,7 @@ public class QueryTransformerRegexTest extends TestCase
res = transformer.getResult();
assertEquals(
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.group = ?1 " +
"and h.version between 1 and 2 group by c.level order by c.level having c.level > 0",
"and h.version between 1 and 2 group by c.level having c.level > 0 order by c.level",
res);
}
@ -67,21 +67,8 @@ public class QueryTransformerRegexTest extends TestCase
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.group = :par",
"sec$GroupHierarchy");
transformer.addWhere("{E}.createdBy = :par1 and a.updatedBy = :par2");
String res = transformer.getResult();
assertEquals(
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.group = :par and h.createdBy = :par1" +
" and h.updatedBy = :par2",
res);
////////////////////////////////////
transformer = new QueryTransformerRegex(
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.group = :par",
"sec$GroupHierarchy");
transformer.addWhere("{E}.createdBy = :par1 and {E}.updatedBy = :par2");
res = transformer.getResult();
String res = transformer.getResult();
assertEquals(
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.group = :par and h.createdBy = :par1" +
" and h.updatedBy = :par2",
@ -118,7 +105,7 @@ public class QueryTransformerRegexTest extends TestCase
public void testInvalidEntity() {
QueryTransformerRegex transformer = new QueryTransformerRegex(
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.group = ?1 " +
"group by c.level order by c.level having c.level > 0",
"group by c.level having c.level > 0 order by c.level",
"sec$Group");
try {
transformer.addWhere("a.createdBy = :par1");
@ -144,13 +131,13 @@ public class QueryTransformerRegexTest extends TestCase
public void testReplaceWithCount() {
QueryTransformerRegex transformer = new QueryTransformerRegex(
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.group = ?1 " +
"group by c.level order by c.level having c.level > 0",
"group by c.level having c.level > 0 order by c.level",
"sec$GroupHierarchy");
transformer.replaceWithCount();
String res = transformer.getResult();
assertEquals(
"select count(h) from sec$GroupHierarchy h join h.parent.constraints c where h.group = ?1 " +
"group by c.level order by c.level having c.level > 0",
"group by c.level having c.level > 0",
res);
}

View File

@ -10,13 +10,30 @@
*/
package com.haulmont.cuba.core.global;
import com.haulmont.cuba.core.sys.jpql.DomainModel;
import com.haulmont.cuba.core.sys.jpql.DomainModelBuilder;
import com.haulmont.cuba.core.sys.jpql.transform.QueryTransformerAstBased;
import org.antlr.runtime.RecognitionException;
/**
* Factory to get {@link QueryParser} and {@link QueryTransformer} instances
*/
public class QueryTransformerFactory
{
public class QueryTransformerFactory {
private static boolean useAst = false;
public static QueryTransformer createTransformer(String query, String targetEntity) {
return new QueryTransformerRegex(query, targetEntity);
if (useAst) {
try {
DomainModelBuilder builder = new DomainModelBuilder();
DomainModel domainModel = builder.produce(MetadataHelper.getAllPersistentMetaClasses());
//todo кэшировать метамодель - слишком долго строить каждый раз
return new QueryTransformerAstBased(domainModel, query, targetEntity);
} catch (RecognitionException e) {
throw new RuntimeException(e);
}
} else {
return new QueryTransformerRegex(query, targetEntity);
}
}
public static QueryParser createParser(String query) {

View File

@ -290,7 +290,7 @@ public class QueryTransformerRegex extends QueryParserRegex implements QueryTran
}
public String getResult() {
return buffer.toString();
return buffer.toString().trim();
}
public Set<String> getAddedParams() {

View File

@ -13,6 +13,12 @@ import java.util.List;
public class DomainModel {
private List<Entity> entities = new ArrayList<Entity>();
public DomainModel(Entity... initialEntities) {
for (Entity initialEntity : initialEntities) {
add(initialEntity);
}
}
public void add(Entity entity) {
if (entity == null)
throw new NullPointerException("No entity passed");

View File

@ -25,7 +25,7 @@ public class DomainModelBuilder {
DomainModel result = new DomainModel();
EntityBuilder builder = new EntityBuilder();
for (MetaClass aClass : classes) {
builder.startNewEntity(aClass);
builder.startNewEntity(aClass.getName());
Collection<MetaProperty> props = aClass.getProperties();
for (MetaProperty prop : props) {

View File

@ -13,6 +13,14 @@ public class EntityPath {
public String[] traversedFields;
public String lastEntityFieldPattern;
public Pointer walk(DomainModel model, QueryVariableContext queryVC) {
Pointer pointer = EntityPointer.create(queryVC, topEntityVariableName);
for (String traversedField : traversedFields) {
pointer = pointer.next(model, traversedField);
}
return pointer;
}
public static EntityPath parseEntityPath(String lastWord) {
String[] parts = lastWord.split("\\.");
EntityPath result = new EntityPath();
@ -32,12 +40,4 @@ public class EntityPath {
}
return result;
}
public Pointer walk(DomainModel model, QueryVariableContext queryVC) {
Pointer pointer = EntityPointer.create(queryVC, topEntityVariableName);
for (String traversedField : traversedFields) {
pointer = pointer.next(model, traversedField);
}
return pointer;
}
}

View File

@ -15,4 +15,9 @@ public class ErrorRec {
this.node = node;
this.message = message;
}
@Override
public String toString() {
return message + "[" + node.toString() + "]";
}
}

View File

@ -0,0 +1,34 @@
package com.haulmont.cuba.core.sys.jpql;
import java.util.ArrayList;
import java.util.List;
/**
* Author: Alexander Chevelev
* Date: 01.04.2011
* Time: 18:36:09
*/
public class ErrorsFoundException extends RuntimeException{
private List<ErrorRec> errorRecs;
public ErrorsFoundException() {
}
public ErrorsFoundException(String message, List<ErrorRec> errorRecs) {
super(message);
this.errorRecs = new ArrayList<ErrorRec>(errorRecs);
}
public List<ErrorRec> getErrorRecs() {
return errorRecs;
}
@Override
public String toString() {
String result = "";
for (ErrorRec rec : errorRecs) {
result += rec + "\n";
}
return result;
}
}

View File

@ -0,0 +1,105 @@
package com.haulmont.cuba.core.sys.jpql;
import com.haulmont.cuba.core.sys.jpql.tree.BaseJoinNode;
import com.haulmont.cuba.core.sys.jpql.tree.IdentificationVariableNode;
import com.haulmont.cuba.core.sys.jpql.tree.QueryNode;
import com.haulmont.cuba.core.sys.jpql.tree.SimpleConditionNode;
import org.antlr.runtime.tree.CommonErrorNode;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.TreeVisitorAction;
import java.util.*;
/**
* User: Alex Chevelev
* Date: 15.10.2010
* Time: 23:10:59
*/
public class IdVarSelector implements TreeVisitorAction {
private QueryVariableContext root;
private List<ErrorRec> invalidIdVarNodes = new ArrayList<ErrorRec>();
private List<CommonErrorNode> errorNodes = new ArrayList<CommonErrorNode>();
private DomainModel model;
private Deque<QueryVariableContext> stack = new ArrayDeque<QueryVariableContext>();
public IdVarSelector(DomainModel model) {
this.model = model;
}
public QueryVariableContext getContextTree() {
return root;
}
public Object pre(Object t) {
if (!(t instanceof CommonTree))
return t;
if (t instanceof CommonErrorNode) {
errorNodes.add((CommonErrorNode) t);
return t;
}
CommonTree node = (CommonTree) t;
if (node instanceof QueryNode) {
QueryVariableContext newCurrent = new QueryVariableContext(model, (QueryNode) node);
if (root == null) {
root = newCurrent;
}
QueryVariableContext last = stack.peekLast();
if (last != null) {
last.addChild(newCurrent);
}
stack.addLast(newCurrent);
}
return t;
}
public Object post(Object t) {
if (!(t instanceof CommonTree))
return t;
if (t instanceof CommonErrorNode) {
return t;
}
CommonTree node = (CommonTree) t;
if (node.token == null)
return t;
if ((node instanceof QueryNode) && isInWhereSubquery(node)) {
stack.peekLast().setPropagateVariablesUp(false);
return t;
}
if (node instanceof IdentificationVariableNode) {
IdentificationVariableNode vnode = (IdentificationVariableNode) node;
vnode.identifyVariableEntity(model, stack, invalidIdVarNodes);
return t;
}
if (node instanceof BaseJoinNode) {
BaseJoinNode vnode = (BaseJoinNode) node;
vnode.identifyVariableEntity(model, stack, invalidIdVarNodes);
return t;
}
return t;
}
private boolean isInWhereSubquery(CommonTree node) {
return node.getParent() != null && node.getParent() instanceof SimpleConditionNode;
}
public List<ErrorRec> getInvalidIdVarNodes() {
return Collections.unmodifiableList(invalidIdVarNodes);
}
public List<CommonErrorNode> getErrorNodes() {
return Collections.unmodifiableList(errorNodes);
}
}

View File

@ -0,0 +1,33 @@
package com.haulmont.cuba.core.sys.jpql;
import com.haulmont.cuba.core.sys.jpql.model.Attribute;
/**
* Author: Alexander Chevelev
* Date: 05.04.2011
* Time: 3:09:53
*/
public enum InferredType {
Collection {
public boolean matches(Attribute attribute) {
return attribute.isCollection() && attribute.isEntityReferenceAttribute();
}
},
Entity {
public boolean matches(Attribute attribute) {
return !attribute.isCollection() && attribute.isEntityReferenceAttribute();
}
},
Date {
public boolean matches(Attribute attribute) {
return java.util.Date.class.isAssignableFrom(attribute.getSimpleType());
}
},
Any {
public boolean matches(Attribute attribute) {
return true;
}
};
public abstract boolean matches(Attribute attribute);
}

View File

@ -19,16 +19,31 @@ import org.antlr.runtime.TokenStream;
import org.antlr.runtime.tree.CommonTree;
public class Parser {
public static CommonTree parse(String input) throws RecognitionException {
JPAParser parser = createParser(input);
JPAParser.ql_statement_return aReturn = parser.ql_statement();
return (CommonTree) aReturn.getTree();
}
public static CommonTree parseWhereClause(String input) throws RecognitionException {
JPAParser parser = createParser(input);
JPAParser.where_clause_return aReturn = parser.where_clause();
return (CommonTree) aReturn.getTree();
}
public static CommonTree parseJoinClause(String join) throws RecognitionException {
JPAParser parser = createParser(join);
JPAParser.join_return aReturn = parser.join();
return (CommonTree) aReturn.getTree();
}
private static JPAParser createParser(String input) {
if (input.contains("~"))
throw new IllegalArgumentException("Input string cannot contain \"~\"");
CharStream cs = new AntlrNoCaseStringStream(input);
JPALexer lexer = new JPALexer(cs);
TokenStream tstream = new CommonTokenStream(lexer);
JPAParser parser = new JPAParser(tstream);
JPAParser.ql_statement_return aReturn = parser.ql_statement();
return (CommonTree) aReturn.getTree();
return new JPAParser(tstream);
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
*/
package com.haulmont.cuba.core.sys.jpql;
/**
* Author: Alexander Chevelev
* Date: 29.03.2011
* Time: 1:06:23
*/
public class QueryBuilder {
private StringBuilder sb = new StringBuilder();
public void appendSpace() {
if (sb.length() != 0 && sb.charAt(sb.length() - 1) != ' ')
sb.append(' ');
}
public void appendChar(char c) {
if (sb.length() != 0 && getLast() == ' ' && (c == ' ' || c == ')' || c == ',')) {
deleteLast();
}
sb.append(c);
}
public void appendString(String s) {
if (sb.length() != 0 && getLast() == ' ' && (s.charAt(0) == ' ' || s.charAt(0) == ')' || s.charAt(0) == ',')) {
deleteLast();
}
sb.append(s);
}
public char getLast() {
return sb.charAt(sb.length() - 1);
}
public void deleteLast() {
sb.deleteCharAt(sb.length() - 1);
}
@Override
public String toString() {
return sb.toString();
}
}

View File

@ -0,0 +1,87 @@
package com.haulmont.cuba.core.sys.jpql;
import com.haulmont.cuba.core.sys.jpql.antlr.JPALexer;
import com.haulmont.cuba.core.sys.jpql.model.Entity;
import com.haulmont.cuba.core.sys.jpql.pointer.EntityPointer;
import com.haulmont.cuba.core.sys.jpql.pointer.Pointer;
import com.haulmont.cuba.core.sys.jpql.tree.PathNode;
import com.haulmont.cuba.core.sys.jpql.tree.SelectedItemNode;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.tree.CommonErrorNode;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;
import org.antlr.runtime.tree.TreeVisitor;
import java.util.List;
/**
* Author: Alexander Chevelev
* Date: 06.04.2011
* Time: 18:31:25
*/
public class QueryTreeAnalyzer {
private DomainModel model;
private IdVarSelector idVarSelector;
protected CommonTree tree;
public void prepare(DomainModel model, String query) throws RecognitionException {
this.model = model;
query = query.replace("\n", " ");
query = query.replace("\r", " ");
query = query.replace("\t", " ");
tree = Parser.parse(query);
TreeVisitor visitor = new TreeVisitor();
idVarSelector = new IdVarSelector(model);
visitor.visit(tree, idVarSelector);
}
public QueryVariableContext getRootQueryVariableContext() {
return idVarSelector.getContextTree();
}
public List<ErrorRec> getInvalidIdVarNodes() {
return idVarSelector.getInvalidIdVarNodes();
}
public List<CommonErrorNode> getErrorNodes() {
return idVarSelector.getErrorNodes();
}
public CommonTree getTree() {
return tree;
}
public String getRootEntityVariableName(String entityName) {
QueryVariableContext ctx = getRootQueryVariableContext();
return ctx.getVariableNameByEntity(entityName);
}
public PathNode getSelectedPathNode() {
Tree selectedItems = tree.getFirstChildWithType(JPALexer.T_SELECTED_ITEMS);
boolean isDistinct = "DISTINCT".equalsIgnoreCase(selectedItems.getChild(0).getText());
SelectedItemNode selectedItemNode;
if (isDistinct) {
if (selectedItems.getChildCount() != 2)
throw new IllegalStateException("Cannot select path node if multiple fields selected");
selectedItemNode = (SelectedItemNode) selectedItems.getChild(1);
} else {
if (selectedItems.getChildCount() != 1)
throw new IllegalStateException("Cannot select path node if multiple fields selected");
selectedItemNode = (SelectedItemNode) selectedItems.getChild(0);
}
if (!(selectedItemNode.getChild(0) instanceof PathNode)) {
throw new IllegalStateException("An entity path is assumed to be selected");
}
return (PathNode) selectedItemNode.getChild(0);
}
public Entity getSelectedEntity(PathNode path) {
Pointer pointer = path.walk(model, getRootQueryVariableContext());
if (!(pointer instanceof EntityPointer)) {
throw new IllegalStateException("A path resulting in an entity is assumed to be selected");
}
return ((EntityPointer)pointer).getEntity();
}
}

View File

@ -37,7 +37,7 @@ public class QueryVariableContext {
return propagateVariablesUpstairs;
}
public void setPropateVariablesUp(boolean propateVariablesUpdatairs) {
public void setPropagateVariablesUp(boolean propateVariablesUpdatairs) {
this.propagateVariablesUpstairs = propateVariablesUpdatairs;
}
@ -63,6 +63,9 @@ public class QueryVariableContext {
if (entity == null) {
throw new NullPointerException("No entity passed");
}
if (entityVariableName2entity.containsKey(variableName))
throw new IllegalArgumentException("Trying to rebing variable [" + variableName + "]");
entityVariableName2entity.put(variableName, entity);
}
@ -106,4 +109,17 @@ public class QueryVariableContext {
private void setParent(QueryVariableContext parent) {
this.parent = parent;
}
public String getVariableNameByEntity(String entityName) {
if (entityName == null)
throw new NullPointerException("No entity name passed");
for (Map.Entry<String, Entity> entry : entityVariableName2entity.entrySet()) {
if (entityName.equals(entry.getValue().getName())) {
return entry.getKey();
}
}
return parent == null ? null : parent.getVariableNameByEntity(entityName);
}
}

View File

@ -0,0 +1,111 @@
/*
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
*/
package com.haulmont.cuba.core.sys.jpql;
import com.haulmont.cuba.core.sys.jpql.antlr.JPALexer;
import com.haulmont.cuba.core.sys.jpql.tree.TreeToQueryCapable;
import org.antlr.runtime.tree.CommonErrorNode;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.TreeVisitorAction;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Author: Alexander Chevelev
* Date: 26.03.2011
* Time: 3:09:04
*/
public class TreeToQuery implements TreeVisitorAction {
private QueryBuilder sb = new QueryBuilder();
private List<ErrorRec> invalidNodes = new ArrayList<ErrorRec>();
public Object pre(Object t) {
if (!(t instanceof CommonTree)) {
return t;
}
if (t instanceof CommonErrorNode) {
invalidNodes.add(new ErrorRec((CommonErrorNode) t, "Error node"));
return t;
}
CommonTree node = (CommonTree) t;
if (node.token == null)
return t;
if (node.getType() == JPALexer.HAVING ||
node.parent != null && node.parent.getType() == JPALexer.T_SIMPLE_CONDITION ||
node.parent != null && node.parent.getType() == JPALexer.T_GROUP_BY ||
node.parent != null && node.parent.getType() == JPALexer.T_ORDER_BY && node.getType() != JPALexer.T_ORDER_BY_FIELD ||
node.parent != null && node.parent.getType() == JPALexer.T_CONDITION && node.getType() == JPALexer.LPAREN && node.childIndex - 1 >= 0 && node.parent.getChild(node.childIndex - 1).getType() != JPALexer.LPAREN ||
node.getType() == JPALexer.AND ||
node.parent != null && node.parent.getType() == JPALexer.T_ORDER_BY_FIELD ||
node.getType() == JPALexer.OR ||
node.getType() == JPALexer.DISTINCT && node.childIndex == 0 ||
node.getType() == JPALexer.JOIN ||
node.getType() == JPALexer.FETCH
) {
sb.appendSpace();
}
if (node.getType() == JPALexer.T_ORDER_BY_FIELD && node.childIndex - 1 >= 0 && node.parent.getChild(node.childIndex - 1).getType() == JPALexer.T_ORDER_BY_FIELD) {
sb.appendString(", ");
}
if (node instanceof TreeToQueryCapable) {
return ((TreeToQueryCapable) t).treeToQueryPre(sb, invalidNodes);
}
if (node.getType() == JPALexer.T_SELECTED_ITEMS) {
return t;
}
if (node.getType() == JPALexer.T_SOURCES) {
sb.appendString("FROM ");
return t;
}
sb.appendString(node.toString());
return t;
}
public Object post(Object t) {
if (!(t instanceof CommonTree))
return t;
if (t instanceof CommonErrorNode) {
return t;
}
CommonTree node = (CommonTree) t;
if (node.token == null)
return t;
if (node.getType() == JPALexer.DISTINCT || node.getType() == JPALexer.FETCH)
sb.appendSpace();
if (node instanceof TreeToQueryCapable) {
return ((TreeToQueryCapable) t).treeToQueryPost(sb, invalidNodes);
}
return t;
}
public List<ErrorRec> getInvalidNodes() {
return Collections.unmodifiableList(invalidNodes);
}
public String getQueryString() {
return sb.toString();
}
}

View File

@ -1,43 +1,45 @@
T_JOIN_VAR=9
T__29=29
T__28=28
T__27=27
T__26=26
T__25=25
T__24=24
T__23=23
T__22=22
T_JOIN_VAR=11
T_AGGREGATE_EXPR=20
COUNT=28
T_ORDER_BY=18
WORD=40
T__93=93
WORD=15
T__94=94
RPAREN=32
T__91=91
T__92=92
T__90=90
SIMPLE_FIELD_PATH=17
TRIM_CHARACTER=14
COMMENT=20
TRIM_CHARACTER=39
T_SELECTED_ITEM=5
COMMENT=43
T__99=99
T__98=98
T__97=97
T__96=96
T_QUERY=10
T_QUERY=13
T__95=95
T__80=80
T__81=81
T__82=82
ASC=22
T__83=83
LINE_COMMENT=21
LINE_COMMENT=44
T__85=85
T__84=84
T__87=87
T__86=86
T__89=89
T__88=88
FIELD_PATH=18
WS=19
WS=42
T__71=71
T__72=72
FETCH=35
T__70=70
T_SELECTED_FIELD=6
T_SELECTED_FIELD=8
OR=29
T__76=76
T__75=75
DISTINCT=33
T__74=74
T__73=73
T__79=79
@ -52,9 +54,18 @@ T__64=64
T__65=65
T__62=62
T__63=63
T_ID_VAR=8
T_SOURCE=7
T__116=116
T_ID_VAR=10
T_SIMPLE_CONDITION=15
T__114=114
T__115=115
MAX=25
AND=30
SUM=27
T__61=61
T__60=60
LPAREN=31
T__55=55
T__56=56
T__57=57
@ -63,106 +74,127 @@ T__51=51
T__52=52
T__53=53
T__54=54
T__107=107
T__108=108
T__109=109
AVG=24
T_ORDER_BY_FIELD=19
T__59=59
T__103=103
T__104=104
T__105=105
T__106=106
T__111=111
T__110=110
T__113=113
T__112=112
T__50=50
T__42=42
T__43=43
T__40=40
T__41=41
T_GROUP_BY=17
T__46=46
T__47=47
T__44=44
T_CONDITION=11
T_CONDITION=14
T__45=45
T_SELECTED_ENTITY=7
T_SELECTED_ENTITY=9
T__48=48
T__49=49
T__30=30
T__31=31
T__32=32
T__33=33
ESCAPE_CHARACTER=12
T__34=34
T__35=35
T__36=36
T__37=37
INT_NUMERAL=16
T__38=38
T__39=39
STRINGLITERAL=13
T_SOURCES=5
'>='=68
'/'=74
'>'=67
'MIN'=40
'SUBSTRING'=85
'CONCAT'=84
'FETCH'=28
'NEW'=37
'<>'=66
'+'=71
'LEFT'=29
'MEMBER'=59
'NULL'=57
'LENGTH'=75
'EMPTY'=58
'true'=95
'JOIN'=32
'SIZE'=80
'OR'=50
'AVG'=38
'?'=93
'UPPER'=88
':'=94
'SQRT'=78
'('=34
'-'=72
'HAVING'=46
'ASC'=48
'ABS'=77
','=24
'SOME'=64
'BY'=45
'EXISTS'=61
'BOTH'=91
'OBJECT'=36
'0x'=92
'SELECT'=22
'NOT'=52
'ESCAPE'=55
'LOWER'=87
'ANY'=63
'COUNT'=42
'FROM'=23
'LIKE'=54
'CURRENT_TIMESTAMP'=83
'OUTER'=30
'IS'=56
'LOCATE'=76
'='=65
'DESC'=49
'SUM'=41
')'=27
'INNER'=31
'MAX'=39
'AND'=51
'ORDER'=47
'TRAILING'=90
'LEADING'=89
'CURRENT_DATE'=81
'IN'=33
'BETWEEN'=53
'CURRENT_TIME'=82
'AS'=25
'<='=70
'false'=96
'(SELECT'=26
'<'=69
'MOD'=79
'*'=73
'WHERE'=43
'TRIM'=86
'OF'=60
'ALL'=62
'DISTINCT'=35
'GROUP'=44
HAVING=21
T__102=102
T__101=101
MIN=26
T__100=100
T_PARAMETER=16
JOIN=34
NAMED_PARAMETER=41
ESCAPE_CHARACTER=37
INT_NUMERAL=36
STRINGLITERAL=38
T_COLLECTION_MEMBER=12
DESC=23
T_SOURCES=6
'>='=91
'/'=95
'>'=90
'MIN'=26
'SUBSTRING'=106
'CONCAT'=105
'FETCH'=35
'NEW'=56
'<>'=89
'+'=64
'MEMBER'=82
'LEFT'=50
'DAY'=68
'NULL'=80
'.'=53
'LENGTH'=96
'EMPTY'=81
'true'=115
'JOIN'=34
'SIZE'=101
'OR'=29
'@DATEAFTER'=73
'AVG'=24
'?'=114
'@DATEBEFORE'=72
'UPPER'=109
'SQRT'=99
'('=31
'HAVING'=21
'-'=65
'ASC'=22
'ABS'=98
'SOME'=87
','=47
'EXISTS'=84
'BY'=59
'BOTH'=112
'OBJECT'=55
'0x'=113
'SELECT'=45
'NOT'=61
'ESCAPE'=78
'LOWER'=108
'ANY'=86
'COUNT'=28
'FROM'=46
'LIKE'=77
'CURRENT_TIMESTAMP'=104
'OUTER'=51
'IS'=79
'LOCATE'=97
'='=88
'MONTH'=67
'DESC'=23
'@BETWEEN'=62
'SUM'=27
')'=32
'HOUR'=69
'INNER'=52
'MAX'=25
'AND'=30
'YEAR'=66
'ORDER'=60
'TRAILING'=111
'LEADING'=110
'CURRENT_DATE'=102
'@TODAY'=75
'IN'=54
'NOW'=63
'BETWEEN'=76
'CURRENT_TIME'=103
'AS'=48
'SECOND'=71
'<='=93
'false'=116
'(SELECT'=49
'<'=92
'MOD'=100
'*'=94
'WHERE'=57
'@DATEEQUALS'=74
'TRIM'=107
'ALL'=85
'OF'=83
'DISTINCT'=33
'MINUTE'=70
'GROUP'=58

View File

@ -1,6 +1,9 @@
package com.haulmont.cuba.core.sys.jpql.model;
import com.haulmont.cuba.core.sys.jpql.InferredType;
import java.util.List;
import java.util.Set;
/**
* Author: Alexander Chevelev
@ -13,18 +16,12 @@ public interface Entity {
String getUserFriendlyName();
void addSingleValueAttribute(Class aClass, String name);
Attribute getAttributeByName(String attributeName);
List<Attribute> findAttributesStartingWith(String fieldNamePattern);
void addReferenceAttribute(String referencedEntityName, String name);
List<Attribute> findAttributesStartingWith(String fieldNamePattern, Set<InferredType> expectedTypes);
void addAttributeCopy(Attribute attribute);
void addCollectionReferenceAttribute(String referencedEntityName, String name);
void addSingleValueAttribute(Class aClass, String name, String userFriendlyName);
void addReferenceAttribute(String referencedEntityName, String name, String userFriendlyName);

View File

@ -11,23 +11,27 @@ import com.haulmont.cuba.core.global.MessageUtils;
public class EntityBuilder {
private EntityImpl result;
// public EntityImpl produce(String entityName) {
// return new EntityImpl(entityName);
// }
//
// public Entity produce(String entityName, String... stringAttributeNames) {
// EntityImpl result = new EntityImpl(entityName);
// for (String stringAttributeName : stringAttributeNames) {
// result.addSingleValueAttribute(String.class, stringAttributeName);
// }
// return result;
// }
public EntityImpl produceImmediately(String entityName) {
return new EntityImpl(entityName);
}
public void startNewEntity(MetaClass metaClass) {
result = new EntityImpl(metaClass.getName());
result.setUserFriendlyName(MessageUtils.getEntityCaption(metaClass));
}
public Entity produceImmediately(String entityName, String... stringAttributeNames) {
EntityImpl result = new EntityImpl(entityName);
for (String stringAttributeName : stringAttributeNames) {
result.addSingleValueAttribute(String.class, stringAttributeName);
}
return result;
}
public void startNewEntity(String name) {
result = new EntityImpl(name);
}
public void addStringAttribute(String name) {
addSingleValueAttribute(String.class, name);
}

View File

@ -1,9 +1,8 @@
package com.haulmont.cuba.core.sys.jpql.model;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.haulmont.cuba.core.sys.jpql.InferredType;
import java.util.*;
/**
* User: Alex Chevelev
@ -55,11 +54,18 @@ public class EntityImpl implements Entity {
return name2attribute.get(attributeName);
}
public List<Attribute> findAttributesStartingWith(String fieldNamePattern) {
public List<Attribute> findAttributesStartingWith(String fieldNamePattern, Set<InferredType> expectedTypes) {
List<Attribute> result = new ArrayList<Attribute>();
for (Map.Entry<String, AttributeImpl> entry : name2attribute.entrySet()) {
if (entry.getKey().startsWith(fieldNamePattern))
result.add(entry.getValue());
if (entry.getKey().startsWith(fieldNamePattern)) {
for (InferredType expectedType : expectedTypes) {
AttributeImpl attribute = entry.getValue();
if (expectedType.matches(attribute)) {
result.add(attribute);
break;
}
}
}
}
return result;
}

View File

@ -1,6 +1,9 @@
package com.haulmont.cuba.core.sys.jpql.model;
import com.haulmont.cuba.core.sys.jpql.InferredType;
import java.util.List;
import java.util.Set;
/**
* Author: Alexander Chevelev
@ -21,20 +24,14 @@ public class NoEntity implements Entity{
return null;
}
public void addSingleValueAttribute(Class aClass, String name) {
}
public Attribute getAttributeByName(String attributeName) {
return null;
}
public List<Attribute> findAttributesStartingWith(String fieldNamePattern) {
public List<Attribute> findAttributesStartingWith(String fieldNamePattern, Set<InferredType> expectedTypes) {
return null;
}
public void addReferenceAttribute(String referencedEntityName, String name) {
}
public void addAttributeCopy(Attribute attribute) {
}
@ -42,9 +39,6 @@ public class NoEntity implements Entity{
return instance;
}
public void addCollectionReferenceAttribute(String referencedEntityName, String name) {
}
public void addSingleValueAttribute(Class aClass, String name, String userFriendlyName) {
}

View File

@ -8,7 +8,7 @@ import com.haulmont.cuba.core.sys.jpql.model.Entity;
* Date: 01.11.2010
* Time: 0:27:12
*/
public class CollectionPointer implements Pointer {
public class CollectionPointer implements com.haulmont.cuba.core.sys.jpql.pointer.Pointer {
private Entity entity;
public CollectionPointer(Entity entity) {

View File

@ -10,7 +10,6 @@ import com.haulmont.cuba.core.sys.jpql.DomainModel;
public class NoPointer implements Pointer {
private static final NoPointer instance = new NoPointer();
//todo
private NoPointer() {
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
*/
package com.haulmont.cuba.core.sys.jpql.transform;
import com.haulmont.cuba.core.sys.jpql.tree.IdentificationVariableNode;
import com.haulmont.cuba.core.sys.jpql.tree.PathNode;
import org.antlr.runtime.tree.Tree;
/**
* Author: Alexander Chevelev
* Date: 13.04.2011
* Time: 17:59:30
*/
public class EntityNameEntityReference implements EntityReference {
private String entityName;
public EntityNameEntityReference(String entityName) {
this.entityName = entityName;
}
public String replaceEntries(String queryPart, String replaceablePart) {
throw new UnsupportedOperationException();
}
public void renameVariableIn(PathNode node) {
throw new UnsupportedOperationException();
}
public Tree createNode() {
throw new UnsupportedOperationException();
}
public boolean isJoinableTo(IdentificationVariableNode node) {
return entityName.equals(node.getEntityName());
}
}

View File

@ -0,0 +1,20 @@
package com.haulmont.cuba.core.sys.jpql.transform;
import com.haulmont.cuba.core.sys.jpql.tree.IdentificationVariableNode;
import com.haulmont.cuba.core.sys.jpql.tree.PathNode;
import org.antlr.runtime.tree.Tree;
/**
* Author: Alexander Chevelev
* Date: 06.04.2011
* Time: 16:43:37
*/
public interface EntityReference {
String replaceEntries(String queryPart, String replaceablePart);
void renameVariableIn(PathNode node);
Tree createNode();
boolean isJoinableTo(IdentificationVariableNode node);
}

View File

@ -0,0 +1,41 @@
package com.haulmont.cuba.core.sys.jpql.transform;
import com.haulmont.cuba.core.sys.jpql.model.Entity;
import com.haulmont.cuba.core.sys.jpql.model.VirtualEntity;
import com.haulmont.cuba.core.sys.jpql.tree.PathNode;
/**
* Author: Alexander Chevelev
* Date: 06.04.2011
* Time: 16:32:06
*/
public class EntityReferenceInferer {
private String entityName;
public EntityReferenceInferer(String entityName) {
if (entityName == null)
throw new NullPointerException("No entity name passed");
this.entityName = entityName;
}
public EntityReference infer(QueryTreeTransformer queryAnalyzer) {
String entityVariableNameInQuery = queryAnalyzer.getRootEntityVariableName(entityName);
if (entityVariableNameInQuery != null) {
return new VariableEntityReference(entityName, entityVariableNameInQuery);
}
PathNode path = queryAnalyzer.getSelectedPathNode();
Entity entity = queryAnalyzer.getSelectedEntity(path);
if (!(entity instanceof VirtualEntity) && entity.getName().equals(entityName)) {
Entity pathStartingEntity = queryAnalyzer.getRootQueryVariableContext().
getEntityByVariableName(path.getEntityVariableName());
return new PathEntityReference(entityName, path, pathStartingEntity);
}
throw new RuntimeException("No variable or selected field of entity " + entityName + " found in query");
}
public String getEntityName() {
return entityName;
}
}

View File

@ -0,0 +1,46 @@
package com.haulmont.cuba.core.sys.jpql.transform;
import com.haulmont.cuba.core.sys.jpql.tree.ParameterNode;
import org.antlr.runtime.tree.TreeVisitorAction;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* Author: Alexander Chevelev
* Date: 27.03.2011
* Time: 21:19:38
*/
public class ParameterCounter implements TreeVisitorAction {
private boolean differentNamesOnly;
private int totalParameterCount = 0;
private Set<String> names = new HashSet<String>();
public ParameterCounter(boolean differentNamesOnly) {
this.differentNamesOnly = differentNamesOnly;
}
public Object pre(Object o) {
if (o instanceof ParameterNode) {
ParameterNode node = (ParameterNode) o;
if (node.isNamed()) {
names.add(node.getParameterReference());
}
totalParameterCount++;
}
return o;
}
public Object post(Object o) {
return o;
}
public int getParameterCount() {
return differentNamesOnly ? names.size() : totalParameterCount;
}
public Set<String> getParameterNames() {
return Collections.unmodifiableSet(names);
}
}

View File

@ -0,0 +1,48 @@
package com.haulmont.cuba.core.sys.jpql.transform;
import com.haulmont.cuba.core.sys.jpql.model.Entity;
import com.haulmont.cuba.core.sys.jpql.tree.IdentificationVariableNode;
import com.haulmont.cuba.core.sys.jpql.tree.PathNode;
import org.antlr.runtime.tree.Tree;
import java.util.ArrayList;
import java.util.List;
/**
* Author: Alexander Chevelev
* Date: 06.04.2011
* Time: 17:13:12
*/
public class PathEntityReference implements EntityReference {
private PathNode pathNode;
private String entityName;
private Entity pathStartingEntity;
public PathEntityReference(String entityName, PathNode pathNode, Entity pathStartingEntity) {
this.entityName = entityName;
this.pathStartingEntity = pathStartingEntity;
this.pathNode = pathNode.dupNode();
}
public String replaceEntries(String queryPart, String replaceablePart) {
return queryPart.replaceAll("\\{E\\}", pathNode.asPathString());
}
public void renameVariableIn(PathNode node) {
node.renameVariableTo(pathNode.getEntityVariableName());
List newChildren = new ArrayList(pathNode.dupNode().getChildren());
while (node.getChildCount() > 0) {
newChildren.add(node.deleteChild(0));
}
node.addChildren(newChildren);
}
public Tree createNode() {
return pathNode.dupNode();
}
public boolean isJoinableTo(IdentificationVariableNode node) {
return pathStartingEntity.getName().equals(node.getEntityName()) &&
pathNode.getEntityVariableName().equals(node.getVariableName());
}
}

View File

@ -0,0 +1,186 @@
package com.haulmont.cuba.core.sys.jpql.transform;
import com.haulmont.cuba.core.global.QueryTransformer;
import com.haulmont.cuba.core.sys.jpql.*;
import com.haulmont.cuba.core.sys.jpql.antlr.JPALexer;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.tree.CommonErrorNode;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.TreeVisitor;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Author: Alexander Chevelev
* Date: 26.03.2011
* Time: 1:25:51
*/
public class QueryTransformerAstBased implements QueryTransformer {
private DomainModel model;
private String query;
private String entityName;
private QueryTreeTransformer queryAnalyzer;
private Set<String> addedParams = new HashSet<String>();
public QueryTransformerAstBased(DomainModel model, String query, String entityName) throws RecognitionException {
this.model = model;
this.query = query;
this.entityName = entityName;
initQueryAnalyzer(model, query);
}
private void initQueryAnalyzer(DomainModel model, String query) throws RecognitionException {
queryAnalyzer = new QueryTreeTransformer();
queryAnalyzer.prepare(model, query);
List<CommonErrorNode> errorNodes = new ArrayList<CommonErrorNode>(queryAnalyzer.getErrorNodes());
List<ErrorRec> invalidIdVarNodes = queryAnalyzer.getInvalidIdVarNodes();
for (ErrorRec invalidIdVarNode : invalidIdVarNodes) {
if (errorNodes.contains(invalidIdVarNode.node)) {
errorNodes.remove(invalidIdVarNode.node);
}
}
List<ErrorRec> errors = new ArrayList<ErrorRec>(queryAnalyzer.getInvalidIdVarNodes());
for (CommonErrorNode errorNode : errorNodes) {
ErrorRec rec = new ErrorRec(errorNode, "CommonErrorNode");
errors.add(rec);
}
if (!errors.isEmpty()) {
throw new ErrorsFoundException("Errors found", errors);
}
}
public String getResult() {
CommonTree tree = queryAnalyzer.getTree();
TreeVisitor visitor = new TreeVisitor();
TreeToQuery treeToQuery = new TreeToQuery();
visitor.visit(tree, treeToQuery);
return treeToQuery.getQueryString().trim();
}
public Set<String> getAddedParams() {
return addedParams;
}
/**
* @param where - "{E}" may be used as a replaceable entity placeholder. No such value
* should be used as a string constant
*/
public void addWhere(String where) {
EntityReferenceInferer inferrer = new EntityReferenceInferer(entityName);
EntityReference ref = inferrer.infer(queryAnalyzer);
boolean doReplaceVariableName = true;
if (where.contains("{E}")) {
doReplaceVariableName = false;
where = ref.replaceEntries(where, "\\{E\\}");
}
try {
CommonTree whereTree = Parser.parseWhereClause("where " + where);
addWhere(whereTree, ref, doReplaceVariableName);
} catch (RecognitionException e) {
throw new RuntimeException(e);
}
}
public void addWhereAsIs(String where) {
try {
CommonTree whereTree = Parser.parseWhereClause("where " + where);
addWhere(whereTree, null, false);
} catch (RecognitionException e) {
throw new RuntimeException(e);
}
}
/**
* в реальности это копирование из другого запроса
*
* @param statement выражение, из которого скопировать where часть
*/
public void mergeWhere(String statement) {
EntityReferenceInferer inferer = new EntityReferenceInferer(entityName);
EntityReference ref = inferer.infer(queryAnalyzer);
try {
CommonTree statementTree = Parser.parse(statement);
CommonTree whereClause = (CommonTree) statementTree.getFirstChildWithType(JPALexer.T_CONDITION);
addWhere(whereClause, ref, true);
} catch (RecognitionException e) {
throw new RuntimeException(e);
}
}
public void addJoinAndWhere(String join, String where) {
EntityReferenceInferer inferer = new EntityReferenceInferer(entityName);
EntityReference ref = inferer.infer(queryAnalyzer);
if (where.contains("{E}")) {
where = ref.replaceEntries(where, "\\{E\\}");
}
if (join.contains("{E}")) {
join = ref.replaceEntries(join, "\\{E\\}");
}
try {
CommonTree joinClause = Parser.parseJoinClause(join);
queryAnalyzer.mixinJoinIntoTree(joinClause, ref, true);
CommonTree whereTree = Parser.parseWhereClause("where " + where);
addWhere(whereTree, ref, false);
} catch (RecognitionException e) {
throw new RuntimeException(e);
}
}
public void addJoinAsIs(String join) {
try {
CommonTree joinClause = Parser.parseJoinClause(join);
queryAnalyzer.mixinJoinIntoTree(joinClause, new EntityNameEntityReference(entityName), false);
} catch (RecognitionException e) {
throw new RuntimeException(e);
}
}
public void replaceWithCount() {
EntityReferenceInferer inferer = new EntityReferenceInferer(entityName);
EntityReference ref = inferer.infer(queryAnalyzer);
queryAnalyzer.replaceWithCount(ref);
}
public void replaceOrderBy(String newOrderingField, boolean desc) {
queryAnalyzer.replaceOrderBy(newOrderingField, desc);
}
public void reset() {
try {
initQueryAnalyzer(model, query);
} catch (RecognitionException e) {
throw new RuntimeException(e);
}
addedParams.clear();
}
private void addWhere(CommonTree whereTree, EntityReference ref, boolean replaceVariableName) {
TreeVisitor visitor = new TreeVisitor();
VariableManipulator variableManip = new VariableManipulator();
visitor.visit(whereTree, variableManip);
if (replaceVariableName) {
Set<String> variables = variableManip.getUsedVariableNames();
if (variables.size() > 1) {
// предположение, что добавляемый where использует только одну переменную и не определяет собственных
throw new IllegalStateException("Multiple variables used in condition");
}
String assumedEntityVariableInWhere = variableManip.getVariableNameInUse(0);
variableManip.renameVariable(assumedEntityVariableInWhere, ref);
}
ParameterCounter parameterCounter = new ParameterCounter(true);
visitor.visit(whereTree, parameterCounter);
addedParams.addAll(parameterCounter.getParameterNames());
queryAnalyzer.mixinWhereConditionsIntoTree(whereTree);
}
}

View File

@ -0,0 +1,139 @@
package com.haulmont.cuba.core.sys.jpql.transform;
import com.haulmont.cuba.core.sys.jpql.QueryTreeAnalyzer;
import com.haulmont.cuba.core.sys.jpql.antlr.JPALexer;
import com.haulmont.cuba.core.sys.jpql.tree.*;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;
import java.util.ArrayList;
import java.util.List;
/**
* Author: Alexander Chevelev
* Date: 26.03.2011
* Time: 1:56:20
*/
public class QueryTreeTransformer extends QueryTreeAnalyzer {
public QueryTreeTransformer() {
}
public void mixinWhereConditionsIntoTree(CommonTree whereTreeToMixIn) {
CommonTree whereTreeToMixWithin = (CommonTree) tree.getFirstChildWithType(JPALexer.T_CONDITION);
if (whereTreeToMixWithin == null) {
FromNode fromNode = (FromNode) tree.getFirstChildWithType(JPALexer.T_SOURCES);
List<Tree> endingNodes = new ArrayList<Tree>();
int deletionCount = tree.getChildCount() - (fromNode.getChildIndex() + 1);
for (int i = 0; i < deletionCount; i++) {
endingNodes.add((Tree) tree.deleteChild(fromNode.getChildIndex() + 1));
}
tree.addChild(whereTreeToMixIn);
for (Tree endingNode : endingNodes) {
tree.addChild(endingNode);
}
tree.freshenParentAndChildIndexes();
} else {
CommonTree and = new CommonTree(new CommonToken(JPALexer.AND, "and"));
whereTreeToMixWithin.addChild(and);
for (Object o : whereTreeToMixIn.getChildren()) {
CommonTree t = (CommonTree) o;
whereTreeToMixWithin.addChild(t.dupNode());
}
whereTreeToMixIn.freshenParentAndChildIndexes();
}
}
public void mixinJoinIntoTree(CommonTree joinClause, EntityReference entityRef, boolean renameVariable) {
CommonTree from = (CommonTree) tree.getFirstChildWithType(JPALexer.T_SOURCES);
for (int i = 0; i < from.getChildCount(); i++) {
SelectionSourceNode sourceNode = (SelectionSourceNode) from.getChild(i);
if (sourceNode.getChild(0) instanceof IdentificationVariableNode) {
IdentificationVariableNode entityVariableNode = (IdentificationVariableNode) sourceNode.getChild(0);
if (entityRef.isJoinableTo(entityVariableNode)) {
String variableName = entityVariableNode.getVariableName();
JoinVariableNode joinVariableNode = (JoinVariableNode) joinClause;
if (renameVariable) {
PathNode path = joinVariableNode.getPathNode();
path.renameVariableTo(variableName);
}
sourceNode.addChild(joinClause);
from.freshenParentAndChildIndexes();
return;
}
}
}
throw new RuntimeException("Join mixing failed. Cannot find selected entity with name " + entityRef);
}
public void replaceWithCount(EntityReference entityRef) {
Tree selectedItems = tree.getFirstChildWithType(JPALexer.T_SELECTED_ITEMS);
boolean isDistinct = "DISTINCT".equalsIgnoreCase(selectedItems.getChild(0).getText());
if (!(isDistinct && selectedItems.getChildCount() == 2 ||
selectedItems.getChildCount() == 1))
throw new IllegalStateException("Cannot replace with count if multiple fields selected");
SelectedItemNode selectedItemNode;
if (isDistinct)
selectedItems.deleteChild(0);
selectedItemNode = (SelectedItemNode) selectedItems.getChild(0);
AggregateExpressionNode countNode = createCountNode(entityRef, isDistinct);
selectedItemNode.deleteChild(0);
selectedItemNode.addChild(countNode);
Tree orderBy = tree.getFirstChildWithType(JPALexer.T_ORDER_BY);
if (orderBy != null) {
tree.deleteChild(orderBy.getChildIndex());
}
tree.freshenParentAndChildIndexes();
}
public void replaceOrderBy(String newOrderingField, boolean desc) {
CommonTree orderBy = (CommonTree) tree.getFirstChildWithType(JPALexer.T_ORDER_BY);
if (orderBy == null) {
throw new IllegalStateException("No order by clause found");
}
OrderByFieldNode orderByField = (OrderByFieldNode) orderBy.getFirstChildWithType(JPALexer.T_ORDER_BY_FIELD);
if (orderByField == null)
throw new IllegalStateException("No ordering field found");
if (!(orderByField.getChildCount() == 1 || orderByField.getChildCount() == 2)) {
throw new IllegalStateException("Invalid order by field node children count: " + orderByField.getChildCount());
}
PathNode orderingField = (PathNode) orderByField.getChild(0);
orderingField.changeField(newOrderingField);
if (orderByField.getChildCount() == 2) {
orderByField.deleteChild(1);
}
String text;
int type;
if (desc) {
text = "DESC";
type = JPALexer.DESC;
CommonTree node = new CommonTree(new CommonToken(type, text));
orderByField.addChild(node);
}
orderByField.freshenParentAndChildIndexes();
}
private AggregateExpressionNode createCountNode(EntityReference ref, boolean distinct) {
AggregateExpressionNode result = new AggregateExpressionNode(JPALexer.T_AGGREGATE_EXPR);
result.addChild(new CommonTree(new CommonToken(JPALexer.COUNT, "COUNT")));
result.addChild(new CommonTree(new CommonToken(JPALexer.LPAREN, "(")));
if (distinct) {
result.addChild(new CommonTree(new CommonToken(JPALexer.DISTINCT, "DISTINCT")));
}
result.addChild(ref.createNode());
result.addChild(new CommonTree(new CommonToken(JPALexer.RPAREN, ")")));
return result;
}
}

View File

@ -0,0 +1,39 @@
package com.haulmont.cuba.core.sys.jpql.transform;
import com.haulmont.cuba.core.sys.jpql.antlr.JPALexer;
import com.haulmont.cuba.core.sys.jpql.tree.IdentificationVariableNode;
import com.haulmont.cuba.core.sys.jpql.tree.PathNode;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;
/**
* Author: Alexander Chevelev
* Date: 06.04.2011
* Time: 16:46:32
*/
public class VariableEntityReference implements EntityReference {
private String entityName;
private String entityVariableName;
public VariableEntityReference(String entityName, String entityVariableNameInQuery) {
this.entityName = entityName;
this.entityVariableName = entityVariableNameInQuery;
}
public String replaceEntries(String queryPart, String replaceablePart) {
return queryPart.replaceAll("\\{E\\}", entityVariableName);
}
public void renameVariableIn(PathNode node) {
node.renameVariableTo(entityVariableName);
}
public Tree createNode() {
return new CommonTree(new CommonToken(JPALexer.WORD, entityVariableName));
}
public boolean isJoinableTo(IdentificationVariableNode node) {
return entityName.equals(node.getEntityName());
}
}

View File

@ -0,0 +1,60 @@
package com.haulmont.cuba.core.sys.jpql.transform;
import com.haulmont.cuba.core.sys.jpql.tree.PathNode;
import org.antlr.runtime.tree.TreeVisitorAction;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Author: Alexander Chevelev
* Date: 27.03.2011
* Time: 0:36:19
*/
public class VariableManipulator implements TreeVisitorAction {
private List<PathNode> variableUses = new ArrayList<PathNode>();
public VariableManipulator() {
}
public Object pre(Object o) {
// todo небезопасен, если изменяемое дерево определяет свои собственные переменные
if (o instanceof PathNode) {
PathNode pathNode = (PathNode) o;
variableUses.add(pathNode);
}
return o;
}
public Object post(Object o) {
return o;
}
public Set<String> getUsedVariableNames() {
Set<String> result = new HashSet<String>();
for (PathNode variableUse : variableUses) {
result.add(variableUse.getEntityVariableName());
}
return result;
}
public String getVariableNameInUse(int index) {
return variableUses.get(index).getEntityVariableName();
}
public void renameVariable(String origName, EntityReference newName) {
if (origName == null)
throw new NullPointerException("No original name passed");
if (newName == null)
throw new NullPointerException("No new name passed");
for (PathNode variableUse : variableUses) {
if (origName.equals(variableUse.getEntityVariableName())) {
newName.renameVariableIn(variableUse);
}
}
}
}

View File

@ -0,0 +1,32 @@
package com.haulmont.cuba.core.sys.jpql.tree;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.Tree;
/**
* Author: Alexander Chevelev
* Date: 30.10.2010
* Time: 4:15:07
*/
public class AggregateExpressionNode extends BaseCustomNode {
private AggregateExpressionNode(Token token) {
super(token);
}
public AggregateExpressionNode(int type) {
this(new CommonToken(type, ""));
}
@Override
public String toString() {
return "AGGREGATE EXPR";
}
@Override
public Tree dupNode() {
AggregateExpressionNode result = new AggregateExpressionNode(token);
dupChildren(result);
return result;
}
}

View File

@ -0,0 +1,48 @@
package com.haulmont.cuba.core.sys.jpql.tree;
import com.haulmont.cuba.core.sys.jpql.ErrorRec;
import com.haulmont.cuba.core.sys.jpql.QueryBuilder;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;
import java.util.List;
/**
* Author: Alexander Chevelev
* Date: 26.03.2011
* Time: 15:40:55
*/
public class BaseCustomNode extends CommonTree implements TreeToQueryCapable {
public BaseCustomNode(Token t) {
super(t);
}
public CommonTree treeToQueryPre(QueryBuilder sb, List<ErrorRec> invalidNodes) {
return this;
}
public CommonTree treeToQueryPost(QueryBuilder sb, List<ErrorRec> invalidNodes) {
return this;
}
protected CommonTree getNextNode() {
return getChildIndex() == (getParent().getChildCount() - 1) ?
null:
(CommonTree) getParent().getChild(getChildIndex() + 1);
}
protected CommonTree getPrevNode() {
return getChildIndex() == 0 ?
null:
(CommonTree) getParent().getChild(getChildIndex() - 1);
}
protected void dupChildren(CommonTree result) {
for (Object child : children) {
CommonTree t = (CommonTree) child;
Tree copy = t.dupNode();
result.addChild(copy);
}
}
}

View File

@ -0,0 +1,83 @@
package com.haulmont.cuba.core.sys.jpql.tree;
import com.haulmont.cuba.core.sys.jpql.DomainModel;
import com.haulmont.cuba.core.sys.jpql.ErrorRec;
import com.haulmont.cuba.core.sys.jpql.QueryVariableContext;
import com.haulmont.cuba.core.sys.jpql.pointer.*;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonErrorNode;
import org.antlr.runtime.tree.CommonTree;
import java.util.Deque;
import java.util.List;
/**
* Author: Alexander Chevelev
* Date: 30.10.2010
* Time: 4:15:07
*/
public class BaseJoinNode extends BaseCustomNode {
protected String variableName;
protected BaseJoinNode(Token token, String variableName) {
super(token);
this.variableName = variableName;
}
public BaseJoinNode(int type, String variableName) {
this(new CommonToken(type, ""), variableName);
}
public String getVariableName() {
return variableName;
}
public void identifyVariableEntity(DomainModel model,
Deque<QueryVariableContext> stack,
List<ErrorRec> invalidNodes) {
String variableName = getVariableName();
if (variableName == null) {
invalidNodes.add(new ErrorRec(this, "No variable name found"));
return;
}
List children = getChildren();
if (children == null) {
invalidNodes.add(new ErrorRec(this, "No children found"));
return;
}
if (children.size() != 1) {
invalidNodes.add(new ErrorRec(this, "Number of children not equals 1"));
return;
}
CommonTree child0 = (CommonTree) children.get(0);
if (child0 instanceof CommonErrorNode) {
invalidNodes.add(new ErrorRec(this, "Child 0 is an error node"));
return;
}
QueryVariableContext queryVC = stack.peekLast();
PathNode pathNode = (PathNode) child0;
Pointer pointer = pathNode.walk(model, queryVC);
if (pointer instanceof NoPointer) {
invalidNodes.add(new ErrorRec(this, "Cannot resolve joined entity"));
} else if (pointer instanceof SimpleAttributePointer) {
invalidNodes.add(new ErrorRec(this, "Joined entity resolved to a non-entity attribute"));
} else if (pointer instanceof EntityPointer) {
queryVC.addEntityVariable(variableName, ((EntityPointer) pointer).getEntity());
} else if (pointer instanceof CollectionPointer) {
queryVC.addEntityVariable(variableName, ((CollectionPointer) pointer).getEntity());
} else {
invalidNodes.add(new ErrorRec(this,
"Unexpected pointer variable type: " + pointer.getClass())
);
}
}
public void setVariableName(String newName) {
variableName = newName;
}
}

View File

@ -0,0 +1,52 @@
package com.haulmont.cuba.core.sys.jpql.tree;
import com.haulmont.cuba.core.sys.jpql.ErrorRec;
import com.haulmont.cuba.core.sys.jpql.QueryBuilder;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;
import java.util.List;
/**
* Author: Alexander Chevelev
* Date: 30.10.2010
* Time: 4:15:07
*/
public class CollectionMemberNode extends BaseJoinNode {
private CollectionMemberNode(Token token, String variableName) {
super(token, variableName);
}
public CollectionMemberNode(int type, String variableName) {
this(new CommonToken(type, ""), variableName);
}
@Override
public String toString() {
return (token != null ? token.getText() : "") + "Collection member decl: " + variableName;
}
@Override
public Tree dupNode() {
CollectionMemberNode result = new CollectionMemberNode(token, variableName);
dupChildren(result);
return result;
}
public CommonTree treeToQueryPre(QueryBuilder sb, List<ErrorRec> invalidNodes) {
sb.appendSpace();
sb.appendString("in(");
return this;
}
public CommonTree treeToQueryPost(QueryBuilder sb, List<ErrorRec> invalidNodes) {
// должно появится после определения сущности, из которой выбирают, поэтому в post
sb.appendString(")");
sb.appendSpace();
sb.appendString(variableName);
return this;
}
}

View File

@ -0,0 +1,46 @@
package com.haulmont.cuba.core.sys.jpql.tree;
import com.haulmont.cuba.core.sys.jpql.ErrorRec;
import com.haulmont.cuba.core.sys.jpql.QueryBuilder;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;
import java.util.List;
/**
* Author: Alexander Chevelev
* Date: 30.10.2010
* Time: 4:15:07
*/
public class FromNode extends BaseCustomNode {
private Token fromT;
private FromNode(Token token, Token fromT) {
super(token);
this.fromT = fromT;
}
public FromNode(int type, Token fromT) {
this(new CommonToken(type, ""), fromT);
}
@Override
public String toString() {
return (token != null ? token.getText() : "") + fromT;
}
@Override
public Tree dupNode() {
FromNode result = new FromNode(token, fromT);
dupChildren(result);
return result;
}
public CommonTree treeToQueryPre(QueryBuilder sb, List<ErrorRec> invalidNodes) {
sb.appendSpace();
sb.appendString(fromT.getText());
return this;
}
}

View File

@ -0,0 +1,36 @@
package com.haulmont.cuba.core.sys.jpql.tree;
import com.haulmont.cuba.core.sys.jpql.ErrorRec;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;
import java.util.List;
/**
* Author: Alexander Chevelev
* Date: 30.10.2010
* Time: 4:15:07
*/
public class GroupByNode extends BaseCustomNode {
private GroupByNode(Token token) {
super(token);
}
public GroupByNode(int type) {
this(new CommonToken(type, ""));
}
@Override
public String toString() {
return "GROUP BY";
}
@Override
public Tree dupNode() {
GroupByNode result = new GroupByNode(token);
dupChildren(result);
return result;
}
}

View File

@ -1,15 +1,11 @@
package com.haulmont.cuba.core.sys.jpql.tree;
import com.haulmont.cuba.core.sys.jpql.DomainModel;
import com.haulmont.cuba.core.sys.jpql.ErrorRec;
import com.haulmont.cuba.core.sys.jpql.QueryVariableContext;
import com.haulmont.cuba.core.sys.jpql.UnknownEntityNameException;
import com.haulmont.cuba.core.sys.jpql.model.Entity;
import com.haulmont.cuba.core.sys.jpql.model.NoEntity;
import com.haulmont.cuba.core.sys.jpql.*;
import com.haulmont.cuba.core.sys.jpql.pointer.SimpleAttributePointer;
import com.haulmont.cuba.core.sys.jpql.pointer.NoPointer;
import com.haulmont.cuba.core.sys.jpql.pointer.Pointer;
import com.haulmont.cuba.core.sys.jpql.pointer.EntityPointer;
import com.haulmont.cuba.core.sys.jpql.model.*;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonErrorNode;
@ -24,7 +20,7 @@ import java.util.List;
* Date: 30.10.2010
* Time: 4:15:07
*/
public class IdentificationVariableNode extends CommonTree {
public class IdentificationVariableNode extends BaseCustomNode {
private String variableName;
private IdentificationVariableNode(Token token, String variableName) {
@ -88,6 +84,7 @@ public class IdentificationVariableNode extends CommonTree {
List children = node.getChildren();
CommonTree T_SELECTED_ITEMS_NODE = (CommonTree) children.get(0);
for (Object o : T_SELECTED_ITEMS_NODE.getChildren()) {
o = ((SelectedItemNode) o).getChild(0);
if (!(o instanceof PathNode)) {
throw new RuntimeException("Not a path node");
}
@ -106,7 +103,7 @@ public class IdentificationVariableNode extends CommonTree {
} else if (pointer instanceof EntityPointer) {
if (T_SELECTED_ITEMS_NODE.getChildren().size() != 1) {
//todo implement
throw new RuntimeException("");
throw new RuntimeException("Не реализован вариант, когда возвращается массив");
} else {
queryVC.setEntity(((EntityPointer) pointer).getEntity());
}
@ -121,6 +118,21 @@ public class IdentificationVariableNode extends CommonTree {
@Override
public Tree dupNode() {
return new IdentificationVariableNode(token, variableName);
IdentificationVariableNode result = new IdentificationVariableNode(token, variableName);
dupChildren(result);
return result;
}
@Override
public CommonTree treeToQueryPost(QueryBuilder sb, List<ErrorRec> invalidNodes) {
// должно появится после определения сущности, из которой выбирают, поэтому в post
sb.appendSpace();
sb.appendString(variableName);
return this;
}
public String getEntityName() {
return getChild(0).getText();
}
}

View File

@ -1,82 +1,29 @@
package com.haulmont.cuba.core.sys.jpql.tree;
import com.haulmont.cuba.core.sys.jpql.DomainModel;
import com.haulmont.cuba.core.sys.jpql.ErrorRec;
import com.haulmont.cuba.core.sys.jpql.QueryVariableContext;
import com.haulmont.cuba.core.sys.jpql.pointer.*;
import com.haulmont.cuba.core.sys.jpql.QueryBuilder;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonErrorNode;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;
import java.util.Deque;
import java.util.List;
/**
* Author: Alexander Chevelev
* Date: 30.10.2010
* Time: 4:15:07
* Date: 01.04.2011
* Time: 20:22:32
*/
public class JoinVariableNode extends CommonTree {
private String variableName;
public class JoinVariableNode extends BaseJoinNode {
private String joinSpec;
private JoinVariableNode(Token token, String variableName) {
super(token);
this.variableName = variableName;
public JoinVariableNode(Token token, String joinSpec, String variableName) {
super(token, variableName);
this.joinSpec = joinSpec;
}
public JoinVariableNode(int type, String variableName) {
this(new CommonToken(type, ""), variableName);
}
public String getVariableName() {
return variableName;
}
public void identifyVariableEntity(DomainModel model,
Deque<QueryVariableContext> stack,
List<ErrorRec> invalidIdVarNodes) {
String variableName = getVariableName();
if (variableName == null) {
invalidIdVarNodes.add(new ErrorRec(this, "No variable name found"));
return;
}
List children = getChildren();
if (children == null) {
invalidIdVarNodes.add(new ErrorRec(this, "No children found"));
return;
}
if (children.size() != 1) {
invalidIdVarNodes.add(new ErrorRec(this, "Number of children not equals 1"));
return;
}
CommonTree child0 = (CommonTree) children.get(0);
if (child0 instanceof CommonErrorNode) {
invalidIdVarNodes.add(new ErrorRec(this, "Child 0 is an error node"));
return;
}
QueryVariableContext queryVC = stack.peekLast();
PathNode pathNode = (PathNode) child0;
Pointer pointer = pathNode.walk(model, queryVC);
if (pointer instanceof NoPointer) {
invalidIdVarNodes.add(new ErrorRec(this, "Cannot resolve joined entity"));
} else if (pointer instanceof SimpleAttributePointer) {
invalidIdVarNodes.add(new ErrorRec(this, "Joined entity resolved to a non-entity attribute"));
} else if (pointer instanceof EntityPointer) {
queryVC.addEntityVariable(variableName, ((EntityPointer) pointer).getEntity());
} else if (pointer instanceof CollectionPointer) {
queryVC.addEntityVariable(variableName, ((CollectionPointer) pointer).getEntity());
} else {
invalidIdVarNodes.add(new ErrorRec(this,
"Unexpected pointer variable type: " + pointer.getClass())
);
}
public JoinVariableNode(int type, String joinSpec, String variableName) {
this(new CommonToken(type, ""), joinSpec, variableName);
}
@Override
@ -86,6 +33,26 @@ public class JoinVariableNode extends CommonTree {
@Override
public Tree dupNode() {
return new JoinVariableNode(token, variableName);
JoinVariableNode result = new JoinVariableNode(token, joinSpec, variableName);
dupChildren(result);
return result;
}
public CommonTree treeToQueryPre(QueryBuilder sb, List<ErrorRec> invalidNodes) {
sb.appendSpace();
sb.appendString(joinSpec);
sb.appendSpace();
return this;
}
public CommonTree treeToQueryPost(QueryBuilder sb, List<ErrorRec> invalidNodes) {
// должно появится после определения сущности, из которой выбирают, поэтому в post
sb.appendSpace();
sb.appendString(variableName);
return this;
}
public PathNode getPathNode() {
return (PathNode) getChild(0);
}
}

View File

@ -0,0 +1,32 @@
package com.haulmont.cuba.core.sys.jpql.tree;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.Tree;
/**
* Author: Alexander Chevelev
* Date: 30.10.2010
* Time: 4:15:07
*/
public class OrderByFieldNode extends BaseCustomNode {
private OrderByFieldNode(Token token) {
super(token);
}
public OrderByFieldNode(int type) {
this(new CommonToken(type, ""));
}
@Override
public String toString() {
return "ORDER BY FIELD";
}
@Override
public Tree dupNode() {
OrderByFieldNode result = new OrderByFieldNode(token);
dupChildren(result);
return result;
}
}

View File

@ -0,0 +1,32 @@
package com.haulmont.cuba.core.sys.jpql.tree;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.Tree;
/**
* Author: Alexander Chevelev
* Date: 30.10.2010
* Time: 4:15:07
*/
public class OrderByNode extends BaseCustomNode {
private OrderByNode(Token token) {
super(token);
}
public OrderByNode(int type) {
this(new CommonToken(type, ""));
}
@Override
public String toString() {
return "ORDER BY";
}
@Override
public Tree dupNode() {
OrderByNode result = new OrderByNode(token);
dupChildren(result);
return result;
}
}

View File

@ -0,0 +1,65 @@
package com.haulmont.cuba.core.sys.jpql.tree;
import com.haulmont.cuba.core.sys.jpql.ErrorRec;
import com.haulmont.cuba.core.sys.jpql.QueryBuilder;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;
import java.util.List;
/**
* Author: Alexander Chevelev
* Date: 30.10.2010
* Time: 4:15:07
*/
public class ParameterNode extends BaseCustomNode {
private ParameterNode(Token token) {
super(token);
}
public ParameterNode(int type) {
this(new CommonToken(type, ""));
}
@Override
public String toString() {
return "";
}
@Override
public Tree dupNode() {
ParameterNode result = new ParameterNode(token);
dupChildren(result);
return result;
}
@Override
public CommonTree treeToQueryPre(QueryBuilder sb, List<ErrorRec> invalidNodes) {
if (getChildren().size() == 2) {
String child0Text = getChild(0).getText();
String child1Text = getChild(1).getText();
if (":".equals(child0Text) || "?".equals(child0Text)) {
sb.appendString(child0Text);
sb.appendString(child1Text);
return null;
}
}
return super.treeToQueryPre(sb, invalidNodes);
}
public boolean isNamed() {
return getChild(0).getText().charAt(0) == ':';
}
public boolean isIndexed() {
return getChild(0).getText().equals("?");
}
public String getParameterReference() {
return isIndexed() ? getChild(1).getText() : getChild(0).getText().substring(1);
}
}

View File

@ -1,47 +1,88 @@
package com.haulmont.cuba.core.sys.jpql.tree;
import com.haulmont.cuba.core.sys.jpql.DomainModel;
import com.haulmont.cuba.core.sys.jpql.EntityPath;
import com.haulmont.cuba.core.sys.jpql.QueryVariableContext;
import com.haulmont.cuba.core.sys.jpql.*;
import com.haulmont.cuba.core.sys.jpql.pointer.Pointer;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;
import java.util.Collections;
import java.util.List;
/**
* Author: Alexander Chevelev
* Date: 30.10.2010
* Time: 4:15:07
*/
public class PathNode extends CommonTree {
private String path;
public class PathNode extends BaseCustomNode {
private String entityVariableName;
private PathNode(Token token, String path) {
public PathNode(Token token, String entityVariableName) {
super(token);
this.path = path;
this.entityVariableName = entityVariableName;
}
public PathNode(int type, String path) {
this(new CommonToken(type, path), path);
public PathNode(int type, String entityVariableName) {
this(new CommonToken(type, ""), entityVariableName);
}
public String getEntityVariableName() {
return entityVariableName;
}
@Override
public Tree dupNode() {
return new PathNode(token, path);
public PathNode dupNode() {
PathNode result = new PathNode(token, entityVariableName);
dupChildren(result);
return result;
}
public Pointer walk(DomainModel model, QueryVariableContext queryVC) {
EntityPath entityPath = EntityPath.parseEntityPath(path);
Pointer pointer = entityPath.walk(model, queryVC);
if (!(entityPath.lastEntityFieldPattern == null || "".equals(entityPath.lastEntityFieldPattern))) {
pointer = pointer.next(model, entityPath.lastEntityFieldPattern);
List treeItems = getChildren();
if (treeItems == null) {
treeItems = Collections.emptyList();
}
return pointer;
String[] parts = new String[treeItems.size()];
for (int i = 0; i < treeItems.size(); i++) {
CommonTree treeItem = (CommonTree) treeItems.get(i);
parts[i] = treeItem.getText();
}
EntityPath path = new EntityPath();
path.topEntityVariableName = entityVariableName;
path.lastEntityFieldPattern = null;
path.traversedFields = parts;
return path.walk(model, queryVC);
}
@Override
public String toString() {
return (token != null ? token.getText() : "Path is: " + path);
return (token != null ? token.getText() : "") + "Path entity variable: " + entityVariableName;
}
}
public CommonTree treeToQueryPre(QueryBuilder sb, List<ErrorRec> invalidNodes) {
sb.appendString(asPathString());
return null;
}
public String asPathString() {
String result = "";
result += entityVariableName;
if (children != null) {
for (Object child : children) {
result += '.' + child.toString();
}
}
return result;
}
public void renameVariableTo(String newVariableName) {
entityVariableName = newVariableName;
}
public void changeField(String newField) {
CommonTree lastChild = (CommonTree) getChild(getChildCount() - 1);
lastChild.getToken().setText(newField);
}
}

View File

@ -1,15 +1,19 @@
package com.haulmont.cuba.core.sys.jpql.tree;
import com.haulmont.cuba.core.sys.jpql.ErrorRec;
import com.haulmont.cuba.core.sys.jpql.QueryBuilder;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;
import java.util.List;
/**
* Author: Alexander Chevelev
* Date: 20.10.2010
* Time: 23:20:41
*/
public class QueryNode extends CommonTree {
public class QueryNode extends BaseCustomNode {
private Token lastToken;
private QueryNode(Token token, Token lastToken) {
@ -34,7 +38,27 @@ public class QueryNode extends CommonTree {
@Override
public Tree dupNode() {
return new QueryNode(token, lastToken);
QueryNode result = new QueryNode(token, lastToken);
dupChildren(result);
return result;
}
@Override
public String toStringTree() {
return super.toStringTree();
}
public CommonTree treeToQueryPre(QueryBuilder sb, List<ErrorRec> invalidNodes) {
sb.appendString(getText());
return this;
}
public CommonTree treeToQueryPost(QueryBuilder sb, List<ErrorRec> invalidNodes) {
if (parent != null) {
if (' ' == sb.getLast())
sb.deleteLast();
sb.appendString(") ");
}
return this;
}
}

View File

@ -0,0 +1,49 @@
package com.haulmont.cuba.core.sys.jpql.tree;
import com.haulmont.cuba.core.sys.jpql.ErrorRec;
import com.haulmont.cuba.core.sys.jpql.QueryBuilder;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;
import java.util.List;
/**
* Author: Alexander Chevelev
* Date: 30.10.2010
* Time: 4:15:07
*/
public class SelectedItemNode extends BaseCustomNode {
private SelectedItemNode(Token token) {
super(token);
}
public SelectedItemNode(int type) {
this(new CommonToken(type, ""));
}
@Override
public String toString() {
return "SELECTED_ITEM";
}
@Override
public Tree dupNode() {
SelectedItemNode result = new SelectedItemNode(token);
dupChildren(result);
return result;
}
@Override
public CommonTree treeToQueryPre(QueryBuilder sb, List<ErrorRec> invalidNodes) {
CommonTree prevNode = getPrevNode();
if (prevNode != null && prevNode instanceof SelectedItemNode) {
sb.appendString(", ");
} else {
sb.appendSpace();
}
return super.treeToQueryPre(sb, invalidNodes);
}
}

View File

@ -0,0 +1,53 @@
package com.haulmont.cuba.core.sys.jpql.tree;
import com.haulmont.cuba.core.sys.jpql.ErrorRec;
import com.haulmont.cuba.core.sys.jpql.QueryBuilder;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;
import java.util.List;
/**
* Author: Alexander Chevelev
* Date: 30.10.2010
* Time: 4:15:07
*/
public class SelectionSourceNode extends BaseCustomNode {
private SelectionSourceNode(Token token) {
super(token);
}
public SelectionSourceNode(int type) {
this(new CommonToken(type, ""));
}
@Override
public String toString() {
return "SELECTION_SOURCE";
}
@Override
public Tree dupNode() {
SelectionSourceNode result = new SelectionSourceNode(token);
dupChildren(result);
return result;
}
@Override
public CommonTree treeToQueryPre(QueryBuilder sb, List<ErrorRec> invalidNodes) {
CommonTree prevNode = getPrevNode();
if (prevNode != null && prevNode instanceof SelectionSourceNode) {
sb.appendString(", ");
} else {
sb.appendSpace();
}
return super.treeToQueryPre(sb, invalidNodes);
}
@Override
public CommonTree treeToQueryPost(QueryBuilder sb, List<ErrorRec> invalidNodes) {
return this;
}
}

View File

@ -0,0 +1,47 @@
package com.haulmont.cuba.core.sys.jpql.tree;
import com.haulmont.cuba.core.sys.jpql.ErrorRec;
import com.haulmont.cuba.core.sys.jpql.QueryBuilder;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;
import java.util.List;
/**
* Author: Alexander Chevelev
* Date: 30.10.2010
* Time: 4:15:07
*/
public class SimpleConditionNode extends BaseCustomNode {
private SimpleConditionNode(Token token) {
super(token);
}
public SimpleConditionNode(int type) {
this(new CommonToken(type, ""));
}
@Override
public String toString() {
return "SIMPLE_CONDITION";
}
@Override
public Tree dupNode() {
SimpleConditionNode result = new SimpleConditionNode(token);
dupChildren(result);
return result;
}
@Override
public CommonTree treeToQueryPre(QueryBuilder sb, List<ErrorRec> invalidNodes) {
return super.treeToQueryPre(sb, invalidNodes);
}
@Override
public CommonTree treeToQueryPost(QueryBuilder sb, List<ErrorRec> invalidNodes) {
return this;
}
}

View File

@ -0,0 +1,19 @@
package com.haulmont.cuba.core.sys.jpql.tree;
import com.haulmont.cuba.core.sys.jpql.ErrorRec;
import com.haulmont.cuba.core.sys.jpql.QueryBuilder;
import org.antlr.runtime.tree.CommonTree;
import java.util.List;
/**
* Author: Alexander Chevelev
* Date: 26.03.2011
* Time: 3:16:12
*/
public interface TreeToQueryCapable {
CommonTree treeToQueryPre(QueryBuilder sb, List<ErrorRec> invalidNodes);
CommonTree treeToQueryPost(QueryBuilder sb, List<ErrorRec> invalidNodes);
}

View File

@ -0,0 +1,46 @@
package com.haulmont.cuba.core.sys.jpql.tree;
import com.haulmont.cuba.core.sys.jpql.ErrorRec;
import com.haulmont.cuba.core.sys.jpql.QueryBuilder;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;
import java.util.List;
/**
* Author: Alexander Chevelev
* Date: 30.10.2010
* Time: 4:15:07
*/
public class WhereNode extends BaseCustomNode {
private Token whereT;
private WhereNode(Token token, Token whereT) {
super(token);
this.whereT = whereT;
}
public WhereNode(int type, Token whereT) {
this(new CommonToken(type, ""), whereT);
}
@Override
public String toString() {
return (token != null ? token.getText() : "") + whereT;
}
@Override
public Tree dupNode() {
WhereNode result = new WhereNode(token, whereT);
dupChildren(result);
return result;
}
public CommonTree treeToQueryPre(QueryBuilder sb, List<ErrorRec> invalidNodes) {
sb.appendSpace();
sb.appendString(whereT.getText());
return this;
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
*/
package com.haulmont.cuba.core.sys.jpql;
import org.junit.Test;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
/**
* Author: Alexander Chevelev
* Date: 08.04.2011
* Time: 0:11:17
*/
public class EntityPathTest {
@Test
public void parseEntityPath() {
EntityPath path = EntityPath.parseEntityPath("p.ni");
assertEquals("p", path.topEntityVariableName);
assertEquals("ni", path.lastEntityFieldPattern);
assertArrayEquals(new String[0], path.traversedFields);
path = EntityPath.parseEntityPath("p.");
assertEquals("p", path.topEntityVariableName);
assertEquals("", path.lastEntityFieldPattern);
assertArrayEquals(new String[0], path.traversedFields);
path = EntityPath.parseEntityPath("p.team.");
assertEquals("p", path.topEntityVariableName);
assertEquals("", path.lastEntityFieldPattern);
assertArrayEquals(new String[]{"team"}, path.traversedFields);
path = EntityPath.parseEntityPath("p.team.owner.na");
assertEquals("p", path.topEntityVariableName);
assertEquals("na", path.lastEntityFieldPattern);
assertArrayEquals(new String[]{"team", "owner"}, path.traversedFields);
}
}

View File

@ -4,6 +4,7 @@ import com.haulmont.cuba.core.global.MetadataHelper;
import com.haulmont.cuba.core.sys.jpql.DomainModelBuilder;
import com.haulmont.cuba.core.sys.jpql.DomainModel;
import com.haulmont.cuba.gui.autocomplete.impl.HintProvider;
import com.haulmont.cuba.gui.autocomplete.impl.HintRequest;
import com.haulmont.cuba.gui.autocomplete.impl.HintResponse;
import com.haulmont.cuba.gui.autocomplete.impl.Option;
@ -45,7 +46,10 @@ public class JpqlSuggestionFactory {
HintProvider provider = new HintProvider(domainModel);
try {
HintResponse response = provider.requestHint(query, queryPosition);
HintRequest request = new HintRequest();
request.setQuery(query);
request.setPosition(queryPosition);
HintResponse response = provider.requestHint(request);
String prefix = response.getLastWord();
List<Option> options = response.getOptionObjects();

View File

@ -1,7 +1,6 @@
package com.haulmont.cuba.gui.autocomplete.impl;
import com.haulmont.cuba.core.sys.jpql.*;
import com.haulmont.cuba.core.sys.jpql.Parser;
import com.haulmont.cuba.core.sys.jpql.model.Attribute;
import com.haulmont.cuba.core.sys.jpql.model.Entity;
import com.haulmont.cuba.core.sys.jpql.pointer.CollectionPointer;
@ -10,10 +9,13 @@ import com.haulmont.cuba.core.sys.jpql.pointer.NoPointer;
import com.haulmont.cuba.core.sys.jpql.pointer.Pointer;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.TreeVisitor;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* User: Alex Chevelev
@ -23,6 +25,8 @@ import java.util.List;
public class HintProvider {
private DomainModel model;
private static final char CARET_POSITION_SYMBOL = '~';
public static final Pattern COLLECTION_MEMBER_PATTERN = Pattern.compile(".*\\sin\\s*[(]\\s*[a-zA-Z0-9]+[.][a-zA-Z0-9.]*$");
public static final Pattern JOIN_PATTERN = Pattern.compile(".*\\sjoin\\s*[a-zA-Z0-9]+[.][a-zA-Z0-9.]*$");
public HintProvider(DomainModel model) {
if (model == null)
@ -34,12 +38,16 @@ public class HintProvider {
if (caretPosition < 0)
return "";
// todo
// todo только ли пробелы здесь возможны?
if (queryString.charAt(caretPosition) == ' ') {
return "";
}
int lastWordStart = queryString.lastIndexOf(' ', caretPosition);
return queryString.substring(lastWordStart + 1, caretPosition + 1);
String result = queryString.substring(lastWordStart + 1, caretPosition + 1);
if (result.startsWith("in("))
result = result.substring(3);
return result;
}
public HintResponse requestHint(String queryStringWithCaret) throws RecognitionException {
@ -54,29 +62,30 @@ public class HintProvider {
String queryString = queryStringWithCaret.substring(0, caretPosition + 1) +
queryStringWithCaret.substring(caretPosition + 2);
return requestHint(queryString, caretPosition);
MacroProcessor macroProcessor = new MacroProcessor();
HintRequest hintRequest = macroProcessor.inlineFake(queryString, caretPosition);
return requestHint(hintRequest);
}
public HintResponse requestHint(String input, int cursorPos) throws RecognitionException {
// todo текст-дерево-обратная генерация запроса по дереву будет съедать эти символы в исходном выражении
input = input.replace("\n", " ");
input = input.replace("\r", " ");
input = input.replace("\t", " ");
public HintResponse requestHint(HintRequest hintRequest) throws RecognitionException {
String input = hintRequest.getQuery();
int cursorPos = hintRequest.getPosition();
Set<InferredType> expectedTypes = hintRequest.getExpectedTypes() == null ?
EnumSet.of(InferredType.Any) :
hintRequest.getExpectedTypes();
String lastWord = getLastWord(input, cursorPos);
CommonTree tree = Parser.parse(input);
expectedTypes = narrowExpectedTypes(input, cursorPos, expectedTypes);
return (!lastWord.contains(".")) ?
hintEntityName(lastWord) :
hintFieldName(lastWord, tree, cursorPos);
hintFieldName(lastWord, input, cursorPos, expectedTypes);
}
private HintResponse hintFieldName(String lastWord, CommonTree tree, int caretPosition) {
TreeVisitor visitor = new TreeVisitor();
IdVarSelector idVarSelector = new IdVarSelector(model);
visitor.visit(tree, idVarSelector);
List<ErrorRec> errorRecs = idVarSelector.getInvalidNodes();
QueryVariableContext root = idVarSelector.getContextTree();
private HintResponse hintFieldName(String lastWord, String input, int caretPosition, Set<InferredType> expectedTypes) throws RecognitionException {
QueryTreeAnalyzer queryAnalyzer = new QueryTreeAnalyzer();
queryAnalyzer.prepare(model, input);
List<ErrorRec> errorRecs = queryAnalyzer.getInvalidIdVarNodes();
QueryVariableContext root = queryAnalyzer.getRootQueryVariableContext();
QueryVariableContext queryVC = root.getContextByCaretPosition(caretPosition);
EntityPath path = EntityPath.parseEntityPath(lastWord);
@ -100,7 +109,7 @@ public class HintProvider {
Entity targetEntity = ((EntityPointer) pointer).getEntity();
List<Attribute> attributes = targetEntity.findAttributesStartingWith(
path.lastEntityFieldPattern);
path.lastEntityFieldPattern, expectedTypes);
List<Option> options = new ArrayList<Option>();
for (Attribute attribute : attributes) {
@ -133,4 +142,20 @@ public class HintProvider {
}
return new HintResponse(options, lastWord);
}
}
public static Set<InferredType> narrowExpectedTypes(String input, int cursorPos, Set<InferredType> expectedTypes) {
if (input.charAt(cursorPos) == ' ') {
return expectedTypes;
}
String matchingInput = input.substring(0, cursorPos + 1);
Matcher matcher = COLLECTION_MEMBER_PATTERN.matcher(matchingInput);
if (matcher.matches()) {
return EnumSet.of(InferredType.Collection, InferredType.Entity);
}
matcher = JOIN_PATTERN.matcher(matchingInput);
if (matcher.matches()) {
return EnumSet.of(InferredType.Collection, InferredType.Entity);
}
return expectedTypes;
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
*/
package com.haulmont.cuba.gui.autocomplete.impl;
import com.haulmont.cuba.core.sys.jpql.InferredType;
import java.util.Set;
/**
* Author: Alexander Chevelev
* Date: 24.03.2011
* Time: 21:42:45
*/
public class HintRequest {
private int position;
private String query;
private Set<InferredType> expectedTypes;
public HintRequest() {
}
public int getPosition() {
return position;
}
public String getQuery() {
return query;
}
public void setPosition(int position) {
this.position = position;
}
public void setQuery(String query) {
this.query = query;
}
public Set<InferredType> getExpectedTypes() {
return expectedTypes;
}
public void setExpectedTypes(Set<InferredType> expectedTypes) {
this.expectedTypes = expectedTypes;
}
}

View File

@ -55,8 +55,4 @@ public class HintResponse {
public String getLastWord() {
return lastWord;
}
public String getOptionDescription(String option) {
return null;
}
}
}

View File

@ -71,7 +71,7 @@ public class IdVarSelector implements TreeVisitorAction {
if ((node instanceof QueryNode) && node.getParent() != null && "T_CONDITION".equals(((CommonTree) node.getParent()).token.getText())) {
stack.peekLast().setPropateVariablesUp(false);
stack.peekLast().setPropagateVariablesUp(false);
return t;
}

View File

@ -0,0 +1,154 @@
/*
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
*/
package com.haulmont.cuba.gui.autocomplete.impl;
import com.haulmont.cuba.core.sys.jpql.InferredType;
import java.util.EnumSet;
import java.util.Set;
/**
* Author: Alexander Chevelev
* Date: 24.03.2011
* Time: 20:50:57
*/
public class MacroProcessor {
private final static String BETWEEN_REPLACEMENT = " = :d ";
private final static String TWO_OPERAND_REPLACEMENT = " =";
public HintRequest inlineFake(String query, int position) {
HintRequest result = new HintRequest();
result.setQuery(query);
result.setPosition(position);
result.setExpectedTypes(EnumSet.of(InferredType.Any));
result = inlineFakeBetweenMacro(result);
result = inlineFakeSingleOperandMacro("@today", result);
result = inlineFakeTwoOperandMacro("@dateEquals", result);
result = inlineFakeTwoOperandMacro("@dateAfter", result);
result = inlineFakeTwoOperandMacro("@dateBefore", result);
return result;
}
private HintRequest inlineFakeBetweenMacro(HintRequest request) {
String newQuery = request.getQuery();
int newPosition = request.getPosition();
Set<InferredType> newExpectedTypes = request.getExpectedTypes();
String macroName = "@between";
String macroEntry = macroName + "(";
while (true) {
int macroBegin = newQuery.indexOf(macroEntry);
if (macroBegin == -1) {
break;
}
int macroEnd = macroBegin + macroEntry.length();
int firstComma = newQuery.indexOf(',', macroBegin);
// assuming no braces within macro
int closingBrace = newQuery.indexOf(')', macroBegin);
newQuery = newQuery.substring(0, macroBegin)
+ newQuery.substring(macroEnd, firstComma)
+ BETWEEN_REPLACEMENT
+ newQuery.substring(closingBrace + 1);
if (newPosition > macroEnd && newPosition < firstComma) {
newPosition += -macroEntry.length();
newExpectedTypes = EnumSet.of(InferredType.Date);
} else if (newPosition > firstComma && newPosition < closingBrace) {
throw new IllegalStateException("Cannot handle request: unsupported request position within macro");
} else if (newPosition > closingBrace) {
newPosition += -macroEntry.length() + BETWEEN_REPLACEMENT.length() - 1 + (firstComma - closingBrace);
}
}
HintRequest result = new HintRequest();
result.setQuery(newQuery);
result.setPosition(newPosition);
result.setExpectedTypes(newExpectedTypes);
return result;
}
private HintRequest inlineFakeTwoOperandMacro(String macro, HintRequest request) {
String newQuery = request.getQuery();
int newPosition = request.getPosition();
Set<InferredType> newExpectedTypes = request.getExpectedTypes();
String macroEntry = macro + "(";
while (true) {
int macroBegin = newQuery.indexOf(macroEntry);
if (macroBegin == -1) {
break;
}
int macroEnd = macroBegin + macroEntry.length();
int comma = newQuery.indexOf(',', macroBegin);
// assuming no braces within macro
int closingBrace = newQuery.indexOf(')', macroBegin);
newQuery = newQuery.substring(0, macroBegin)
+ newQuery.substring(macroEnd, comma)
+ TWO_OPERAND_REPLACEMENT
+ newQuery.substring(comma + 1, closingBrace)
+ " "
+ newQuery.substring(closingBrace + 1);
if (newPosition > macroEnd && newPosition < comma) {
newPosition += -macroEntry.length();
newExpectedTypes = EnumSet.of(InferredType.Date);
} else if (newPosition > comma && newPosition < closingBrace) {
newPosition += -macroEntry.length() + TWO_OPERAND_REPLACEMENT.length() - 1;
newExpectedTypes = EnumSet.of(InferredType.Date);
} else if (newPosition > closingBrace) {
newPosition += -macroEntry.length() + TWO_OPERAND_REPLACEMENT.length() - 1 + 1 - 1;
}
}
HintRequest result = new HintRequest();
result.setQuery(newQuery);
result.setPosition(newPosition);
result.setExpectedTypes(newExpectedTypes);
return result;
}
private HintRequest inlineFakeSingleOperandMacro(String macro, HintRequest request) {
String newQuery = request.getQuery();
int newPosition = request.getPosition();
Set<InferredType> newExpectedTypes = request.getExpectedTypes();
String macroEntry = macro + "(";
while (true) {
int macroBegin = newQuery.indexOf(macroEntry);
if (macroBegin == -1) {
break;
}
int macroEnd = macroBegin + macroEntry.length();
int closingBrace = newQuery.indexOf(')', macroBegin);
newQuery = newQuery.substring(0, macroBegin)
+ newQuery.substring(macroEnd, closingBrace)
+ BETWEEN_REPLACEMENT
+ newQuery.substring(closingBrace + 1);
if (newPosition > macroEnd && newPosition < closingBrace) {
newPosition += -macroEntry.length();
newExpectedTypes = EnumSet.of(InferredType.Date);
} else if (newPosition > closingBrace) {
newPosition += -macroEntry.length() + BETWEEN_REPLACEMENT.length() - 1;
}
}
HintRequest result = new HintRequest();
result.setQuery(newQuery);
result.setPosition(newPosition);
result.setExpectedTypes(newExpectedTypes);
return result;
}
}

View File

@ -17,13 +17,12 @@ import com.haulmont.chile.core.model.MetaProperty;
import com.haulmont.chile.core.model.MetaPropertyPath;
import com.haulmont.chile.core.model.utils.InstanceUtils;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.entity.Versioned;
import com.haulmont.cuba.core.global.*;
import com.haulmont.cuba.gui.UserSessionClient;
import com.haulmont.cuba.gui.filter.QueryFilter;
import com.haulmont.cuba.gui.data.*;
import com.haulmont.cuba.gui.xml.ParametersHelper;
import com.haulmont.cuba.gui.filter.QueryFilter;
import com.haulmont.cuba.gui.xml.ParameterInfo;
import com.haulmont.cuba.gui.xml.ParametersHelper;
import com.haulmont.cuba.security.global.UserSession;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.ObjectUtils;

View File

@ -0,0 +1,842 @@
/*
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
*/
package com.haulmont.cuba.gui.autocomplete.impl;
import com.haulmont.cuba.core.sys.jpql.DomainModel;
import com.haulmont.cuba.core.sys.jpql.InferredType;
import com.haulmont.cuba.core.sys.jpql.model.Entity;
import com.haulmont.cuba.core.sys.jpql.model.EntityBuilder;
import com.haulmont.cuba.core.sys.jpql.model.EntityImpl;
import junit.framework.Assert;
import org.antlr.runtime.RecognitionException;
import org.junit.Test;
import java.util.Date;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
/**
* User: Alex Chevelev
* Date: 13.10.2010
* Time: 18:01:03
*/
public class HintProviderTest {
@Test
public void requestHint_entityNameHint_simple() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
EntityImpl playerEntity = builder.produceImmediately("Player");
DomainModel model = new DomainModel();
model.add(playerEntity);
HintProvider hintProvider = createTestHintProvider(model);
HintResponse response = hintProvider.requestHint("SELECT p FROM P~");
List<String> options = response.getOptions();
assertEquals(1, options.size());
assertEquals("Player", options.get(0));
response = hintProvider.requestHint("FROM N~");
options = response.getOptions();
assertEquals(0, options.size());
}
@Test
public void requestHint_entityNameHint_order() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
EntityImpl playerEntity = builder.produceImmediately("Player");
EntityImpl parentEntity = builder.produceImmediately("Parent");
DomainModel model = new DomainModel();
model.add(playerEntity);
model.add(parentEntity);
HintProvider hintProvider = createTestHintProvider(model);
HintResponse response = hintProvider.requestHint("SELECT p FROM P~");
List<String> options = response.getOptions();
assertEquals(2, options.size());
assertEquals("Parent", options.get(0));
assertEquals("Player", options.get(1));
}
private HintProvider createTestHintProvider(DomainModel model) {
return new HintProvider(model);
}
@Test
public void requestHint_erroneous() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
EntityImpl playerEntity = builder.produceImmediately("Player");
DomainModel model = new DomainModel();
model.add(playerEntity);
HintProvider hintProvider = createTestHintProvider(model);
HintResponse response = hintProvider.requestHint("select t FROM p...~");
List<String> options = response.getOptions();
assertEquals(0, options.size());
assertEquals("Query error", response.getErrorMessage());
assertArrayEquals(new String[]{"Cannot parse [p...]"},
response.getCauseErrorMessages().toArray()
);
}
@Test
public void requestHint_fieldNameHint_simple() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity playerEntity = builder.produceImmediately("Player", "name", "nickname");
DomainModel model = new DomainModel();
model.add(playerEntity);
HintProvider hintProvider = createTestHintProvider(model);
HintResponse response = hintProvider.requestHint("SELECT p.~ FROM Player p");
List<String> options = response.getOptions();
assertEquals(2, options.size());
assertEquals("name", options.get(0));
assertEquals("nickname", options.get(1));
response = hintProvider.requestHint("SELECT p.ni~ FROM Player p");
options = response.getOptions();
assertEquals(1, options.size());
assertEquals("nickname", options.get(0));
response = hintProvider.requestHint("SELECT p.p~ FROM Player p");
options = response.getOptions();
assertEquals(0, options.size());
}
@Test
public void requestHint_fieldNameHint_simple_wherePart() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity teamEntity = builder.produceImmediately("Team", "name", "owner");
DomainModel model = new DomainModel();
model.add(teamEntity);
HintProvider hintProvider = createTestHintProvider(model);
HintResponse response = hintProvider.requestHint("select t from Team t where t.~");
List<String> options = response.getOptions();
assertEquals(2, options.size());
assertEquals("name", options.get(0));
assertEquals("owner", options.get(1));
hintProvider = createTestHintProvider(model);
response = hintProvider.requestHint("select t.~ from Team t where t.name = 'KS'");
options = response.getOptions();
assertEquals(2, options.size());
assertEquals("name", options.get(0));
assertEquals("owner", options.get(1));
hintProvider = createTestHintProvider(model);
response = hintProvider.requestHint("select t.name from Team t where t.~");
options = response.getOptions();
assertEquals(2, options.size());
assertEquals("name", options.get(0));
assertEquals("owner", options.get(1));
hintProvider = createTestHintProvider(model);
response = hintProvider.requestHint("select t.~ from Team t where t.name in ('KS', 'Zenit')");
options = response.getOptions();
assertEquals(2, options.size());
assertEquals("name", options.get(0));
assertEquals("owner", options.get(1));
}
@Test
public void requestHint_fieldNameHint_simple_referencedEntity() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity teamEntity = builder.produceImmediately("Team", "name");
builder.startNewEntity("Player");
builder.addStringAttribute("name");
builder.addStringAttribute("nickname");
builder.addReferenceAttribute("team", "Team");
Entity playerEntity = builder.produce();
DomainModel model = new DomainModel();
model.add(teamEntity);
model.add(playerEntity);
HintProvider hintProvider = createTestHintProvider(model);
HintResponse response = hintProvider.requestHint("SELECT p.te~ FROM Player p");
List<String> options = response.getOptions();
assertEquals(1, options.size());
assertEquals("team", options.get(0));
response = hintProvider.requestHint("SELECT p.team.~ FROM Player p");
options = response.getOptions();
assertEquals(1, options.size());
assertEquals("name", options.get(0));
response = hintProvider.requestHint("SELECT p.team.ni~ FROM Player p");
options = response.getOptions();
assertEquals(0, options.size());
}
@Test
public void requestHint_fieldNameHint_simple_referencedEntity_collections() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity teamEntity = builder.produceImmediately("Team", "name");
builder.startNewEntity("Player");
builder.addStringAttribute("name");
builder.addStringAttribute("nickname");
builder.addReferenceAttribute("team", "Team");
Entity playerEntity = builder.produce();
builder.startNewEntity("League");
builder.addStringAttribute("name");
builder.addCollectionReferenceAttribute("teams", "Team");
Entity leagueEntity = builder.produce();
DomainModel model = new DomainModel();
model.add(teamEntity);
model.add(playerEntity);
model.add(leagueEntity);
HintProvider hintProvider = createTestHintProvider(model);
HintResponse response = hintProvider.requestHint("SELECT l.teams.~ FROM League l");
List<String> options = response.getOptions();
assertEquals(0, options.size());
assertEquals("Query error", response.getErrorMessage());
assertEquals(1, response.getCauseErrorMessages().size());
assertEquals("Cannot get attribute of collection [l.teams.]", response.getCauseErrorMessages().get(0));
response = hintProvider.requestHint("SELECT l.name FROM League l where l.teams.~");
options = response.getOptions();
assertEquals(0, options.size());
assertEquals("Query error", response.getErrorMessage());
assertEquals(1, response.getCauseErrorMessages().size());
assertEquals("Cannot get attribute of collection [l.teams.]", response.getCauseErrorMessages().get(0));
response = hintProvider.requestHint("SELECT l.name FROM League l where exists (select 1 from Team t where t.name = l.teams.n~");
options = response.getOptions();
assertEquals(0, options.size());
assertEquals("Query error", response.getErrorMessage());
assertEquals(1, response.getCauseErrorMessages().size());
assertEquals("Cannot get attribute of collection [l.teams.n]", response.getCauseErrorMessages().get(0));
}
@Test
public void requestHint_fieldNameHint_subqueryEntity() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity teamEntity = builder.produceImmediately("Team", "name", "owner");
builder.startNewEntity("Player");
builder.addStringAttribute("name");
builder.addStringAttribute("nickname");
builder.addReferenceAttribute("team", "Team");
Entity playerEntity = builder.produce();
DomainModel model = new DomainModel();
model.add(teamEntity);
model.add(playerEntity);
HintProvider hintProvider = createTestHintProvider(model);
HintResponse response = hintProvider.requestHint("select p.~ from (select t from Team t) p");
List<String> options = response.getOptions();
assertEquals(2, options.size());
assertEquals("name", options.get(0));
assertEquals("owner", options.get(1));
response = hintProvider.requestHint("select p.~ from (select t.name from Team t) p");
options = response.getOptions();
assertEquals(1, options.size());
assertEquals("name", options.get(0));
response = hintProvider.requestHint("select p.t~ from (select t.name from Team t) p");
options = response.getOptions();
assertEquals(0, options.size());
response = hintProvider.requestHint("select p.o~ from (select t.name, t.owner from Team t) p");
options = response.getOptions();
assertEquals(1, options.size());
assertEquals("owner", options.get(0));
response = hintProvider.requestHint("select g.o~ from (select t.name, t.owner from Team t) p, (select t.name from Team t) g");
options = response.getOptions();
assertEquals(0, options.size());
}
@Test
public void requestHint_fieldNameHint_severalLevelsOfSubquery() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity teamEntity = builder.produceImmediately("Team", "name", "owner");
builder.startNewEntity("Player");
builder.addStringAttribute("name");
builder.addStringAttribute("nickname");
builder.addReferenceAttribute("team", "Team");
Entity playerEntity = builder.produce();
DomainModel model = new DomainModel();
model.add(teamEntity);
model.add(playerEntity);
HintProvider hintProvider = createTestHintProvider(model);
HintResponse response = hintProvider.requestHint(
"select p.~ from " +
"(select t from Team t " +
"where t.name in " +
" (select a.name from Player a)" +
") p");
List<String> options = response.getOptions();
assertEquals(2, options.size());
assertEquals("name", options.get(0));
assertEquals("owner", options.get(1));
response = hintProvider.requestHint("select p.owner from (select t.o~ from Team t where t.name in (select a.name from Player a)) p");
options = response.getOptions();
assertEquals(1, options.size());
assertEquals("owner", options.get(0));
response = hintProvider.requestHint("select p.owner from (select t from Team t where t.name in (select a.~ from Player a)) p");
options = response.getOptions();
assertEquals(3, options.size());
assertEquals("name", options.get(0));
assertEquals("nickname", options.get(1));
assertEquals("team", options.get(2));
response = hintProvider.requestHint("select p.owner from (select t from Team t where t.~ in (select a.name from Player a)) p");
options = response.getOptions();
assertEquals(2, options.size());
assertEquals("name", options.get(0));
assertEquals("owner", options.get(1));
response = hintProvider.requestHint("select p.owner from (select a.ni~ from Team t where t.name in (select a.name from Player a)) p");
options = response.getOptions();
assertEquals(0, options.size());
assertEquals("Query error", response.getErrorMessage());
assertEquals(1, response.getCauseErrorMessages().size());
assertEquals("Cannot parse [a.ni]", response.getCauseErrorMessages().get(0));
}
@Test
public void requestHint_fieldNameHint_subqueries_using_AS() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity teamEntity = builder.produceImmediately("Team", "name", "owner");
builder.startNewEntity("Player");
builder.addStringAttribute("name");
builder.addStringAttribute("nickname");
builder.addReferenceAttribute("team", "Team");
Entity playerEntity = builder.produce();
DomainModel model = new DomainModel();
model.add(teamEntity);
model.add(playerEntity);
HintProvider hintProvider = createTestHintProvider(model);
HintResponse response = hintProvider.requestHint(
"select p.~ from (select t.owner from Team as t where t.name) p");
List<String> options = response.getOptions();
assertEquals(1, options.size());
assertEquals("owner", options.get(0));
}
@Test
public void requestHint_entityNameHint_subquery() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity teamEntity = builder.produceImmediately("Team", "name", "owner");
builder.startNewEntity("Player");
builder.addStringAttribute("name");
builder.addStringAttribute("nickname");
builder.addReferenceAttribute("team", "Team");
Entity playerEntity = builder.produce();
DomainModel model = new DomainModel();
model.add(teamEntity);
model.add(playerEntity);
HintProvider hintProvider = createTestHintProvider(model);
HintResponse response = hintProvider.requestHint("select p from (select t from T~) p");
List<String> options = response.getOptions();
assertEquals(1, options.size());
assertEquals("Team", options.get(0));
}
@Test
public void requestHint_fieldNameHint_where_in_topLevelVariablesUse() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity teamEntity = builder.produceImmediately("Team", "name", "owner");
builder.startNewEntity("Player");
builder.addStringAttribute("name");
builder.addStringAttribute("nickname");
builder.addReferenceAttribute("team", "Team");
Entity playerEntity = builder.produce();
DomainModel model = new DomainModel();
model.add(teamEntity);
model.add(playerEntity);
HintProvider hintProvider = createTestHintProvider(model);
HintResponse response = hintProvider.requestHint(
"select p.name from Player p " +
"where p.nickname in " +
"(select t.name " +
"from Team t " +
"where t.onwer = p.~)");
List<String> options = response.getOptions();
assertEquals(3, options.size());
assertEquals("name", options.get(0));
assertEquals("nickname", options.get(1));
assertEquals("team", options.get(2));
response = hintProvider.requestHint(
"select t.~ from Player p " +
"where p.nickname in " +
"(select t.name " +
"from Team t " +
"where t.onwer = p.name)");
options = response.getOptions();
assertEquals(0, options.size());
assertEquals("Query error", response.getErrorMessage());
assertEquals(1, response.getCauseErrorMessages().size());
assertEquals("Cannot parse [t.]", response.getCauseErrorMessages().get(0));
hintProvider = createTestHintProvider(model);
response = hintProvider.requestHint("select p from Player p where p.team.name in (select a.~ from Team a where a.name = 'KS')");
options = response.getOptions();
assertEquals(2, options.size());
assertEquals("name", options.get(0));
assertEquals("owner", options.get(1));
}
@Test
public void requestHint_fieldNameHint_where_exists() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity teamEntity = builder.produceImmediately("Team", "name", "owner");
builder.startNewEntity("Player");
builder.addStringAttribute("name");
builder.addStringAttribute("nickname");
builder.addReferenceAttribute("team", "Team");
Entity playerEntity = builder.produce();
DomainModel model = new DomainModel();
model.add(teamEntity);
model.add(playerEntity);
HintProvider hintProvider = createTestHintProvider(model);
HintResponse response = hintProvider.requestHint(
"select p.name from Player p " +
"where exists " +
"(select 1 " +
"from Team t " +
"where t.onwer = p.~)");
List<String> options = response.getOptions();
assertEquals(3, options.size());
assertEquals("name", options.get(0));
assertEquals("nickname", options.get(1));
assertEquals("team", options.get(2));
response = hintProvider.requestHint(
"select t.~ from Player p " +
"where exists " +
"(select 1 " +
"from Team t " +
"where t.onwer = p.name)");
options = response.getOptions();
assertEquals(0, options.size());
assertEquals("Query error", response.getErrorMessage());
assertEquals(1, response.getCauseErrorMessages().size());
assertEquals("Cannot parse [t.]", response.getCauseErrorMessages().get(0));
response = hintProvider.requestHint(
"select p.name from Player p " +
"where exists " +
"(select 1 " +
"from Team t " +
"where t.~ = p.name)");
options = response.getOptions();
assertEquals(2, options.size());
assertEquals("name", options.get(0));
assertEquals("owner", options.get(1));
}
@Test
public void requestHint_fieldNameHint_wherein_subquerywhere() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity teamEntity = builder.produceImmediately("Team", "name", "owner");
Entity playerEntity = builder.produceImmediately("Player", "nickname", "name");
DomainModel model = new DomainModel();
model.add(playerEntity);
model.add(teamEntity);
HintProvider hintProvider = createTestHintProvider(model);
HintResponse response = hintProvider.requestHint("select p.name from Player p where p.team in (select a from Team a where a.~)");
List<String> options = response.getOptions();
assertEquals(2, options.size());
assertEquals("name", options.get(0));
assertEquals("owner", options.get(1));
hintProvider = createTestHintProvider(model);
response = hintProvider.requestHint("select p.name from Player p where p.team in (select a from Team a where a.name = p.n~)");
options = response.getOptions();
assertEquals(2, options.size());
assertEquals("name", options.get(0));
assertEquals("nickname", options.get(1));
}
@Test
public void requestHint_fieldNameHint_join() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity personEntity = builder.produceImmediately("Person", "name");
builder.startNewEntity("Team");
builder.addStringAttribute("name");
builder.addStringAttribute("owner");
builder.addReferenceAttribute("manager", "Person");
Entity teamEntity = builder.produce();
builder.startNewEntity("Player");
builder.addStringAttribute("name");
builder.addStringAttribute("nickname");
builder.addReferenceAttribute("team", "Team");
builder.addReferenceAttribute("agent", "Person");
Entity playerEntity = builder.produce();
DomainModel model = new DomainModel();
model.add(teamEntity);
model.add(playerEntity);
model.add(personEntity);
HintProvider hintProvider = createTestHintProvider(model);
HintResponse response = hintProvider.requestHint("select p.name, t.o~ from Player p join p.team as t");
List<String> options = response.getOptions();
assertEquals(1, options.size());
assertEquals("owner", options.get(0));
hintProvider = createTestHintProvider(model);
response = hintProvider.requestHint("select p from Player p join p.team as t where t.~");
options = response.getOptions();
assertEquals(3, options.size());
assertEquals("manager", options.get(0));
assertEquals("name", options.get(1));
assertEquals("owner", options.get(2));
hintProvider = createTestHintProvider(model);
response = hintProvider.requestHint("select p from Player p join p.~ ");
options = response.getOptions();
assertEquals(2, options.size());
assertEquals("agent", options.get(0));
assertEquals("team", options.get(1));
hintProvider = createTestHintProvider(model);
response = hintProvider.requestHint("select p from Player p join p.team as t where t.~");
options = response.getOptions();
assertEquals(3, options.size());
assertEquals("manager", options.get(0));
assertEquals("name", options.get(1));
assertEquals("owner", options.get(2));
hintProvider = createTestHintProvider(model);
response = hintProvider.requestHint(
"select m.~ from Player p " +
"join p.team as t " +
"join t.manager as m");
options = response.getOptions();
assertEquals(1, options.size());
assertEquals("name", options.get(0));
hintProvider = createTestHintProvider(model);
response = hintProvider.requestHint(
"select t from Player p " +
"join p.team as t " +
"join t.~");
options = response.getOptions();
assertEquals(1, options.size());
assertEquals("manager", options.get(0));
}
@Test
public void requestHint_fieldNameHint_join_withCollections() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity personEntity = builder.produceImmediately("Person", "name");
builder.startNewEntity("Team");
builder.addStringAttribute("name");
builder.addStringAttribute("owner");
builder.addReferenceAttribute("manager", "Person");
Entity teamEntity = builder.produce();
builder.startNewEntity("Player");
builder.addStringAttribute("name");
builder.addStringAttribute("nickname");
builder.addReferenceAttribute("team", "Team");
builder.addReferenceAttribute("agent", "Person");
Entity playerEntity = builder.produce();
builder.startNewEntity("League");
builder.addStringAttribute("name");
builder.addCollectionReferenceAttribute("teams", "Team");
Entity leagueEntity = builder.produce();
DomainModel model = new DomainModel();
model.add(teamEntity);
model.add(playerEntity);
model.add(leagueEntity);
model.add(personEntity);
HintProvider hintProvider = createTestHintProvider(model);
HintResponse response = hintProvider.requestHint(
"select m.~ from League l " +
"left join l.teams as t " +
"left join t.manager as m");
List<String> options = response.getOptions();
assertEquals(1, options.size());
assertEquals("name", options.get(0));
hintProvider = createTestHintProvider(model);
response = hintProvider.requestHint(
"select l from League l " +
"join l.teams as t " +
"join t.~");
options = response.getOptions();
assertEquals(1, options.size());
assertEquals("manager", options.get(0));
}
@Test
public void requestHint_fieldNameHint_join_and_collection() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity driver = builder.produceImmediately("Driver", "name", "signal");
builder.startNewEntity("HomeBase");
builder.addStringAttribute("city");
Entity homeBase = builder.produce();
builder.startNewEntity("Car");
builder.addStringAttribute("model");
builder.addCollectionReferenceAttribute("drivers", "Driver");
builder.addReferenceAttribute("station", "HomeBase");
Entity car = builder.produce();
DomainModel model = new DomainModel(car, driver, homeBase);
HintProvider hp = new HintProvider(model);
HintResponse response = hp.requestHint("select d.name from Car c join c.station s, in(c.drivers) d where d.name = ?1 and s.~");
List<String> options = response.getOptions();
assertEquals(1, options.size());
assertEquals("city", options.get(0));
}
@Test
public void requestHint_fieldNameHint_join_throughSeveralFields() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity personEntity = builder.produceImmediately("Person", "personName");
builder.startNewEntity("Team");
builder.addStringAttribute("name");
builder.addStringAttribute("owner");
builder.addReferenceAttribute("manager", "Person");
Entity teamEntity = builder.produce();
builder.startNewEntity("Player");
builder.addStringAttribute("name");
builder.addStringAttribute("nickname");
builder.addReferenceAttribute("team", "Team");
builder.addReferenceAttribute("agent", "Person");
Entity playerEntity = builder.produce();
builder.startNewEntity("League");
builder.addStringAttribute("name");
builder.addCollectionReferenceAttribute("teams", "Team");
Entity leagueEntity = builder.produce();
builder.startNewEntity("Country");
builder.addStringAttribute("flag");
builder.addReferenceAttribute("league", "League");
Entity countryEntity = builder.produce();
DomainModel model = new DomainModel(teamEntity, playerEntity, leagueEntity, personEntity, countryEntity);
HintProvider hintProvider = createTestHintProvider(model);
HintResponse response = hintProvider.requestHint(
"select m.~ from Player p " +
"left join p.team.manager as m");
List<String> options = response.getOptions();
assertEquals(1, options.size());
assertEquals("personName", options.get(0));
hintProvider = createTestHintProvider(model);
response = hintProvider.requestHint(
"select c.flag from Country c " +
"join c.league.teams as t " +
"join t.~");
options = response.getOptions();
assertEquals(1, options.size());
assertEquals("manager", options.get(0));
}
@Test
public void requestHint_fieldNameHint_keywordCaseInsensitivity() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity playerEntity = builder.produceImmediately("Player", "name", "nickname");
DomainModel model = new DomainModel();
model.add(playerEntity);
HintProvider hintProvider = createTestHintProvider(model);
HintResponse response = hintProvider.requestHint("select p.~ from Player p");
List<String> options = response.getOptions();
assertEquals(2, options.size());
assertEquals("name", options.get(0));
assertEquals("nickname", options.get(1));
}
@Test
public void requestHint_fieldNameHint_returnedFieldOrder() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity playerEntity = builder.produceImmediately("Player", "nickname", "name");
DomainModel model = new DomainModel();
model.add(playerEntity);
HintProvider hintProvider = createTestHintProvider(model);
HintResponse response = hintProvider.requestHint("select p.~ from Player p");
List<String> options = response.getOptions();
assertEquals(2, options.size());
assertEquals("name", options.get(0));
assertEquals("nickname", options.get(1));
}
@Test
public void requestHint_betweenMacro() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
builder.startNewEntity("Player");
builder.addStringAttribute("nickname");
builder.addStringAttribute("name");
builder.addSingleValueAttribute(Date.class, "joinDate");
Entity playerEntity = builder.produce();
DomainModel model = new DomainModel();
model.add(playerEntity);
HintProvider hintProvider = createTestHintProvider(model);
HintResponse response = hintProvider.requestHint("select p.~ from Player p where @between(p.joinDate, now, now+1, day)");
List<String> options = response.getOptions();
assertEquals(3, options.size());
assertEquals("joinDate", options.get(0));
assertEquals("name", options.get(1));
assertEquals("nickname", options.get(2));
hintProvider = createTestHintProvider(model);
response = hintProvider.requestHint("select p.name from Player p where @between(p.~, now, now+1, day)");
options = response.getOptions();
assertEquals(1, options.size());
assertEquals("joinDate", options.get(0));
}
@Test
public void requestHint_with_in_collections() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity driver = builder.produceImmediately("Driver", "name", "signal");
builder.startNewEntity("Car");
builder.addStringAttribute("model");
builder.addCollectionReferenceAttribute("drivers", "Driver");
Entity car = builder.produce();
DomainModel model = new DomainModel(car, driver);
HintProvider hintProvider = createTestHintProvider(model);
HintResponse response = hintProvider.requestHint("select d.~ from Car c, in(c.drivers) d");
List<String> options = response.getOptions();
assertEquals(2, options.size());
assertEquals("name", options.get(0));
assertEquals("signal", options.get(1));
response = hintProvider.requestHint("select d.name from Car c, in(c.~");
options = response.getOptions();
assertEquals(1, options.size());
assertEquals("drivers", options.get(0));
response = hintProvider.requestHint("select d.name from Car c, in(c.drivers) d where d.~");
options = response.getOptions();
assertEquals(2, options.size());
assertEquals("name", options.get(0));
assertEquals("signal", options.get(1));
}
@Test
public void requestHint_with_variableRebinding() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity driver = builder.produceImmediately("Driver", "name", "signal");
builder.startNewEntity("Car");
builder.addStringAttribute("model");
builder.addCollectionReferenceAttribute("drivers", "Driver");
Entity car = builder.produce();
DomainModel model = new DomainModel(car, driver);
HintProvider hintProvider = createTestHintProvider(model);
try {
hintProvider.requestHint("select a.~ from Car a, in(a.drivers) a where a.model = ?1");
Assert.fail();
} catch (IllegalArgumentException e) {
}
}
@Test
public void narrowExpectedTypes() {
Set<InferredType> result = HintProvider.narrowExpectedTypes(" in(p.te", 5, EnumSet.of(InferredType.Any));
assertEquals(EnumSet.of(InferredType.Collection, InferredType.Entity), result);
result = HintProvider.narrowExpectedTypes(" in( p.te", 6, EnumSet.of(InferredType.Any));
assertEquals(EnumSet.of(InferredType.Collection, InferredType.Entity), result);
result = HintProvider.narrowExpectedTypes(" in ( p.te", 9, EnumSet.of(InferredType.Any));
assertEquals(EnumSet.of(InferredType.Collection, InferredType.Entity), result);
result = HintProvider.narrowExpectedTypes(" in (p.te", 6, EnumSet.of(InferredType.Any));
assertEquals(EnumSet.of(InferredType.Collection, InferredType.Entity), result);
result = HintProvider.narrowExpectedTypes(" join p.te", 7, EnumSet.of(InferredType.Any));
assertEquals(EnumSet.of(InferredType.Collection, InferredType.Entity), result);
result = HintProvider.narrowExpectedTypes(" join p.te", 8, EnumSet.of(InferredType.Any));
assertEquals(EnumSet.of(InferredType.Collection, InferredType.Entity), result);
result = HintProvider.narrowExpectedTypes("select p.te", 9, EnumSet.of(InferredType.Any));
assertEquals(EnumSet.of(InferredType.Any), result);
result = HintProvider.narrowExpectedTypes("where p.te", 8, EnumSet.of(InferredType.Any));
assertEquals(EnumSet.of(InferredType.Any), result);
result = HintProvider.narrowExpectedTypes("group by p.te", 11, EnumSet.of(InferredType.Any));
assertEquals(EnumSet.of(InferredType.Any), result);
result = HintProvider.narrowExpectedTypes("order by p.te", 11, EnumSet.of(InferredType.Any));
assertEquals(EnumSet.of(InferredType.Any), result);
result = HintProvider.narrowExpectedTypes("having p.te", 9, EnumSet.of(InferredType.Any));
assertEquals(EnumSet.of(InferredType.Any), result);
result = HintProvider.narrowExpectedTypes("count (distinct p.te", 18, EnumSet.of(InferredType.Any));
assertEquals(EnumSet.of(InferredType.Any), result);
}
@Test
public void getLastWord() {
String lastWord = HintProvider.getLastWord("FROM P", "FROM P".length() - 1);
assertEquals("P", lastWord);
lastWord = HintProvider.getLastWord("FROM P", "FROM ".length() - 1);
assertEquals("", lastWord);
lastWord = HintProvider.getLastWord("SELECT p.team.na", "SELECT p.team.na".length() - 1);
assertEquals("p.team.na", lastWord);
lastWord = HintProvider.getLastWord("in(p.teams", "in(p.teams".length() - 1);
assertEquals("p.teams", lastWord);
}
}

View File

@ -0,0 +1,158 @@
/*
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
*/
package com.haulmont.cuba.gui.autocomplete.impl;
import com.haulmont.cuba.core.sys.jpql.InferredType;
import org.junit.Before;
import org.junit.Test;
import java.util.EnumSet;
import static junit.framework.Assert.assertEquals;
/**
* Author: Alexander Chevelev
* Date: 24.03.2011
* Time: 21:36:09
*/
public class MacroProcessorTest {
private MacroProcessor processor;
@Before
public void initProcessor() {
processor = new MacroProcessor();
}
@Test
public void inlineFake_between() {
HintRequest request = processor.inlineFake("select p. from Player p where @between(p.joinDate, now, now+1, day)", 8);
assertEquals("select p. from Player p where p.joinDate = :d ", request.getQuery());
assertEquals(8, request.getPosition());
assertEquals(EnumSet.of(InferredType.Any), request.getExpectedTypes());
request = processor.inlineFake("select p.name from Player p where @between(p., now, now+1, day)", 44);
assertEquals("select p.name from Player p where p. = :d ", request.getQuery());
assertEquals(35, request.getPosition());
assertEquals(EnumSet.of(InferredType.Date), request.getExpectedTypes());
try {
processor.inlineFake("select p.name from Player p where @between(p.joinDate, p., now + 1, day)", 44);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
}
request = processor.inlineFake("select p.name from Player p where @between(p.joinDate, now, now+1, day) and p.", 77);
assertEquals("select p.name from Player p where p.joinDate = :d and p.", request.getQuery());
assertEquals(56, request.getPosition());
assertEquals(EnumSet.of(InferredType.Any), request.getExpectedTypes());
}
@Test
public void inlineFake_dateBefore() {
HintRequest request = processor.inlineFake("select p. from Player p where @dateBefore(p.joinDate, :d)", 8);
assertEquals("select p. from Player p where p.joinDate = :d ", request.getQuery());
assertEquals(8, request.getPosition());
assertEquals(EnumSet.of(InferredType.Any), request.getExpectedTypes());
request = processor.inlineFake("select p.name from Player p where @dateBefore(p., :d)", 47);
assertEquals("select p.name from Player p where p. = :d ", request.getQuery());
assertEquals(35, request.getPosition());
assertEquals(EnumSet.of(InferredType.Date), request.getExpectedTypes());
request = processor.inlineFake("select p.name from Player p where @dateBefore(p.joinDate, p.)", 59);
assertEquals("select p.name from Player p where p.joinDate = p. ", request.getQuery());
assertEquals(48, request.getPosition());
assertEquals(EnumSet.of(InferredType.Date), request.getExpectedTypes());
request = processor.inlineFake("select p.name from Player p where @dateBefore(p.joinDate, :d) and p.", 67);
assertEquals("select p.name from Player p where p.joinDate = :d and p.", request.getQuery());
assertEquals(56, request.getPosition());
assertEquals(EnumSet.of(InferredType.Any), request.getExpectedTypes());
}
@Test
public void inlineFake_dateEquals() {
HintRequest request = processor.inlineFake("select p. from Player p where @dateEquals(p.joinDate, :d)", 8);
assertEquals("select p. from Player p where p.joinDate = :d ", request.getQuery());
assertEquals(8, request.getPosition());
assertEquals(EnumSet.of(InferredType.Any), request.getExpectedTypes());
request = processor.inlineFake("select p.name from Player p where @dateEquals(p., :d)", 47);
assertEquals("select p.name from Player p where p. = :d ", request.getQuery());
assertEquals(35, request.getPosition());
assertEquals(EnumSet.of(InferredType.Date), request.getExpectedTypes());
request = processor.inlineFake("select p.name from Player p where @dateEquals(p.joinDate, p.)", 59);
assertEquals("select p.name from Player p where p.joinDate = p. ", request.getQuery());
assertEquals(48, request.getPosition());
assertEquals(EnumSet.of(InferredType.Date), request.getExpectedTypes());
}
@Test
public void inlineFake_dateAfter() {
HintRequest request = processor.inlineFake("select p. from Player p where @dateAfter(p.joinDate, :d)", 8);
assertEquals("select p. from Player p where p.joinDate = :d ", request.getQuery());
assertEquals(8, request.getPosition());
assertEquals(EnumSet.of(InferredType.Any), request.getExpectedTypes());
request = processor.inlineFake("select p.name from Player p where @dateAfter(p., :d)", 46);
assertEquals("select p.name from Player p where p. = :d ", request.getQuery());
assertEquals(35, request.getPosition());
assertEquals(EnumSet.of(InferredType.Date), request.getExpectedTypes());
request = processor.inlineFake("select p.name from Player p where @dateAfter(p.joinDate, p.)", 58);
assertEquals("select p.name from Player p where p.joinDate = p. ", request.getQuery());
assertEquals(48, request.getPosition());
assertEquals(EnumSet.of(InferredType.Date), request.getExpectedTypes());
}
@Test
public void inlineFake_today() {
HintRequest request = processor.inlineFake("select p. from Player p where @today(p.joinDate)", 8);
assertEquals("select p. from Player p where p.joinDate = :d ", request.getQuery());
assertEquals(8, request.getPosition());
assertEquals(EnumSet.of(InferredType.Any), request.getExpectedTypes());
request = processor.inlineFake("select p.name from Player p where @today(p.)", 42);
assertEquals("select p.name from Player p where p. = :d ", request.getQuery());
assertEquals(35, request.getPosition());
assertEquals(EnumSet.of(InferredType.Date), request.getExpectedTypes());
request = processor.inlineFake("select p.name from Player p where @today(p.joinDate) and p.", 58);
assertEquals("select p.name from Player p where p.joinDate = :d and p.", request.getQuery());
assertEquals(56, request.getPosition());
assertEquals(EnumSet.of(InferredType.Any), request.getExpectedTypes());
}
@Test
public void inlineFake_two_inlines_in_row() {
HintRequest request = processor.inlineFake("select p. from Player p where @between(p.joinDate, now, now+1, day) and @today(p.leaveDate)", 8);
assertEquals("select p. from Player p where p.joinDate = :d and p.leaveDate = :d ", request.getQuery());
assertEquals(8, request.getPosition());
assertEquals(EnumSet.of(InferredType.Any), request.getExpectedTypes());
request = processor.inlineFake("select p.name from Player p where @between(p.joinDate, now, now+1, day) and @today(p.)", 84);
assertEquals("select p.name from Player p where p.joinDate = :d and p. = :d ", request.getQuery());
assertEquals(56, request.getPosition());
assertEquals(EnumSet.of(InferredType.Date), request.getExpectedTypes());
request = processor.inlineFake("select p.name from Player p where @between(p.joinDate, now, now+1, day) and @between(p., now, now+1, day)", 86);
assertEquals("select p.name from Player p where p.joinDate = :d and p. = :d ", request.getQuery());
assertEquals(56, request.getPosition());
assertEquals(EnumSet.of(InferredType.Date), request.getExpectedTypes());
request = processor.inlineFake("select p.name from Player p where @dateEquals(p.joinDate, :d) and @dateEquals(p. ,:d)", 79);
assertEquals("select p.name from Player p where p.joinDate = :d and p. =:d ", request.getQuery());
assertEquals(56, request.getPosition());
assertEquals(EnumSet.of(InferredType.Date), request.getExpectedTypes());
request = processor.inlineFake("select p.name from Player p where @today(p.joinDate) and @today(p.)", 65);
assertEquals("select p.name from Player p where p.joinDate = :d and p. = :d ", request.getQuery());
assertEquals(56, request.getPosition());
assertEquals(EnumSet.of(InferredType.Date), request.getExpectedTypes());
}
}

View File

@ -0,0 +1,227 @@
/*
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
*/
package com.haulmont.cuba.gui.autocomplete.impl;
import com.haulmont.cuba.core.sys.jpql.DomainModel;
import com.haulmont.cuba.core.sys.jpql.Parser;
import com.haulmont.cuba.core.sys.jpql.antlr.JPALexer;
import com.haulmont.cuba.core.sys.jpql.model.Entity;
import com.haulmont.cuba.core.sys.jpql.model.EntityBuilder;
import com.haulmont.cuba.core.sys.jpql.transform.QueryTreeTransformer;
import com.haulmont.cuba.core.sys.jpql.transform.VariableEntityReference;
import com.haulmont.cuba.core.sys.jpql.tree.*;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;
import org.junit.Test;
import static junit.framework.Assert.*;
/**
* Author: Alexander Chevelev
* Date: 01.04.2011
* Time: 21:06:39
*/
public class QueryAnalyzerTest {
@Test
public void mixinJoinIntoTree() throws RecognitionException {
DomainModel model = prepareDomainModel();
QueryTreeTransformer qa = new QueryTreeTransformer();
qa.prepare(model, "select c from Car c");
CommonTree tree = qa.getTree();
CommonTree sources = (CommonTree) tree.getFirstChildWithType(JPALexer.T_SOURCES);
assertEquals(1, sources.getChildCount());
assertTrue(sources.getChild(0) instanceof SelectionSourceNode);
CommonTree source = (CommonTree) sources.getFirstChildWithType(JPALexer.T_SOURCE);
assertTrue(source.getChild(0) instanceof IdentificationVariableNode);
JoinVariableNode join = (JoinVariableNode) Parser.parseJoinClause("join a.drivers d");
qa.mixinJoinIntoTree(join, new VariableEntityReference("Car", "c"), true);
tree = qa.getTree();
sources = (CommonTree) tree.getFirstChildWithType(JPALexer.T_SOURCES);
assertEquals(1, sources.getChildCount());
SelectionSourceNode sourceNode = (SelectionSourceNode) sources.getChild(0);
assertEquals(2, sourceNode.getChildCount());
assertTrue(sourceNode.getChild(0) instanceof IdentificationVariableNode);
assertTrue(sourceNode.getChild(1) instanceof JoinVariableNode);
JoinVariableNode joinNode = (JoinVariableNode) sourceNode.getChild(1);
assertEquals("d", joinNode.getVariableName());
assertEquals("c", ((PathNode) join.getChild(0)).getEntityVariableName());
}
@Test
public void mixinJoinIntoTree_with_in_collections() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
builder.startNewEntity("HomeBase");
builder.addStringAttribute("name");
Entity homeBase = builder.produce();
builder.startNewEntity("Driver");
builder.addStringAttribute("name");
builder.addStringAttribute("signal");
Entity driver = builder.produce();
builder.startNewEntity("Car");
builder.addStringAttribute("model");
builder.addCollectionReferenceAttribute("drivers", "Driver");
builder.addReferenceAttribute("station", "HomeBase");
Entity car = builder.produce();
DomainModel model = new DomainModel(car, driver, homeBase);
JoinVariableNode join = (JoinVariableNode) Parser.parseJoinClause("join c.station h");
QueryTreeTransformer qa = new QueryTreeTransformer();
qa.prepare(model, "select d.name from Car c, in(c.drivers) d");
CommonTree tree = qa.getTree();
CommonTree sources = (CommonTree) tree.getFirstChildWithType(JPALexer.T_SOURCES);
assertEquals(2, sources.getChildCount());
assertTrue(sources.getChild(0) instanceof SelectionSourceNode);
CommonTree source0 = (CommonTree) sources.getChild(0);
assertEquals(1, source0.getChildCount());
assertTrue(source0.getChild(0) instanceof IdentificationVariableNode);
assertTrue(sources.getChild(1) instanceof SelectionSourceNode);
CommonTree source1 = (CommonTree) sources.getChild(1);
assertTrue(source1.getChild(0) instanceof CollectionMemberNode);
qa.mixinJoinIntoTree(join, new VariableEntityReference("Car", "c"), true);
tree = qa.getTree();
sources = (CommonTree) tree.getFirstChildWithType(JPALexer.T_SOURCES);
assertEquals(2, sources.getChildCount());
assertTrue(sources.getChild(0) instanceof SelectionSourceNode);
source0 = (CommonTree) sources.getChild(0);
assertEquals(2, source0.getChildCount());
assertTrue(source0.getChild(0) instanceof IdentificationVariableNode);
assertTrue(source0.getChild(1) instanceof JoinVariableNode);
assertTrue(sources.getChild(1) instanceof SelectionSourceNode);
source1 = (CommonTree) sources.getChild(1);
assertTrue(source1.getChild(0) instanceof CollectionMemberNode);
}
@Test
public void mixinWhereConditionsIntoTree() throws RecognitionException {
DomainModel model = prepareDomainModel();
QueryTreeTransformer qa = new QueryTreeTransformer();
qa.prepare(model, "select c from Car c");
WhereNode where = (WhereNode) Parser.parseWhereClause("where c.model = ?1");
CommonTree tree = qa.getTree();
assertNull(tree.getFirstChildWithType(JPALexer.T_CONDITION));
qa.mixinWhereConditionsIntoTree(where);
tree = qa.getTree();
assertNotNull(tree.getFirstChildWithType(JPALexer.T_CONDITION));
}
@Test
public void replaceOrderBy() throws RecognitionException {
DomainModel model = prepareDomainModel();
QueryTreeTransformer qa = new QueryTreeTransformer();
qa.prepare(model, "select c from Car c order by c.model");
CommonTree tree = qa.getTree();
CommonTree orderByNode = (CommonTree) tree.getFirstChildWithType(JPALexer.T_ORDER_BY);
Tree orderByField = orderByNode.getFirstChildWithType(JPALexer.T_ORDER_BY_FIELD);
assertEquals(1, orderByField.getChildCount());
PathNode pathNode = (PathNode) orderByField.getChild(0);
assertEquals("c", pathNode.getEntityVariableName());
assertEquals("model", pathNode.getChild(0).getText());
qa.replaceOrderBy("regNumber", true);
assertEquals(2, orderByField.getChildCount());
pathNode = (PathNode) orderByField.getChild(0);
assertEquals("c", pathNode.getEntityVariableName());
assertEquals("regNumber", pathNode.getChild(0).getText());
assertEquals("DESC", orderByField.getChild(1).getText());
}
@Test
public void replaceWithCount() throws RecognitionException {
DomainModel model = prepareDomainModel();
QueryTreeTransformer qa = new QueryTreeTransformer();
qa.prepare(model, "select c from Car c order by c.model");
CommonTree tree = qa.getTree();
CommonTree selectedItems = (CommonTree) tree.getFirstChildWithType(JPALexer.T_SELECTED_ITEMS);
Tree selectedItem = selectedItems.getFirstChildWithType(JPALexer.T_SELECTED_ITEM);
PathNode pathNode = (PathNode) selectedItem.getChild(0);
assertEquals("c", pathNode.getEntityVariableName());
assertEquals(0, pathNode.getChildCount());
CommonTree orderByNode = (CommonTree) tree.getFirstChildWithType(JPALexer.T_ORDER_BY);
assertNotNull(orderByNode.getFirstChildWithType(JPALexer.T_ORDER_BY_FIELD));
qa.replaceWithCount(new VariableEntityReference("Car", "c"));
assertTrue(selectedItem.getChild(0) instanceof AggregateExpressionNode);
AggregateExpressionNode countExpr = (AggregateExpressionNode) selectedItem.getChild(0);
assertEquals("COUNT", countExpr.getChild(0).getText());
assertEquals("c", countExpr.getChild(2).getText());
assertEquals(4, countExpr.getChildCount());
assertNull(orderByNode.getFirstChildWithType(JPALexer.T_ORDER_BY));
}
@Test
public void replaceWithCount_distinct() throws RecognitionException {
DomainModel model = prepareDomainModel();
QueryTreeTransformer qa = new QueryTreeTransformer();
qa.prepare(model, "select distinct d from Car c, in(c.drivers) d order by d.name");
CommonTree tree = qa.getTree();
CommonTree selectedItems = (CommonTree) tree.getFirstChildWithType(JPALexer.T_SELECTED_ITEMS);
Tree selectedItem = selectedItems.getFirstChildWithType(JPALexer.T_SELECTED_ITEM);
PathNode pathNode = (PathNode) selectedItem.getChild(0);
assertEquals("d", pathNode.getEntityVariableName());
assertEquals(0, pathNode.getChildCount());
CommonTree orderByNode = (CommonTree) tree.getFirstChildWithType(JPALexer.T_ORDER_BY);
assertNotNull(orderByNode.getFirstChildWithType(JPALexer.T_ORDER_BY_FIELD));
qa.replaceWithCount(new VariableEntityReference("Driver", "d"));
selectedItems = (CommonTree) tree.getFirstChildWithType(JPALexer.T_SELECTED_ITEMS);
assertEquals(1, selectedItems.getChildCount());
selectedItem = selectedItems.getFirstChildWithType(JPALexer.T_SELECTED_ITEM);
assertTrue(selectedItem.getChild(0) instanceof AggregateExpressionNode);
AggregateExpressionNode countExpr = (AggregateExpressionNode) selectedItem.getChild(0);
assertEquals("COUNT", countExpr.getChild(0).getText());
assertEquals("DISTINCT", countExpr.getChild(2).getText());
assertEquals("d", countExpr.getChild(3).getText());
assertEquals(5, countExpr.getChildCount());
assertNull(orderByNode.getFirstChildWithType(JPALexer.T_ORDER_BY));
}
private DomainModel prepareDomainModel() {
EntityBuilder builder = new EntityBuilder();
Entity driver = builder.produceImmediately("Driver", "name", "signal");
builder.startNewEntity("Car");
builder.addStringAttribute("model");
builder.addStringAttribute("regNumber");
builder.addCollectionReferenceAttribute("drivers", "Driver");
Entity car = builder.produce();
return new DomainModel(car, driver);
}
}

View File

@ -0,0 +1,760 @@
package com.haulmont.cuba.gui.autocomplete.impl.transform;
import com.haulmont.cuba.core.sys.jpql.DomainModel;
import com.haulmont.cuba.core.sys.jpql.ErrorsFoundException;
import com.haulmont.cuba.core.sys.jpql.model.Entity;
import com.haulmont.cuba.core.sys.jpql.model.EntityBuilder;
import com.haulmont.cuba.core.sys.jpql.model.EntityImpl;
import com.haulmont.cuba.core.sys.jpql.transform.QueryTransformerAstBased;
import org.antlr.runtime.RecognitionException;
import org.junit.Before;
import org.junit.Test;
import java.util.Date;
import java.util.Set;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
/**
* Author: Alexander Chevelev
* Date: 26.03.2011
* Time: 1:23:25
*/
public class QueryTransformerAstBasedTest {
@Before
public void setUp() throws Exception {
}
@Test
public void getResult_noChangesMade() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
EntityImpl playerEntity = builder.produceImmediately("Player");
DomainModel model = new DomainModel(playerEntity);
assertTransformsToSame(model, "SELECT p FROM Player p");
}
@Test
public void getResult_noChangesMade_withMultiFieldSelect() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
builder.startNewEntity("Team");
builder.addStringAttribute("name");
Entity teamEntity = builder.produce();
builder.startNewEntity("Player");
builder.addStringAttribute("nickname");
builder.addReferenceAttribute("team", "Team");
Entity playerEntity = builder.produce();
DomainModel model = new DomainModel(playerEntity, teamEntity);
assertTransformsToSame(model, "SELECT p.team.name, p.nickname FROM Player p");
}
@Test
public void getResult_noChangesMade_withMultiEntitySelect() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity teamEntity = builder.produceImmediately("Team");
Entity playerEntity = builder.produceImmediately("Player");
DomainModel model = new DomainModel(playerEntity, teamEntity);
assertTransformsToSame(model, "SELECT p, t FROM Player p, Team t");
}
@Test
public void getResult_noChangesMade_withAggregateExpression() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity teamEntity = builder.produceImmediately("Team", "name");
builder.startNewEntity("Player");
builder.addSingleValueAttribute(Integer.class, "age");
builder.addReferenceAttribute("team", "Team");
Entity playerEntity = builder.produce();
DomainModel model = new DomainModel(playerEntity, teamEntity);
assertTransformsToSame(model, "SELECT count(p) FROM Player p");
assertTransformsToSame(model, "SELECT max(p.age) FROM Player p");
assertTransformsToSame(model, "SELECT min(p.age) FROM Player p");
assertTransformsToSame(model, "SELECT avg(p.age) FROM Player p");
assertTransformsToSame(model, "SELECT sum(p.age) FROM Player p");
assertTransformsToSame(model, "SELECT max(p.age), t FROM Player p join p.team t group by t");
assertTransformsToSame(model, "SELECT max(p.age), t.name FROM Player p join p.team t group by t.name");
}
@Test
public void getResult_noChangesMade_withMacros() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity teamEntity = builder.produceImmediately("Team", "name");
builder.startNewEntity("Player");
builder.addSingleValueAttribute(Date.class, "birthDate");
builder.addReferenceAttribute("team", "Team");
Entity playerEntity = builder.produce();
DomainModel model = new DomainModel(playerEntity, teamEntity);
QueryTransformerAstBased transformerAstBased = new QueryTransformerAstBased(model, "SELECT p FROM Player p where @between(p.birthDate, now-2, now+2, month) ", "Player");
String result = transformerAstBased.getResult();
assertEquals("SELECT p FROM Player p where @between ( p.birthDate, now - 2, now + 2, month)", result);
transformerAstBased = new QueryTransformerAstBased(model, "SELECT p FROM Player p where @dateBefore(p.birthDate, :d) ", "Player");
result = transformerAstBased.getResult();
assertEquals("SELECT p FROM Player p where @dateBefore ( p.birthDate, :d)", result);
transformerAstBased = new QueryTransformerAstBased(model, "SELECT p FROM Player p where @dateAfter(p.birthDate, :d) ", "Player");
result = transformerAstBased.getResult();
assertEquals("SELECT p FROM Player p where @dateAfter ( p.birthDate, :d)", result);
transformerAstBased = new QueryTransformerAstBased(model, "SELECT p FROM Player p where @dateEquals(p.birthDate, :d) ", "Player");
result = transformerAstBased.getResult();
assertEquals("SELECT p FROM Player p where @dateEquals ( p.birthDate, :d)", result);
transformerAstBased = new QueryTransformerAstBased(model, "SELECT p FROM Player p where @today(p.birthDate) ", "Player");
result = transformerAstBased.getResult();
assertEquals("SELECT p FROM Player p where @today ( p.birthDate)", result);
}
@Test
public void getResult_noChangesMade_withWhere() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity teamEntity = builder.produceImmediately("Team", "name");
builder.startNewEntity("Player");
builder.addReferenceAttribute("team", "Team");
builder.addStringAttribute("name");
Entity playerEntity = builder.produce();
DomainModel model = new DomainModel(playerEntity, teamEntity);
assertTransformsToSame(model, "SELECT p FROM Player p where p.name = 'de Souza'");
QueryTransformerAstBased transformerAstBased = new QueryTransformerAstBased(model, "SELECT p FROM Player p left join p.team as t WHERE t.name = 'KS FC'", "Player");
String result = transformerAstBased.getResult();
System.out.println(result);
assertEquals("SELECT p FROM Player p left join p.team t WHERE t.name = 'KS FC'", result);
}
@Test
public void getResult_noChangesMade_withJoin() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity personEntity = builder.produceImmediately("Person", "personName");
builder.startNewEntity("Team");
builder.addStringAttribute("name");
builder.addStringAttribute("owner");
builder.addReferenceAttribute("manager", "Person");
Entity teamEntity = builder.produce();
builder.startNewEntity("Player");
builder.addStringAttribute("name");
builder.addStringAttribute("nickname");
builder.addReferenceAttribute("team", "Team");
builder.addReferenceAttribute("agent", "Person");
Entity playerEntity = builder.produce();
builder.startNewEntity("League");
builder.addStringAttribute("name");
builder.addCollectionReferenceAttribute("teams", "Team");
Entity leagueEntity = builder.produce();
builder.startNewEntity("Country");
builder.addStringAttribute("flag");
builder.addReferenceAttribute("league", "League");
Entity countryEntity = builder.produce();
DomainModel model = new DomainModel(teamEntity, playerEntity, leagueEntity, personEntity, countryEntity);
QueryTransformerAstBased transformerAstBased = new QueryTransformerAstBased(model, "select m.personName from Player p left join p.team.manager as m", "Player");
String result = transformerAstBased.getResult();
assertEquals("select m.personName from Player p left join p.team.manager m", result);
transformerAstBased = new QueryTransformerAstBased(model, "select c.flag from Country c join c.league.teams as t join t.manager m", "Player");
assertEquals("select c.flag from Country c join c.league.teams t join t.manager m",
transformerAstBased.getResult());
}
@Test
public void getResult_noChangesMade_withDistinct() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity personEntity = builder.produceImmediately("Person", "personName");
builder.startNewEntity("Team");
builder.addStringAttribute("name");
builder.addStringAttribute("owner");
builder.addReferenceAttribute("manager", "Person");
Entity teamEntity = builder.produce();
builder.startNewEntity("Player");
builder.addStringAttribute("name");
builder.addStringAttribute("nickname");
builder.addReferenceAttribute("team", "Team");
builder.addReferenceAttribute("agent", "Person");
Entity playerEntity = builder.produce();
builder.startNewEntity("League");
builder.addStringAttribute("name");
builder.addCollectionReferenceAttribute("teams", "Team");
Entity leagueEntity = builder.produce();
builder.startNewEntity("Country");
builder.addStringAttribute("flag");
builder.addReferenceAttribute("league", "League");
Entity countryEntity = builder.produce();
DomainModel model = new DomainModel(teamEntity, playerEntity, leagueEntity, personEntity, countryEntity);
assertTransformsToSame(model, "select distinct m from Player p left join p.team.manager m");
}
@Test
public void getResult_noChangesMade_withSubqueries() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity teamEntity = builder.produceImmediately("Team", "name", "owner");
builder.startNewEntity("Player");
builder.addStringAttribute("name");
builder.addStringAttribute("nickname");
builder.addReferenceAttribute("team", "Team");
Entity playerEntity = builder.produce();
DomainModel model = new DomainModel(playerEntity, teamEntity);
assertTransformsToSame(model, "select p.name from (select t.name from Team t) p");
assertTransformsToSame(model, "select p.owner from (select t.name, t.owner from Team t) p");
assertTransformsToSame(model, "select g.owner from (select t.name, t.owner from Team t) p, (select t.name from Team t) g");
}
@Test
public void getResult_noChangesMade_severalLevelsOfSubquery() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity teamEntity = builder.produceImmediately("Team", "name", "owner");
builder.startNewEntity("Player");
builder.addStringAttribute("name");
builder.addStringAttribute("nickname");
builder.addReferenceAttribute("team", "Team");
Entity playerEntity = builder.produce();
DomainModel model = new DomainModel(playerEntity, teamEntity);
assertTransformsToSame(model, "select p.owner from (select t from Team t where t.name in (select a.name from Player a)) p");
// 'as' опускается
QueryTransformerAstBased transformerAstBased = new QueryTransformerAstBased(model, "select p.owner from (select t.owner from Team as t where t.name = '1') p", "AsdfAsdfAsdf");
String result = transformerAstBased.getResult();
assertEquals("select p.owner from (select t.owner from Team t where t.name = '1') p", result);
}
@Test
public void getResult_noChangesMade_withParameters() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity playerEntity = builder.produceImmediately("Player", "name", "nickname");
DomainModel model = new DomainModel(playerEntity);
assertTransformsToSame(model, "select p.nickname from Player p where p.name = :name");
assertTransformsToSame(model, "select p.nickname from Player p where p.name = :name or p.name = :name2");
assertTransformsToSame(model, "select p.nickname from Player p where p.name = ?1 or p.name = ?2");
}
@Test
public void getResult_noChangesMade_with_in_collections() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity driver = builder.produceImmediately("Driver", "name", "signal");
builder.startNewEntity("HomeBase");
builder.addStringAttribute("city");
Entity homeBase = builder.produce();
builder.startNewEntity("Car");
builder.addStringAttribute("model");
builder.addCollectionReferenceAttribute("drivers", "Driver");
builder.addReferenceAttribute("station", "HomeBase");
Entity car = builder.produce();
DomainModel model = new DomainModel(car, driver, homeBase);
assertTransformsToSame(model, "select d.name from Car c, in(c.drivers) d where d.name = ?1");
assertTransformsToSame(model, "select d.name from Car c join c.station s, in(c.drivers) d where d.name = ?1 and s.city = :par2");
}
@Test
public void getResult_noChangesMade_withGroupByHavingOrderBy() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity playerEntity = builder.produceImmediately("Player", "name", "nickname", "level");
builder.startNewEntity("Team");
builder.addCollectionReferenceAttribute("players", "Player");
builder.addStringAttribute("title");
Entity team = builder.produce();
DomainModel model = new DomainModel(playerEntity, team);
assertTransformsToSame(model, "select p from Team t join t.players p " +
"group by p.level having p.level > 0 order by p.level");
}
private void assertTransformsToSame(DomainModel model, String query) throws RecognitionException {
QueryTransformerAstBased transformerAstBased = new QueryTransformerAstBased(model, query, "Player");
String result = transformerAstBased.getResult();
assertEquals(query, result);
}
@Test
public void test() throws RecognitionException {
DomainModel model = prepareDomainModel();
QueryTransformerAstBased transformer = new QueryTransformerAstBased(model,
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.userGroup = :par",
"sec$GroupHierarchy");
transformer.addWhere("a.createdBy = :par1");
String res = transformer.getResult();
assertEquals(
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.userGroup = :par and h.createdBy = :par1",
res);
transformer = new QueryTransformerAstBased(model,
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.userGroup = ?1 " +
"group by c.level having c.level > 0 order by c.level",
"sec$GroupHierarchy");
transformer.addWhere("a.createdBy = :par1");
res = transformer.getResult();
assertEquals(
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.userGroup = ?1 " +
"and h.createdBy = :par1 group by c.level having c.level > 0 order by c.level",
res);
Set<String> set = transformer.getAddedParams();
assertEquals(1, set.size());
assertEquals("par1", set.iterator().next());
transformer.addWhere("(a.updatedBy = :par2 and a.groupId = :par3)");
res = transformer.getResult();
assertEquals(
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.userGroup = ?1 " +
"and h.createdBy = :par1 and ( h.updatedBy = :par2 and h.groupId = :par3) group by c.level having c.level > 0 order by c.level",
res);
set = transformer.getAddedParams();
assertEquals(3, set.size());
transformer.reset();
transformer.mergeWhere("select gh from sec$GroupHierarchy gh where gh.version between 1 and 2");
res = transformer.getResult();
assertEquals(
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.userGroup = ?1 " +
"and h.version between 1 and 2 group by c.level having c.level > 0 order by c.level",
res);
}
@Test
public void addWhereAsId() throws RecognitionException {
DomainModel model = prepareDomainModel();
QueryTransformerAstBased transformer = new QueryTransformerAstBased(model,
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.userGroup = :par",
"sec$GroupHierarchy");
transformer.addWhereAsIs("a.createdBy = :par1");
String res = transformer.getResult();
assertEquals(
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.userGroup = :par " +
"and a.createdBy = :par1",
res);
}
@Test
public void getResult_noChangesMade_parametersWithDot() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity teamEntity = builder.produceImmediately("Team", "name");
builder.startNewEntity("Player");
builder.addSingleValueAttribute(Date.class, "birthDate");
builder.addReferenceAttribute("team", "Team");
Entity playerEntity = builder.produce();
DomainModel model = new DomainModel(playerEntity, teamEntity);
QueryTransformerAstBased transformerAstBased = new QueryTransformerAstBased(model, "SELECT p FROM Player p where p.birthDate = :d.option", "Player");
String result = transformerAstBased.getResult();
assertEquals("SELECT p FROM Player p where p.birthDate = :d.option", result);
}
@Test
public void getResult_noChangesMade_orderBySeveralFields() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
Entity teamEntity = builder.produceImmediately("Team", "name");
builder.startNewEntity("Player");
builder.addSingleValueAttribute(Date.class, "birthDate");
builder.addStringAttribute("surname");
builder.addReferenceAttribute("team", "Team");
Entity playerEntity = builder.produce();
DomainModel model = new DomainModel(playerEntity, teamEntity);
QueryTransformerAstBased transformerAstBased = new QueryTransformerAstBased(model, "SELECT p FROM Player p order by p.birthDate, p.surname", "Player");
String result = transformerAstBased.getResult();
assertEquals("SELECT p FROM Player p order by p.birthDate, p.surname", result);
}
@Test
public void getResult_noChangesMade_join_fetch() throws RecognitionException {
DomainModel model = prepareDomainModel();
QueryTransformerAstBased transformer = new QueryTransformerAstBased(model,
"select h from sec$GroupHierarchy h join fetch h.parent.constraints where h.userGroup = :par",
"sec$GroupHierarchy");
String res = transformer.getResult();
assertEquals(
"select h from sec$GroupHierarchy h join fetch h.parent.constraints where h.userGroup = :par",
res);
}
@Test
public void addJoinAsId() throws RecognitionException {
DomainModel model = prepareDomainModel();
QueryTransformerAstBased transformer = new QueryTransformerAstBased(model,
"select h from sec$Constraint u, sec$GroupHierarchy h where h.userGroup = :par",
"sec$GroupHierarchy");
transformer.addJoinAsIs("join a.parent.constraints c");
String res = transformer.getResult();
assertEquals(
"select h from sec$Constraint u, sec$GroupHierarchy h join a.parent.constraints c where h.userGroup = :par",
res);
}
@Test
public void addWhere_with_child_select() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
builder.startNewEntity("Car");
builder.addStringAttribute("model");
builder.addReferenceAttribute("driver", "Person");
Entity car = builder.produce();
Entity person = builder.produceImmediately("Person", "fullname");
DomainModel model = new DomainModel(car, person);
QueryTransformerAstBased transformer = new QueryTransformerAstBased(model,
"select car.driver from Car car", "Car");
transformer.addWhere("{E}.model = ?1");
assertEquals("select car.driver from Car car where car.model = ?1",
transformer.getResult());
transformer = new QueryTransformerAstBased(model,
"select car.driver from Car car", "Person");
transformer.addWhere("{E}.fullname = ?1");
assertEquals("select car.driver from Car car where car.driver.fullname = ?1",
transformer.getResult());
}
private DomainModel prepareDomainModel() {
EntityBuilder builder = new EntityBuilder();
builder.startNewEntity("sec$GroupHierarchy");
builder.addStringAttribute("group");
builder.addStringAttribute("createdBy");
builder.addReferenceAttribute("parent", "sec$GroupHierarchy");
builder.addCollectionReferenceAttribute("constraints", "sec$Constraint");
Entity groupHierarchy = builder.produce();
Entity constraintEntity = builder.produceImmediately("sec$Constraint");
return new DomainModel(groupHierarchy, constraintEntity);
}
@Test
public void testAliasPlaceholder() throws RecognitionException {
DomainModel model = prepareDomainModel();
QueryTransformerAstBased transformer = new QueryTransformerAstBased(model,
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.group = :par",
"sec$GroupHierarchy");
transformer.addWhere("{E}.createdBy = :par1 and {E}.updatedBy = :par2");
String res = transformer.getResult();
assertEquals(
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.group = :par and h.createdBy = :par1" +
" and h.updatedBy = :par2",
res);
////////////////////////////////////
transformer = new QueryTransformerAstBased(model,
"select c from sec$GroupHierarchy h where h.group = :par",
"sec$GroupHierarchy");
transformer.addJoinAndWhere("join h.parent.constraints c", "{E}.createdBy = :par1 and {E}.updatedBy = :par2 and c.createTs = :par3");
res = transformer.getResult();
assertEquals(
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.group = :par and h.createdBy = :par1" +
" and h.updatedBy = :par2 and c.createTs = :par3",
res);
////////////////////////////////////
transformer = new QueryTransformerAstBased(model,
"select c from sec$GroupHierarchy h where h.group = :par",
"sec$GroupHierarchy");
transformer.addJoinAndWhere("join {E}.parent.constraints c", "{E}.createdBy = :par1 and {E}.updatedBy = :par2 and c.createTs = :par3");
res = transformer.getResult();
assertEquals(
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.group = :par and h.createdBy = :par1" +
" and h.updatedBy = :par2 and c.createTs = :par3",
res);
}
@Test
public void testInvalidEntity() throws RecognitionException {
DomainModel model = prepareDomainModel();
QueryTransformerAstBased transformer = new QueryTransformerAstBased(model,
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.group = ?1 " +
"group by c.level having c.level > 0 order by c.level", "sec$Group");
try {
transformer.addWhere("a.createdBy = :par1");
fail();
} catch (Exception e) {
assertTrue(e instanceof RuntimeException);
}
}
@Test
public void addWhere_adds_Where_IfNeeded() throws RecognitionException {
DomainModel model = prepareDomainModel();
QueryTransformerAstBased transformer = new QueryTransformerAstBased(model,
"select h from sec$GroupHierarchy h", "sec$GroupHierarchy");
transformer.addWhere("h.group = ?1");
assertEquals("select h from sec$GroupHierarchy h where h.group = ?1",
transformer.getResult());
transformer = new QueryTransformerAstBased(model,
"select h from sec$GroupHierarchy h join h.parent.constraints c", "sec$GroupHierarchy");
transformer.addWhere("h.group = ?1");
assertEquals("select h from sec$GroupHierarchy h join h.parent.constraints c where h.group = ?1",
transformer.getResult());
transformer = new QueryTransformerAstBased(model,
"select h from sec$GroupHierarchy h join h.parent.constraints c group by c.level having c.level > 0 order by c.level", "sec$GroupHierarchy");
transformer.addWhere("h.group = ?1");
assertEquals("select h from sec$GroupHierarchy h join h.parent.constraints c where h.group = ?1 group by c.level having c.level > 0 order by c.level",
transformer.getResult());
}
@Test
public void addWhere_onIncorrectHavingInTheEnd() throws RecognitionException {
DomainModel model = prepareDomainModel();
try {
new QueryTransformerAstBased(model,
"select h from sec$GroupHierarchy h join h.parent.constraints c group by c.level order by c.level having c.level > 0", "sec$GroupHierarchy");
fail("Incorrectly placed 'having' passed");
} catch (ErrorsFoundException e) {
}
}
@Test
public void addWhere_onIncorrectQuery() throws RecognitionException {
DomainModel model = prepareDomainModel();
try {
new QueryTransformerAstBased(model,
"select h from sec$GroupHierarchy h join h.parent.constraints", "sec$GroupHierarchy");
fail("Not named join variable passed");
} catch (ErrorsFoundException e) {
}
}
@Test
public void testJoin() throws RecognitionException {
DomainModel model = prepareDomainModel();
QueryTransformerAstBased transformer = new QueryTransformerAstBased(model,
"select c from sec$GroupHierarchy h where h.group = :par", "sec$GroupHierarchy");
transformer.addJoinAndWhere("join h.parent.constraints c", "c.createdBy = :par2");
String res = transformer.getResult();
assertEquals(
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.group = :par and c.createdBy = :par2",
res);
}
@Test
public void join_with_in_collections() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
builder.startNewEntity("HomeBase");
builder.addStringAttribute("name");
Entity homeBase = builder.produce();
builder.startNewEntity("Driver");
builder.addStringAttribute("name");
builder.addStringAttribute("signal");
builder.addReferenceAttribute("home", "HomeBase");
Entity driver = builder.produce();
builder.startNewEntity("Car");
builder.addStringAttribute("model");
builder.addCollectionReferenceAttribute("drivers", "Driver");
builder.addReferenceAttribute("station", "HomeBase");
Entity car = builder.produce();
DomainModel model = new DomainModel(car, driver, homeBase);
QueryTransformerAstBased transformer = new QueryTransformerAstBased(model,
"select d.name from Car c, in(c.drivers) d where d.signal = ?1", "Driver");
try {
transformer.addJoinAndWhere("join d.home h", "h.name = :par2");
fail();
} catch (Exception e) {
}
transformer = new QueryTransformerAstBased(model,
"select d.name from Car c, in(c.drivers) d where d.signal = ?1", "Car");
transformer.addJoinAndWhere("join c.station h", "h.name = :par2");
String res = transformer.getResult();
assertEquals(
"select d.name from Car c join c.station h, in(c.drivers) d where d.signal = ?1 and h.name = :par2",
res);
transformer = new QueryTransformerAstBased(model,
"select c, d from Car c, Driver d where d.signal = ?1", "Car");
transformer.addJoinAndWhere("join d.station h", "h.name = :par2");
res = transformer.getResult();
assertEquals(
"select c, d from Car c join c.station h, Driver d where d.signal = ?1 and h.name = :par2",
res);
transformer = new QueryTransformerAstBased(model,
"select c, d from Car c, Driver d where d.signal = ?1", "Driver");
transformer.addJoinAndWhere("join d.home h", "h.name = :par2");
res = transformer.getResult();
assertEquals(
"select c, d from Car c, Driver d join d.home h where d.signal = ?1 and h.name = :par2",
res);
}
@Test
public void testReplaceWithCount() throws RecognitionException {
DomainModel model = prepareDomainModel();
QueryTransformerAstBased transformer = new QueryTransformerAstBased(model,
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.group = ?1 " +
"group by c.level having c.level > 0 order by c.level", "sec$GroupHierarchy");
transformer.replaceWithCount();
assertEquals(
"select COUNT(h) from sec$GroupHierarchy h join h.parent.constraints c where h.group = ?1 " +
"group by c.level having c.level > 0",
transformer.getResult());
transformer = new QueryTransformerAstBased(model,
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.group = ?1 " +
"group by c.level having c.level > 0 order by c.level", "sec$Constraint");
transformer.replaceWithCount();
assertEquals(
"select COUNT(c) from sec$GroupHierarchy h join h.parent.constraints c where h.group = ?1 " +
"group by c.level having c.level > 0",
transformer.getResult());
}
@Test
public void testReplaceWithCount_distinct() throws RecognitionException {
DomainModel model = prepareDomainModel();
QueryTransformerAstBased transformer = new QueryTransformerAstBased(model,
"select distinct c from sec$GroupHierarchy h join h.parent.constraints c where h.group = ?1 " +
"group by c.level having c.level > 0 order by c.level", "sec$Constraint");
transformer.replaceWithCount();
String res = transformer.getResult();
assertEquals(
"select COUNT(DISTINCT c) from sec$GroupHierarchy h join h.parent.constraints c where h.group = ?1 " +
"group by c.level having c.level > 0",
res);
}
@Test
public void testOrderBy() throws RecognitionException {
DomainModel model = prepareDomainModel();
QueryTransformerAstBased transformer = new QueryTransformerAstBased(model,
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.group = ?1 " +
"group by h.level having h.level > 0 order by h.level", "sec$GroupHierarchy");
transformer.replaceOrderBy("group", false);
String res = transformer.getResult();
assertEquals(
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.group = ?1 " +
"group by h.level having h.level > 0 order by h.group",
res);
transformer.replaceOrderBy("group", true);
res = transformer.getResult();
assertEquals(
"select c from sec$GroupHierarchy h join h.parent.constraints c where h.group = ?1 " +
"group by h.level having h.level > 0 order by h.group DESC",
res);
}
@Test
public void transformationsUsingSelectedEntity() throws RecognitionException {
EntityBuilder builder = new EntityBuilder();
builder.startNewEntity("sec$Car");
builder.addStringAttribute("model");
builder.addReferenceAttribute("colour", "sec$Colour");
Entity car = builder.produce();
builder.startNewEntity("sec$Colour");
builder.addStringAttribute("name");
builder.addStringAttribute("createdBy");
builder.addSingleValueAttribute(Integer.class, "version");
builder.addReferenceAttribute("manufacturer", "Manufacturer");
Entity colour = builder.produce();
Entity manufacturer = builder.produceImmediately("Manufacturer", "companyName");
DomainModel model = new DomainModel(car, colour, manufacturer);
QueryTransformerAstBased transformer = new QueryTransformerAstBased(model,
"select c.colour from sec$Car c where c.colour.createdBy = :p", "sec$Colour");
transformer.addWhere("{E}.createdBy = :session$userLogin");
String res = transformer.getResult();
assertEquals(
"select c.colour from sec$Car c where c.colour.createdBy = :p and c.colour.createdBy = :session$userLogin",
res);
transformer = new QueryTransformerAstBased(model,
"select c.colour from sec$Car c where c.colour.createdBy = :p", "sec$Colour");
transformer.addJoinAndWhere("join {E}.manufacturer m", "m.companyName = :par1");
res = transformer.getResult();
assertEquals(
"select c.colour from sec$Car c join c.colour.manufacturer m where c.colour.createdBy = :p and m.companyName = :par1",
res);
transformer = new QueryTransformerAstBased(model,
"select c.colour from sec$Car c where c.colour.createdBy = :p", "sec$Colour");
transformer.mergeWhere("select gh from sec$Colour gh where gh.version between 1 and 2");
res = transformer.getResult();
assertEquals(
"select c.colour from sec$Car c where c.colour.createdBy = :p and c.colour.version between 1 and 2",
res);
transformer = new QueryTransformerAstBased(model,
"select c.colour from sec$Car c where c.colour.createdBy = :p order by c.colour.name", "sec$Colour");
transformer.replaceOrderBy("version", true);
res = transformer.getResult();
assertEquals(
"select c.colour from sec$Car c where c.colour.createdBy = :p order by c.colour.version DESC",
res);
transformer = new QueryTransformerAstBased(model,
"select c.colour from sec$Car c where c.colour.createdBy = :p", "sec$Colour");
transformer.replaceWithCount();
res = transformer.getResult();
assertEquals(
"select COUNT(c.colour) from sec$Car c where c.colour.createdBy = :p",
res);
}
}