Skip to content

Commit

Permalink
improvement jpql implementatio with projections.
Browse files Browse the repository at this point in the history
  • Loading branch information
tglman committed Feb 28, 2012
1 parent 0b203c2 commit f656467
Show file tree
Hide file tree
Showing 4 changed files with 277 additions and 19 deletions.
1 change: 1 addition & 0 deletions .classpath
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry excluding="**/.svn/**" kind="src" output="build/src" path="src"/>
<classpathentry kind="src" output="build/test" path="test"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?ivyXmlPath=ivy.xml&amp;confs=*"/>
<classpathentry kind="output" path="build"/>
Expand Down
1 change: 1 addition & 0 deletions ivy.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@
<dependency org="org.datanucleus" name="datanucleus-rdbms" rev="latest.integration" conf="*->default" />
<dependency org="org.datanucleus" name="datanucleus-api-jdo" rev="latest.integration" conf="*->default" />
<dependency org="javax.jdo" name="jdo-api" rev="latest.integration" conf="*->default" />
<dependency org="junit" name="junit" rev="latest.integration" conf="test->default" />
</dependencies>
</ivy-module>
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package org.romaframework.aspect.persistence.datanucleus.jdo;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

Expand All @@ -13,8 +16,14 @@
import org.romaframework.aspect.persistence.QueryByFilterItem;
import org.romaframework.aspect.persistence.QueryByFilterItemGroup;
import org.romaframework.aspect.persistence.QueryByFilterItemPredicate;
import org.romaframework.aspect.persistence.QueryByFilterItemReverse;
import org.romaframework.aspect.persistence.QueryByFilterItemText;
import org.romaframework.aspect.persistence.QueryByFilterProjection;
import org.romaframework.aspect.persistence.QueryByText;
import org.romaframework.aspect.persistence.QueryOperator;
import org.romaframework.aspect.persistence.QueryByFilterProjection.ProjectionOperator;
import org.romaframework.core.Roma;
import org.romaframework.core.schema.SchemaField;

