package net.techreadiness.persistence.dao;
import java.util.Collection;
import java.util.List;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.SingularAttribute;
import net.techreadiness.persistence.domain.ScopeDO;
import net.techreadiness.persistence.domain.ScopeDO_;
import net.techreadiness.persistence.domain.ScopeTreeDO;
import net.techreadiness.persistence.domain.ScopeTreeDO_;
import net.techreadiness.persistence.domain.ScopeTypeDO;
import net.techreadiness.persistence.domain.ScopeTypeDO_;
import org.springframework.stereotype.Repository;
@Repository
public class ScopeDAOImpl extends BaseDAOImpl<ScopeDO> implements ScopeDAO {
@Override
public List<ScopeDO> findByParentPath(String scopePath) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<ScopeDO> cq = cb.createQuery(ScopeDO.class);
Root<ScopeTreeDO> root = cq.from(ScopeTreeDO.class);
Join<ScopeTreeDO, ScopeDO> j = root.join(ScopeTreeDO_.scope);
cq.select(j);
Predicate p = cb.equal(root.get(ScopeTreeDO_.ancestorPath), scopePath);
cq.where(p);
cq.orderBy(cb.asc(root.get(ScopeTreeDO_.ancestorPath)));
TypedQuery<ScopeDO> query = em.createQuery(cq);
query.setHint("org.hibernate.cacheable", Boolean.TRUE);
return getResultList(query);
}
@Override
public ScopeDO getByScopePath(String scopePath) {
TypedQuery<ScopeDO> query = em.createQuery("select s from ScopeDO s where s.path = :scopePath", ScopeDO.class);
query.setParameter("scopePath", scopePath);
query.setHint("org.hibernate.cacheable", Boolean.TRUE);
return getSingleResult(query);
}
@Override
public List<ScopeDO> getScopesWithNoParent() {
TypedQuery<ScopeDO> query = em.createQuery("select s from ScopeDO s where s.parentScope = null", ScopeDO.class);
return getResultList(query);
}
@Override
public List<ScopeDO> getAppRootScopes() {
TypedQuery<ScopeDO> query = em.createQuery("select st.scope from ScopeTreeDO st where st.depth=2 and distance=0",
ScopeDO.class);
return getResultList(query);
}
private CriteriaQuery<ScopeDO> getScopeCriteria(Long scopeId, SingularAttribute<ScopeTypeDO, Boolean> scopeTypeAttribute) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<ScopeDO> cq = cb.createQuery(ScopeDO.class);
Root<ScopeDO> root = cq.from(ScopeDO.class);
Join<ScopeDO, ScopeTypeDO> scopeType = root.join(ScopeDO_.scopeType);
Join<ScopeDO, ScopeTreeDO> scopeTree = root.join(ScopeDO_.ancestorScopeTrees);
Predicate typeClause = cb.equal(scopeType.get(scopeTypeAttribute), Short.valueOf("1"));
scopeTree.get(ScopeTreeDO_.scope);
Predicate pathClause = cb.equal(scopeTree.get(ScopeTreeDO_.scope).get(ScopeDO_.scopeId), scopeId);
Predicate notRoot = cb.isNotNull(root.get(ScopeDO_.parentScope));
cq.where(notRoot, typeClause, pathClause);
return cq;
}
@Override
public ScopeDO getTopLevelParent(Long scopeId) {
TypedQuery<ScopeDO> query = em.createQuery(
"select tree.scope from ScopeTreeDO tree where tree.ancestorDepth=2 and tree.scope.scopeId=:scopeId",
ScopeDO.class);
query.setParameter("scopeId", scopeId);
return getSingleResult(query);
}
@Override
public List<ScopeDO> getDescendantScopes(Long scopeId) {
StringBuilder sb = new StringBuilder();
sb.append("select s ");
sb.append("from ScopeDO s, ScopeTreeDO tree ");
sb.append("where s.scopeId = tree.scope.scopeId ");
sb.append("and tree.ancestorScope.scopeId =:scopeId ");
TypedQuery<ScopeDO> query = em.createQuery(sb.toString(), ScopeDO.class);
query.setParameter("scopeId", scopeId);
return query.getResultList();
}
@Override
public ScopeDO getScopeForUsers(Long scopeId) {
CriteriaQuery<ScopeDO> cq = getScopeCriteria(scopeId, ScopeTypeDO_.allowUser);
TypedQuery<ScopeDO> query = em.createQuery(cq);
return getSingleResult(query);
}
@Override
public Collection<ScopeDO> getAncestorsAndChildren(Long scopeId) {
StringBuilder sb = new StringBuilder();
sb.append("select distinct s from ScopeTreeDO st ");
sb.append("join st.scope s ");
sb.append("left join s.parentScope ");
sb.append("where st.ancestorScope.scopeId in ( ");
sb.append(" select ancestorScope.scopeId ");
sb.append(" from ScopeTreeDO sts ");
sb.append(" join sts.scope scope ");
sb.append(" join sts.ancestorScope ancestorScope ");
sb.append(" where scope.scopeId = :scopeId) ");
sb.append("and st.distance <= 1 ");
TypedQuery<ScopeDO> query = em.createQuery(sb.toString(), ScopeDO.class);
query.setParameter("scopeId", scopeId);
query.setHint("org.hibernate.cacheable", Boolean.TRUE);
return query.getResultList();
}
/**
* Given a scope point in the tree as identified by id, get:
* <ul>
* <li>the scope node itself</li>
* <li>any ancestor of that node</li>
* <li>any descendant of that node</li>
* </ul>
*
* @param scopeId
* The scope id
* @return The collection of scopes
*/
@Override
public Collection<ScopeDO> getAncestorsAndDescendants(Long scopeId) {
StringBuilder sb = new StringBuilder();
sb.append("select distinct s from ScopeTreeDO st ");
sb.append("join st.scope s ");
sb.append("left join s.parentScope ");
sb.append("where st.ancestorScope.scopeId in ( ");
sb.append(" select ancestorScope.scopeId ");
sb.append(" from ScopeTreeDO sts ");
sb.append(" join sts.scope scope ");
sb.append(" join sts.ancestorScope ancestorScope ");
sb.append(" where scope.scopeId = :scopeId) ");
sb.append("and ((st.distance <= 0) ");
sb.append(" or (st.ancestorScope.scopeId = :scopeId)) ");
TypedQuery<ScopeDO> query = em.createQuery(sb.toString(), ScopeDO.class);
query.setParameter("scopeId", scopeId);
query.setHint("org.hibernate.cacheable", Boolean.TRUE);
return query.getResultList();
}
@Override
public Collection<ScopeDO> findParentsOfScope(Long scopeId) {
TypedQuery<ScopeDO> query = em.createQuery(
"select tree.ancestorScope from ScopeTreeDO tree where tree.scope.scopeId = :scopeId", ScopeDO.class);
query.setParameter("scopeId", scopeId);
return query.getResultList();
}
@Override
public ScopeDO getScopeForOrgs(Long scopeId) {
CriteriaQuery<ScopeDO> cq = getScopeCriteria(scopeId, ScopeTypeDO_.allowOrg);
TypedQuery<ScopeDO> query = em.createQuery(cq);
return getSingleResult(query);
}
@Override
public List<ScopeDO> getChildScopesOfRoot() {
TypedQuery<ScopeDO> query = em.createQuery("select s from ScopeDO s where s.parentScope.scopeId = 1", ScopeDO.class);
return getResultList(query);
}
@Override
public ScopeDO getScopeForOrgParts(Long scopeId) {
CriteriaQuery<ScopeDO> cq = getScopeCriteria(scopeId, ScopeTypeDO_.allowOrgPart);
TypedQuery<ScopeDO> query = em.createQuery(cq);
return getSingleResult(query);
}
@Override
public List<ScopeDO> findDescendantScopes(Long scopeId, boolean allDescendants) {
TypedQuery<ScopeDO> query = em.createQuery("select tree.scope from ScopeTreeDO tree "
+ "where tree.ancestorScope.scopeId = :scopeId "
+ (allDescendants ? " and tree.distance > 0 " : " and tree.distance = 1 "), ScopeDO.class);
query.setParameter("scopeId", scopeId);
return query.getResultList();
}
}