package io.robe.hibernate.criteria.query; import io.robe.common.service.search.model.SearchModel; import io.robe.common.utils.Validations; import io.robe.common.utils.reflection.Fields; import io.robe.hibernate.criteria.api.*; import io.robe.hibernate.criteria.api.cache.FieldMeta; import io.robe.hibernate.criteria.api.criterion.Restrictions; import io.robe.hibernate.criteria.api.projection.ProjectionList; import io.robe.hibernate.criteria.api.projection.Projections; import java.util.*; /** * Created by kamilbukum on 10/01/2017. */ public class Query<E> { /** * provides to transform criteria to query */ private Transformer<E> transformer; /** * * @param transformer */ public Query(Transformer<E> transformer) { this.transformer = transformer; } /** * * @param entityClass * @param search * @return */ public Criteria<E> createCriteria(Class<?> entityClass, SearchModel search) { Criteria<E> criteria = Criteria.createCriteria(entityClass, transformer); if(search == null) { return criteria; } if(search.getQ() != null && search.getQ().length() > 0) { String[] queries = new String[]{search.getQ()}; QueryUtility.configureCriteriaByQ(criteria, queries); } if(search.getFilter() != null && search.getFilter().length > 0) { QueryUtility.configureFilters(criteria, search.getFilter(), 0); } if(search.getSort() != null && search.getSort().length > 0) { QueryUtility.configureSorts(criteria, search.getSort()); } QueryUtility.configureSelectFields(criteria, search); if(search.getLimit() != null) { criteria.setLimit(search.getLimit()); } if(search.getOffset() != null) { criteria.setOffset(search.getOffset()); } return criteria; } public static <E> void addRestrictions(Criteria<E> criteria, String[][] filters){ if(filters != null && filters.length > 0) { for(String[] filter: filters) { if(filter == null || filter.length == 0) continue; String name = filter[0]; if(Validations.isEmptyOrNull(name)) continue; String op = filter.length > 1 ? filter[1]: null; String rawValue = filter.length > 2 ? filter[2]: null; Holder<E> holder = configureFieldByName(criteria, name); if(holder == null) continue; FieldMeta fieldMeta = holder.currentFieldMeta; Object value = Validations.isEmptyOrNull(rawValue) ? null: getValue(op, rawValue, fieldMeta.getField().getType()); addRestriction(holder, op, value); } } } private static <E> void addRestriction(Holder<E> holder, String op, Object value){ if(holder.currentFieldMeta.isCollection()) { CriteriaJoin<E> criteriaJoin = holder.currentCriteria.getJoin(holder.currentFieldName); if(criteriaJoin == null) { holder.currentCriteria.createJoin(holder.currentFieldName, String.class); } criteriaJoin.add(Restrictions.filter(holder.currentFieldName, op, value)); } else { holder.currentCriteria.add(Restrictions.filter(holder.currentFieldName, op, value)); } } public static <E> void addProjections(Criteria<E> criteria, String[] projections){ if(projections != null && projections.length > 0) { for(String projection: projections) { // if projection is empty then ignore it if(Validations.isEmptyOrNull(projection)) continue; Holder<E> holder = configureFieldByName(criteria, projection); if(holder == null) continue; ProjectionList projectionList = null; if(holder.currentCriteria.getProjection() != null) { if(!(holder.currentCriteria.getProjection() instanceof ProjectionList)) { projectionList = Projections.projectionList(); holder.currentCriteria.setProjection(projectionList.add(holder.currentCriteria.getProjection())); } } else { projectionList = Projections.projectionList(); holder.currentCriteria.setProjection(projectionList.add(projectionList)); } projectionList.add(Projections.property(projection)); } } } public static <E> void addOrder(Criteria<E> criteria, String[] sorts){ if(sorts != null && sorts.length > 0) { for(String sort: sorts) { // if projection is empty then ignore it sort = checkStringAndTrim(sort); if(sort == null) continue; if(sort.length() < 2) continue; String op = sort.substring(0, 1); Order.Type type = Order.Type.value(op); sort = sort.substring(1); Holder<E> holder = configureFieldByName(criteria, sort); if(holder == null) continue; Order order = type == Order.Type.ASC ? Order.asc(holder.currentFieldName): Order.desc(holder.currentFieldName); holder.currentCriteria.addOrder(order); } } } private static class Holder<T> { private String currentFieldName; private CriteriaParent<T> currentCriteria; private FieldMeta currentFieldMeta; } public static String checkStringAndTrim(String name){ if(name != null) { name = name.trim(); if(name.equals("")) return null; } return name; } // roleOid.name // roleOid.permissionOid.name // roleOid.permissionOid.code public static <E> Holder<E> configureFieldByName(Criteria<E> criteria, String name){ if(Validations.isEmptyOrNull(name)) return null; // parse x.y name as [x, y] String[] names = name.split("\\."); // uses to keep current name by names index. String currentName; // init start index of names. int step = 0; // always will be current criteria CriteriaParent<E> currentCriteria = criteria; FieldMeta currentFieldMeta; // use aliasJoiner to use as alias. StringJoiner aliasJoiner = new StringJoiner("$"); do { // get current name of field by index. like x.y.z => if step = 1 then currentName = y currentName = names[step]; if(Validations.isEmptyOrNull(currentName)) { throw new RuntimeException(currentName + " defined name is wrong ! "); } currentFieldMeta = criteria.getMeta().getFieldMap().get(currentName); step++; aliasJoiner.add(currentCriteria.getAlias()); if(step >= names.length) { break; } if(currentFieldMeta.getReference() == null) { throw new RuntimeException("" + currentName + " join field of " + name + "'s reference target information must defined ! "); } CriteriaJoin<E> criteriaJoin = currentCriteria.getJoin(currentName); if(criteriaJoin == null) { currentCriteria.createJoin(currentName, currentFieldMeta.getReference().getTargetEntity(), currentFieldMeta.getReference().getReferenceId()); } currentCriteria = criteriaJoin; }while (step >= names.length); Holder<E> holder = new Holder<>(); holder.currentFieldName = currentName; holder.currentCriteria = currentCriteria; holder.currentFieldMeta = currentFieldMeta; return holder; } /** * * @param operator * @param rawValue * @param fieldType * @return */ public static Object getValue(String operator, String rawValue, Class<?> fieldType){ return getValue(Operator.value(operator), rawValue, fieldType); } /** * * @param operator * @param rawValue * @param fieldType * @return */ public static Object getValue(Operator operator, String rawValue, Class<?> fieldType){ if(Operator.IN.equals(operator)) { String[] svalues = rawValue.split("\\|"); List<Object> lvalues = new LinkedList<>(); for (String svalue : svalues) { lvalues.add(Fields.castValue(fieldType, svalue)); } return lvalues; } return Fields.castValue(fieldType, rawValue); } }