Merge pull request #927 from querydsl/i910

Enforce unique aliases
This commit is contained in:
Timo Westkämper 2014-09-08 18:23:21 +03:00
commit e84c71fb82
5 changed files with 68 additions and 25 deletions

View File

@ -13,13 +13,17 @@
*/
package com.mysema.query.jpa;
import javax.persistence.Table;
import javax.persistence.Column;
import java.util.*;
import javax.persistence.Table;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.mysema.query.JoinExpression;
import com.mysema.query.QueryMetadata;
import com.mysema.query.sql.*;
@ -34,7 +38,7 @@ import com.mysema.query.types.*;
*/
public final class NativeSQLSerializer extends SQLSerializer {
private final Map<Expression<?>, String> aliases = Maps.newHashMap();
private final ListMultimap<Expression<?>, String> aliases = ArrayListMultimap.create();
private final boolean wrapEntityProjections;
@ -78,7 +82,7 @@ public final class NativeSQLSerializer extends SQLSerializer {
return expr instanceof Operation && ((Operation<?>)expr).getOperator() == Ops.ALIAS;
}
public Map<Expression<?>, String> getAliases() {
public ListMultimap<Expression<?>, String> getAliases() {
return aliases;
}

View File

@ -15,8 +15,10 @@ package com.mysema.query.jpa.hibernate.sql;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Sets;
import com.mysema.commons.lang.CloseableIterator;
import com.mysema.query.*;
import com.mysema.query.NonUniqueResultException;
@ -86,7 +88,8 @@ public abstract class AbstractHibernateSQLQuery<Q extends AbstractHibernateSQLQu
HibernateUtil.setConstants(query, serializer.getConstantToLabel(), queryMixin.getMetadata().getParams());
if (!forCount) {
Map<Expression<?>, String> aliases = serializer.getAliases();
ListMultimap<Expression<?>, String> aliases = serializer.getAliases();
Set<String> used = Sets.newHashSet();
// set entity paths
List<? extends Expression<?>> projection = queryMixin.getMetadata().getProjection();
Expression<?> proj = projection.get(0);
@ -95,13 +98,25 @@ public abstract class AbstractHibernateSQLQuery<Q extends AbstractHibernateSQLQu
if (isEntityExpression(expr)) {
query.addEntity(extractEntityExpression(expr).toString(), expr.getType());
} else if (aliases.containsKey(expr)) {
query.addScalar(aliases.get(expr));
for (String scalar : aliases.get(expr)) {
if (!used.contains(scalar)) {
query.addScalar(scalar);
used.add(scalar);
break;
}
}
}
}
} else if (isEntityExpression(proj)) {
query.addEntity(extractEntityExpression(proj).toString(), proj.getType());
} else if (aliases.containsKey(proj)) {
query.addScalar(aliases.get(proj));
for (String scalar : aliases.get(proj)) {
if (!used.contains(scalar)) {
query.addScalar(scalar);
used.add(scalar);
break;
}
}
}
// set result transformer, if projection is a FactoryExpression instance

View File

@ -13,8 +13,20 @@
*/
package com.mysema.query.jpa.sql;
import javax.annotation.Nullable;
import javax.persistence.EntityManager;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.Query;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.mysema.commons.lang.CloseableIterator;
import com.mysema.query.*;
import com.mysema.query.jpa.AbstractSQLQuery;
@ -30,15 +42,6 @@ import com.mysema.query.types.FactoryExpressionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import javax.persistence.EntityManager;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.Query;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* AbstractJPASQLQuery is the base class for JPA Native SQL queries
*
@ -113,19 +116,33 @@ public abstract class AbstractJPASQLQuery<Q extends AbstractJPASQLQuery<Q>> exte
query = entityManager.createNativeQuery(queryString);
}
if (!forCount) {
Map<Expression<?>, String> aliases = serializer.getAliases();
ListMultimap<Expression<?>, String> aliases = serializer.getAliases();
Set<String> used = Sets.newHashSet();
if (proj instanceof FactoryExpression) {
for (Expression<?> expr : ((FactoryExpression<?>)proj).getArgs()) {
if (isEntityExpression(expr)) {
queryHandler.addEntity(query, extractEntityExpression(expr).toString(), expr.getType());
} else if (aliases.containsKey(expr)) {
queryHandler.addScalar(query, aliases.get(expr), expr.getType());
for (String scalar : aliases.get(expr)) {
if (!used.contains(scalar)) {
queryHandler.addScalar(query, scalar, expr.getType());
used.add(scalar);
break;
}
}
}
}
} else if (isEntityExpression(proj)) {
queryHandler.addEntity(query, extractEntityExpression(proj).toString(), proj.getType());
} else if (aliases.containsKey(proj)) {
queryHandler.addScalar(query, aliases.get(proj), proj.getType());
for (String scalar : aliases.get(proj)) {
if (!used.contains(scalar)) {
queryHandler.addScalar(query, scalar, proj.getType());
used.add(scalar);
break;
}
}
}
}

View File

@ -12,10 +12,7 @@ import com.mysema.query.jpa.domain.QCat;
import com.mysema.query.jpa.domain.QCompany;
import com.mysema.query.jpa.domain.sql.SAnimal;
import com.mysema.query.sql.SQLSubQuery;
import com.mysema.query.types.ConstructorExpression;
import com.mysema.query.types.Expression;
import com.mysema.query.types.Projections;
import com.mysema.query.types.SubQueryExpression;
import com.mysema.query.types.*;
import com.mysema.query.types.expr.DateExpression;
import com.mysema.query.types.expr.Wildcard;
import com.mysema.testutil.ExcludeIn;
@ -249,6 +246,12 @@ public abstract class AbstractSQLTest {
}
}
@Test
public void Projections_DuplicateColumns() {
SAnimal cat = new SAnimal("cat");
assertEquals(1, query().from(cat).list(new QList(cat.count(), cat.count())).size());
}
@Test
public void Single_Result() {
query().from(cat).singleResult(cat.id);
@ -357,4 +360,5 @@ public abstract class AbstractSQLTest {
// print(rows);
}
}

View File

@ -213,6 +213,9 @@
<configuration>
<rules>
<requireBackwardCompatibility implementation="org.semver.enforcer.RequireBackwardCompatibility">
<excludes>
<exclude>com/mysema/query/jpa/NativeSQLSerializer</exclude>
</excludes>
<compatibilityType>BACKWARD_COMPATIBLE_USER</compatibilityType>
<dumpDetails>true</dumpDetails>
<publicOnly>true</publicOnly>