public class JPQLQueryEngine implements QueryEngine {

Expand All @@ -37,25 +46,30 @@ public long countByText(PersistenceManager manager, QueryByText queryInput) {
}

public List<?> queryByExample(PersistenceManager manager, QueryByExample queryInput) {
// TODO Auto-generated method stub
return null;
return queryByFilter(manager, buildQueryByFilter(queryInput));
}

public List<?> queryByFilter(PersistenceManager manager, QueryByFilter queryInput) {

return null;
StringBuilder stringQuery = new StringBuilder();
List<Object> params = new ArrayList<Object>();
buildQuery(queryInput, stringQuery, params);
Query query = createQuery(manager, stringQuery.toString());
return executeQuery(manager, query, queryInput, params);
}

public List<?> queryByText(PersistenceManager manager, QueryByText queryInput) {
Query query = createQuery(manager, queryInput.getText());
return executeQuery(manager, query, queryInput);
return executeQuery(manager, query, queryInput, null);
}

public List<?> executeQuery(PersistenceManager manager, Query query, org.romaframework.aspect.persistence.Query queryInput) {
public List<?> executeQuery(PersistenceManager manager, Query query, org.romaframework.aspect.persistence.Query queryInput, List<Object> params) {
if (queryInput.getRangeFrom() > -1 && queryInput.getRangeTo() > -1)
query.setRange(queryInput.getRangeFrom(), queryInput.getRangeTo());

List<?> result = (List<?>) query.execute();
List<?> result;
if (params == null || params.isEmpty())
result = (List<?>) query.execute();
else
result = (List<?>) query.executeWithArray(params.toArray());

byte strategy = queryInput.getStrategy();

Expand All @@ -73,25 +87,156 @@ public List<?> executeQuery(PersistenceManager manager, Query query, org.romafra
return result;
}

public void buildQuery(QueryByFilter filter, StringBuilder query, Map<String, Object> params) {
List<Class<?>> froms = new ArrayList<Class<?>>();
froms.add(filter.getCandidateClass());
if (filter.getItems() != null) {
for (QueryByFilterItem item : filter.getItems()) {
if (item instanceof QueryByFilterItemGroup) {

} else if (item instanceof QueryByFilterItemPredicate) {
public void buildQuery(QueryByFilter filter, StringBuilder query, List<Object> params) {
StringBuilder where = new StringBuilder();
Map<Character, Class<?>> froms = new HashMap<Character, Class<?>>();
if (!filter.getItems().isEmpty()) {
where.append(" where ");
buildWhere(where, filter.getItems(), params, filter.getPredicateOperator(), 'A', froms);
}
query.append("select ");
if (!filter.getProjections().isEmpty()) {
buildProjection(query, filter.getProjections(), 'A');
}
query.append(" from ").append(filter.getCandidateClass().getName()).append(" A");
for (Map.Entry<Character, Class<?>> from : froms.entrySet()) {
query.append(',').append(from.getValue().getName()).append(' ').append(from.getKey());
}
query.append(where);
}

}else if (item instanceof QueryByFilterItemText) {
public void buildProjection(StringBuilder pro, List<QueryByFilterProjection> projections, char alias) {
if (projections != null) {
Iterator<QueryByFilterProjection> projectionI = projections.iterator();
while (projectionI.hasNext()) {
QueryByFilterProjection projection = projectionI.next();
resolveProjection(pro, projection.getField(), projection.getOperator(), alias);
if (projectionI.hasNext())
pro.append(',');
}
}
}

}else if (item instanceof QueryByFilterItemReverse) {
private void resolveProjection(StringBuilder build, String filed, ProjectionOperator oper, char alias) {
switch (oper) {
case AVG:
build.append("AVG(").append(alias).append('.').append(filed).append(')');
break;
case COUNT:
build.append("COUNT(").append(alias).append('.').append(filed).append(')');
break;
case MAX:
build.append("MAX(").append(alias).append('.').append(filed).append(')');
break;
case MIN:
build.append("MIN(").append(alias).append('.').append(filed).append(')');
break;
case PLAIN:
build.append(alias).append('.').append(filed);
break;
}
}

public void buildWhere(StringBuilder where, List<QueryByFilterItem> items, List<Object> params, String predicate, char alias, Map<Character, Class<?>> froms) {
if (items == null)
return;
Iterator<QueryByFilterItem> iter = items.iterator();
while (iter.hasNext()) {
QueryByFilterItem item = iter.next();
if (item instanceof QueryByFilterItemGroup) {
if (((QueryByFilterItemGroup) item).getItems() == null && ((QueryByFilterItemGroup) item).getItems().isEmpty())
continue;
where.append("(");
buildWhere(where, ((QueryByFilterItemGroup) item).getItems(), params, ((QueryByFilterItemGroup) item).getPredicate(), alias, froms);
where.append(")");
} else if (item instanceof QueryByFilterItemPredicate) {
where.append(alias).append(".").append(((QueryByFilterItemPredicate) item).getFieldName());
where.append(getJPQLOperator(((QueryByFilterItemPredicate) item).getFieldOperator()));
params.add(((QueryByFilterItemPredicate) item).getFieldValue());
where.append('?').append(params.size());
} else if (item instanceof QueryByFilterItemText) {
where.append(alias).append(".").append(((QueryByFilterItemText) item).getCondition());
} else if (item instanceof QueryByFilterItemReverse) {
String field = ((QueryByFilterItemReverse) item).getField();
char newAlias = alias;
newAlias++;
where.append(newAlias).append(".").append(field);
where.append(getJPQLOperator(((QueryByFilterItemReverse) item).getOperator()));
where.append(alias);
QueryByFilter qbf = ((QueryByFilterItemReverse) item).getQueryByFilter();
froms.put(newAlias, qbf.getCandidateClass());
if (qbf.getItems().size() > 0) {
where.append(" ").append(predicate).append(" ");
}
buildWhere(where, qbf.getItems(), params, qbf.getPredicateOperator(), newAlias, froms);
}
if (iter.hasNext())
where.append(" ").append(predicate).append(" ");
}
}

// query.append("select ");
private String getJPQLOperator(QueryOperator operator) {
switch (operator) {
case CONTAINS:
case IN:
return " IN ";
case LIKE:
return " LIKE ";
case EQUALS:
return " = ";
case MAJOR_EQUALS:
return " >= ";
case MAJOR:
return " > ";
case MINOR:
return " < ";
case MINOR_EQUALS:
return " <= ";
case NOT_EQUALS:
return " <> ";
case NOT_IN:
return " NOT IN ";
}
return "";
}

protected QueryByFilter buildQueryByFilter(QueryByExample iQuery) {

QueryByFilter filter = new QueryByFilter(iQuery.getCandidateClass());
filter.setRangeFrom(iQuery.getRangeFrom(), iQuery.getRangeTo());
filter.setSubClasses(iQuery.isSubClasses());
filter.setMode(iQuery.getMode());
filter.setStrategy(iQuery.getStrategy());

if (iQuery.getFilter() != null) {
Iterator<SchemaField> sf = Roma.schema().getSchemaClass(iQuery.getCandidateClass()).getFieldIterator();
Object fieldValue;
QueryOperator operator = null;
while (sf.hasNext()) {
SchemaField field = sf.next();
fieldValue = field.getValue(iQuery.getFilter());
if (fieldValue != null) {
if (fieldValue instanceof Collection<?> || fieldValue instanceof Map<?, ?>)
continue;
if (fieldValue instanceof String && ((String) fieldValue).length() == 0)
continue;

if (String.class.equals(field.getLanguageType()))
operator = QueryByFilter.FIELD_LIKE;
else
operator = QueryByFilter.FIELD_EQUALS;

filter.addItem(field.getName(), operator, fieldValue);
}
}
}

QueryByFilter addFilter = iQuery.getAdditionalFilter();
if (addFilter != null) {
filter.setSubClasses(addFilter.isSubClasses());
filter.merge(addFilter);
}
return filter;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package org.romaframework.aspect.persistence.datanucleus.test;

import java.util.ArrayList;
import java.util.List;

import junit.framework.Assert;

import org.junit.Test;
import org.romaframework.aspect.persistence.QueryByFilter;
import org.romaframework.aspect.persistence.QueryByFilterItemReverse;
import org.romaframework.aspect.persistence.QueryOperator;
import org.romaframework.aspect.persistence.datanucleus.jdo.JPQLQueryEngine;
import org.romaframework.core.Roma;

public class TestJPQLQueryEngine {

public void beforeClass() {

}

@Test
public void testGenerateSimple() {

JPQLQueryEngine qe = new JPQLQueryEngine();
QueryByFilter qbf = new QueryByFilter(Roma.class);
qbf.addItem("test", QueryOperator.EQUALS, true);
qbf.addItem("test2", QueryOperator.EQUALS, new Object());
StringBuilder query = new StringBuilder();
List<Object> params = new ArrayList<Object>();

qe.buildQuery(qbf, query, params);

Assert.assertEquals(replaceSpaces("select from org.romaframework.core.Roma A where A.test = ?1 and A.test2 = ?2"), replaceSpaces(query.toString()));
Assert.assertEquals(params.size(), 2);
}

@Test
public void testGenerateComplex() {

JPQLQueryEngine qe = new JPQLQueryEngine();
QueryByFilter qbf = new QueryByFilter(Roma.class);
qbf.addItem("test", QueryOperator.EQUALS, true);
qbf.addItem("test2", QueryOperator.EQUALS, new Object());
qbf.addItem("test3", QueryOperator.LIKE, new Object());
qbf.addItem("test3", QueryOperator.NOT_EQUALS, new Object());
qbf.addItem("test3", QueryOperator.IN, new Object());
StringBuilder query = new StringBuilder();
List<Object> params = new ArrayList<Object>();
qe.buildQuery(qbf, query, params);

Assert.assertEquals(replaceSpaces("select from org.romaframework.core.Roma A where A.test = ?1 and A.test2 = ?2 and A.test3 LIKE ?3 and A.test3 <> ?4 and A.test3 IN ?5"),
replaceSpaces(query.toString()));
Assert.assertEquals(params.size(), 5);
}

@Test
public void testGenerateFull() {

JPQLQueryEngine qe = new JPQLQueryEngine();
QueryByFilter qbf = new QueryByFilter(Roma.class);
qbf.addItem("test", QueryOperator.EQUALS, true);
qbf.addItem("test", QueryOperator.CONTAINS, new Object());
qbf.addItem("test", QueryOperator.IN, new Object());
qbf.addItem("test", QueryOperator.LIKE, new Object());
qbf.addItem("test", QueryOperator.MAJOR, new Object());
qbf.addItem("test", QueryOperator.MAJOR_EQUALS, new Object());
qbf.addItem("test", QueryOperator.MINOR, new Object());
qbf.addItem("test", QueryOperator.MINOR_EQUALS, new Object());
qbf.addItem("test", QueryOperator.NOT_EQUALS, new Object());
qbf.addItem("test", QueryOperator.NOT_IN, new Object());

StringBuilder query = new StringBuilder();
List<Object> params = new ArrayList<Object>();
qe.buildQuery(qbf, query, params);

Assert
.assertEquals(
replaceSpaces("select from org.romaframework.core.Roma A where A.test = ?1 and A.test IN ?2 and A.test IN ?3 and A.test LIKE ?4 and A.test > ?5 and A.test >= ?6 and A.test < ?7 and A.test <= ?8 and A.test <> ?9 and A.test NOT IN ?10"),
replaceSpaces(query.toString()));
Assert.assertEquals(params.size(), 10);
}

@Test
public void testGenerateReverse() {

JPQLQueryEngine qe = new JPQLQueryEngine();
QueryByFilter qbf = new QueryByFilter(Roma.class);
qbf.addItem("test", QueryOperator.EQUALS, true);
QueryByFilter qbf1 = new QueryByFilter(Roma.class);
qbf1.addItem("name", QueryOperator.EQUALS, true);
qbf.addItem(new QueryByFilterItemReverse(qbf1, "refer", QueryOperator.EQUALS));
qbf.addItem("name", QueryOperator.EQUALS, true);
StringBuilder query = new StringBuilder();
List<Object> params = new ArrayList<Object>();
qe.buildQuery(qbf, query, params);

Assert.assertEquals(replaceSpaces("select from org.romaframework.core.Roma A,org.romaframework.core.Roma B where A.test = ?1 and B.refer = A and B.name = ?2 and A.name = ?3"),
replaceSpaces(query.toString()));
Assert.assertEquals(params.size(), 3);
}

private String replaceSpaces(String toReplace) {
int size;
do {
size = toReplace.length();
toReplace = toReplace.replace(" ", " ");

} while (size != toReplace.length());
return toReplace;
}
}

0 comments on commit f656467

Please sign in to comment.