mirror of
https://gitee.com/jmix/cuba.git
synced 2024-12-03 19:57:36 +08:00
This commit is contained in:
parent
f09a6091a8
commit
0a668b03d0
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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() {
|
||||
|
@ -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");
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -15,4 +15,9 @@ public class ErrorRec {
|
||||
this.node = node;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return message + "[" + node.toString() + "]";
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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() {
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -55,8 +55,4 @@ public class HintResponse {
|
||||
public String getLastWord() {
|
||||
return lastWord;
|
||||
}
|
||||
|
||||
public String getOptionDescription(String option) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user