Skip to content

Commit

Permalink
Fixed Blazebit#120 - Implemented treat support. Still a work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
beikov committed Mar 31, 2017
1 parent 61d890b commit 9ccad47
Show file tree
Hide file tree
Showing 70 changed files with 2,817 additions and 2,707 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ public interface JpaProvider {
* Whether dereferencing a VALUE function expression is supported by the JPA provider.
*
* @return True if dereferencing is supported, false otherwise
* @since 1.2.0
*/
public boolean supportsCollectionValueDereference();

Expand Down Expand Up @@ -156,24 +155,43 @@ public interface JpaProvider {

/**
* Whether treating a from/root alias is supported.
* For example <code>SELECT TREAT(alias AS Subtype).property FROM ..</code>
*
* @return True if treating a from alias is supported, false otherwise
*/
public boolean supportsRootTreat();

/**
* Whether a treat join is supported.
* For example <code>SELECT ... FROM .. JOIN TREAT(alias.relation AS Subtype)</code>
*
* @return True if a treat join is supported, false otherwise
*/
public boolean supportsTreatJoin();

/**
* Whether a correlation path with a treat expression is supported.
* For example <code>SELECT (SELECT .. FROM TREAT(parent AS Subtype).relation) FROM ..</code>
*
* @return True if a treat in correlation expressions is supported, false otherwise
*/
public boolean supportsTreatCorrelation();

/**
* Whether a root treat in a join is supported.
* For example <code>SELECT ... FROM .. JOIN TREAT(alias AS Subtype).relation</code>
*
* @return True if a root treat in a join is supported, false otherwise
*/
public boolean supportsRootTreatJoin();

/**
* Whether a root treat in a treat join is supported.
* For example <code>SELECT ... FROM .. JOIN TREAT(TREAT(alias AS Subtype).relation AS Subtype)</code>
*
* @return True if a root treat in a treat join is supported, false otherwise
*/
public boolean supportsRootTreatJoin();
public boolean supportsRootTreatTreatJoin();

/**
* Whether properties accessed of a from node are implicitly resolved to properties of a subtype of the from node.
Expand All @@ -182,6 +200,13 @@ public interface JpaProvider {
*/
public boolean supportsSubtypePropertyResolving();

/**
* Whether relations of a from node in joins are implicitly resolved to the relations of a subtype of the from node.
*
* @return True if subtype relation resolving is supported, false otherwise
*/
public boolean supportsSubtypeRelationResolving();

/**
* Whether the <code>COUNT(*)</code> syntax is supported.
*
Expand All @@ -192,11 +217,21 @@ public interface JpaProvider {
/**
* Whether the join columns for the given attribute are in a foreign table.
*
* @param ownerClass The owner of the attribute
* @param ownerType The owner of the attribute
* @param attributeName The attribute name to check
* @return True if join columns are in a foreign table, false otherwise
*/
public boolean isForeignJoinColumn(ManagedType<?> ownerClass, String attributeName);
public boolean isForeignJoinColumn(ManagedType<?> ownerType, String attributeName);

/**
* Whether columns for the given attribute are shared between multiple subtypes
* or shared by occupying the same slot in the resulting SQL.
*
* @param ownerType The owner of the attribute
* @param attributeName The attribute name to check
* @return True if columns of the attribute are shared, false otherwise
*/
public boolean isColumnShared(ManagedType<?> ownerType, String attributeName);

/**
* Whether the given attribute is a collection that uses a join table.
Expand Down Expand Up @@ -235,7 +270,6 @@ public interface JpaProvider {
* The value is not yet used but will be in a future version. Also see: https://github.com/Blazebit/blaze-persistence/issues/402
*
* @return true if supported, else false
* @since 1.2.0
*/
public boolean supportsForeignAssociationInOnClause();

Expand All @@ -244,7 +278,6 @@ public interface JpaProvider {
* Indicates if the provider supports the use of transient entity objects as parameters.
*
* @return true if supported, else false
* @since 1.2.0
*/
public boolean supportsTransientEntityAsParameter();

Expand All @@ -253,8 +286,7 @@ public interface JpaProvider {
* If needed, an expression like <code>alias.association</code> in the ON clause is rewritten to
* <code>alias.association.id</code>.
*
* @return true if supported, else false
* @since 1.2.0
* @return true if required, else false
*/
public boolean needsAssociationToIdRewriteInOnClause();

Expand All @@ -263,8 +295,16 @@ public interface JpaProvider {
* If needed, an expression like <code>alias.association</code> in the ON clause is rewritten to
* <code>alias.association.id</code> which relies on a <i>broken</i> type check in older Hibernate versions.
*
* @return true if supported, else false
* @since 1.2.0
* @return true if required, else false
*/
public boolean needsBrokenAssociationToIdRewriteInOnClause();

/**
* Indicates if the provider does <i>column sharing</i> for same named columns in inheritance mappings
* and thus requires the use of a CASE WHEN expression for restricting casted accesses like e.g. <code>TREAT(alias AS Subtype).property</code>
* to retain cast semantics.
*
* @return true if required, else false
*/
public boolean needsTypeConstraintForColumnSharing();
}
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,7 @@ public boolean isEmpty() {
!fromClassExplicitelySet
&& joinManager.getRoots().size() == 1
&& joinManager.getRoots().get(0).getNodes().isEmpty()
&& joinManager.getRoots().get(0).getTreatedJoinNodes().isEmpty()
&& joinManager.getRoots().get(0).getEntityJoinNodes().isEmpty()
)
;
Expand Down Expand Up @@ -1570,7 +1571,7 @@ protected List<EntityFunctionNode> getEntityFunctionNodes(Query baseQuery) {
String valuesAliases = node.getValuesAliases();

String valuesTableSqlAlias = cbf.getExtendedQuerySupport().getSqlAlias(em, baseQuery, node.getAlias());
entityFunctionNodes.add(new EntityFunctionNode(valuesClause, valuesAliases, node.getPropertyClass(), valuesTableSqlAlias, node.getValueQuery()));
entityFunctionNodes.add(new EntityFunctionNode(valuesClause, valuesAliases, node.getType(), valuesTableSqlAlias, node.getValueQuery()));
}
return entityFunctionNodes;
}
Expand Down Expand Up @@ -1785,7 +1786,7 @@ protected void prepareAndCheck() {
joinManager.acceptVisitor(new JoinNodeVisitor() {
@Override
public void visit(JoinNode node) {
Class<?> cteType = node.getPropertyClass();
Class<?> cteType = node.getType();
// Except for VALUES clause from nodes, every cte type must be defined
if (node.getValueQuery() == null && mainQuery.metamodel.getCte(cteType) != null) {
if (mainQuery.cteManager.getCte(cteType) == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ private void checkEntityId(Object entityId) {
throw new IllegalArgumentException("Invalid null entity id given");
}

EntityType<?> entityType = mainQuery.metamodel.entity(joinManager.getRootNodeOrFail("Paginated queries do not support multiple from clause elements!").getPropertyClass());
EntityType<?> entityType = mainQuery.metamodel.entity(joinManager.getRootNodeOrFail("Paginated queries do not support multiple from clause elements!").getType());
Attribute<?, ?> idAttribute = JpaUtils.getIdAttribute(entityType);
Class<?> idType = JpaUtils.resolveFieldClass(entityType.getJavaType(), idAttribute);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.BasicType;
import javax.persistence.metamodel.EmbeddableType;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.ManagedType;
Expand All @@ -37,6 +38,8 @@
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
* This is a wrapper around the JPA {@link Metamodel} allows additionally efficient access by other attributes than a Class.
Expand All @@ -50,7 +53,8 @@ public class EntityMetamodelImpl implements EntityMetamodel {
private final Map<String, EntityType<?>> entityNameMap;
private final Map<String, Class<?>> entityTypes;
private final Map<String, Class<Enum<?>>> enumTypes;
private final Map<Class<?>, ManagedType<?>> classMap;
private final Map<Class<?>, Type<?>> classMap;
private final ConcurrentMap<Class<?>, Type<?>> basicTypeMap = new ConcurrentHashMap<>();
private final Map<Class<?>, ManagedType<?>> cteMap;
private final Map<Class<?>, Map<String, Map.Entry<AttributePath, String[]>>> typeAttributeColumnNameMap;
private final Map<Class<?>, Map<String, Map.Entry<AttributePath, String[]>>> typeAttributeColumnTypeMap;
Expand All @@ -61,7 +65,7 @@ public EntityMetamodelImpl(EntityManagerFactory emf, ExtendedQuerySupport extend
Map<String, EntityType<?>> nameToType = new HashMap<>(managedTypes.size());
Map<String, Class<?>> entityTypes = new HashMap<>(managedTypes.size());
Map<String, Class<Enum<?>>> enumTypes = new HashMap<>(managedTypes.size());
Map<Class<?>, ManagedType<?>> classToType = new HashMap<>(managedTypes.size());
Map<Class<?>, Type<?>> classToType = new HashMap<>(managedTypes.size());
Map<Class<?>, ManagedType<?>> cteToType = new HashMap<>(managedTypes.size());
Map<Class<?>, Map<String, Map.Entry<AttributePath, String[]>>> typeAttributeColumnNames = new HashMap<>(managedTypes.size());
Map<Class<?>, Map<String, Map.Entry<AttributePath, String[]>>> typeAttributeColumnTypeNames = new HashMap<>(managedTypes.size());
Expand Down Expand Up @@ -200,6 +204,14 @@ public <X> EntityType<X> entity(Class<X> cls) {
return delegate.entity(cls);
}

public EntityType<?> entity(String name) {
EntityType<?> type = entityNameMap.get(name);
if (type == null) {
throw new IllegalArgumentException("Invalid entity type: " + name);
}
return type;
}

@Override
public EntityType<?> getEntity(String name) {
return entityNameMap.get(name);
Expand All @@ -223,6 +235,22 @@ public <X> ManagedType<X> managedType(Class<X> cls) {
return delegate.managedType(cls);
}

@Override
@SuppressWarnings({ "unchecked" })
public <X> Type<X> type(Class<X> cls) {
Type<?> type = classMap.get(cls);
if (type != null) {
return (Type<X>) type;
}

type = new BasicTypeImpl<>(cls);
Type<?> oldType = basicTypeMap.putIfAbsent(cls, type);
if (oldType != null) {
type = oldType;
}
return (Type<X>) type;
}

@Override
public ManagedType<?> managedType(String name) {
ManagedType<?> t = entityNameMap.get(name);
Expand All @@ -233,15 +261,16 @@ public ManagedType<?> managedType(String name) {
return t;
}

@SuppressWarnings({ "unchecked" })
@Override
@SuppressWarnings({ "unchecked" })
public <X> ManagedType<X> getManagedType(Class<X> cls) {
return (ManagedType<X>) classMap.get(cls);
}

@Override
@SuppressWarnings({ "unchecked" })
public <X> EntityType<X> getEntity(Class<X> cls) {
ManagedType<?> type = classMap.get(cls);
Type<?> type = classMap.get(cls);
if (type == null || !(type instanceof EntityType<?>)) {
return null;
}
Expand Down Expand Up @@ -273,4 +302,23 @@ public Set<EntityType<?>> getEntities() {
public Set<EmbeddableType<?>> getEmbeddables() {
return delegate.getEmbeddables();
}

private static class BasicTypeImpl<T> implements BasicType<T> {

private final Class<T> cls;

public BasicTypeImpl(Class<T> cls) {
this.cls = cls;
}

@Override
public PersistenceType getPersistenceType() {
return PersistenceType.BASIC;
}

@Override
public Class<T> getJavaType() {
return cls;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public void visit(PathExpression expression) {
* selects here
*/
JoinNode baseNode = ((JoinNode) expression.getBaseNode());
EntityType<?> entityType = m.getEntity(baseNode.getPropertyClass());
EntityType<?> entityType = m.getEntity(baseNode.getType());
if (entityType == null) {
// ignore if the expression is not an entity
return;
Expand Down Expand Up @@ -101,7 +101,7 @@ public int compare(Attribute<?, ?> o1, Attribute<?, ?> o2) {

if (resolve) {
PathExpression attrPath = new PathExpression(new ArrayList<PathElementExpression>(expression.getExpressions()));
attrPath.setPathReference(new SimplePathReference(baseNode, attr.getName(), null, JpaUtils.resolveFieldClass(entityClass, attr)));
attrPath.setPathReference(new SimplePathReference(baseNode, attr.getName(), JpaUtils.resolveFieldClass(entityClass, attr)));
pathExpressions.add(attrPath);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ public String getAbsolutePath() {
}
}

public void render(StringBuilder sb) {
sb.append(alias);
}

public boolean isImplicit() {
return implicit;
}
Expand Down
Loading

0 comments on commit 9ccad47

Please sign in to comment.