Advertisement
Guest User

Untitled

a guest
Jul 20th, 2018
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 9.68 KB | None | 0 0
  1. package org.matr.microservice.dao.util;
  2.  
  3. import org.hibernate.type.Type;
  4. import org.springframework.util.Assert;
  5. import org.springframework.util.CollectionUtils;
  6.  
  7. import javax.persistence.EntityManager;
  8. import javax.persistence.Query;
  9. import java.util.*;
  10. import java.util.regex.Matcher;
  11. import java.util.regex.Pattern;
  12.  
  13. /**
  14.  * Builds Query.
  15.  */
  16. public class QueryBuilder {
  17.     private static final String AUTO_REPLACE_KEY_PREFIX = "$";
  18.     private static final String AUTO_REPLACE_ID_PATTERN_STRING = "[a-z,A-Z]+";
  19.  
  20.     private static final Pattern AUTO_REPLACE_ID_PATTERN = Pattern.compile(AUTO_REPLACE_ID_PATTERN_STRING);
  21.     private static final Pattern AUTO_REPLACE_KEY_PATTERN = Pattern.compile("\\" +  AUTO_REPLACE_KEY_PREFIX
  22.             + AUTO_REPLACE_ID_PATTERN_STRING);
  23.  
  24.     private final EntityManager entityManager;
  25.     private final StringBuilder query;
  26.     private final Map<String, Object> parameters = new HashMap<String, Object>();
  27.  
  28.     private final Map<String, String> autoReplaces = new HashMap<>();
  29.  
  30.     /**
  31.      * Instantiates a new Query builder.
  32.      *
  33.      * @param entityManager the entityManager
  34.      */
  35.     public QueryBuilder(EntityManager entityManager) {
  36.         this(entityManager, "");
  37.     }
  38.  
  39.     /**
  40.      * Instantiates a new Query builder.
  41.      *
  42.      * @param entityManager the entityManager
  43.      * @param hql the hql
  44.      */
  45.     public QueryBuilder(EntityManager entityManager, String hql) {
  46.         Assert.notNull(entityManager, "EntityManager is undefined");
  47.  
  48.         this.entityManager = entityManager;
  49.         this.query = new StringBuilder(hql);
  50.     }
  51.  
  52.     /**
  53.      * Append hql to query builder.
  54.      *
  55.      * @param hql the hql
  56.      * @return the query builder
  57.      */
  58.     public QueryBuilder append(String hql) {
  59.         this.query.append(performAutoReplaces(hql));
  60.  
  61.         return this;
  62.     }
  63.  
  64.     /**
  65.      * Append hql and parameter value to query builder.
  66.      *
  67.      * @param hql the hql
  68.      * @param value the value
  69.      * @return the query builder
  70.      */
  71.     public QueryBuilder append(String hql, Object value) {
  72.         final String updatedQuery = performAutoReplaces(hql);
  73.         this.query.append(updatedQuery);
  74.  
  75.         final String key = extractParameter(updatedQuery);
  76.         final Object old = parameters.put(key, value);
  77.  
  78.         if (old != null) {
  79.             assertValue(value, key, old);
  80.         }
  81.  
  82.         return this;
  83.     }
  84.  
  85.     private void assertValue(Object value, String key, Object old) {
  86.         Assert.isTrue(old.equals(value),
  87.             String.format("More than one value for the same value: %s old: %s; new: %s", key, old, value));
  88.     }
  89.  
  90.     /**
  91.      * Append different hqls to query builder depends on value(null or not null).
  92.      *
  93.      * @param hqlNotNull the hql not null
  94.      * @param hqlNull the hql null
  95.      * @param value the value
  96.      * @return the query builder
  97.      */
  98.     public QueryBuilder append(String hqlNotNull, String hqlNull, Object value) {
  99.         if (value == null) {
  100.             append(hqlNull);
  101.         } else {
  102.             append(hqlNotNull, value);
  103.         }
  104.  
  105.         return this;
  106.     }
  107.  
  108.     /**
  109.      * Append different hqls to query builder depends on value(null or not null) nad it's type.
  110.      *
  111.      * @param hqlNotNull the hql not null
  112.      * @param hqlNull the hql null
  113.      * @param value the value
  114.      * @param type the type
  115.      * @return the query builder
  116.      */
  117.     public QueryBuilder append(String hqlNotNull, String hqlNull, Object value, Type type) {
  118.         if (value == null) {
  119.             append(hqlNull);
  120.         } else {
  121.             append(hqlNotNull, value, type);
  122.         }
  123.  
  124.         return this;
  125.     }
  126.  
  127.     /**
  128.      * Append hql to query builder, parameter value and it's type.
  129.      *
  130.      * @param hql the hql
  131.      * @param value the value
  132.      * @param type the type
  133.      * @return the query builder
  134.      */
  135.     public QueryBuilder append(String hql, Object value, Type type) {
  136.         Assert.notNull(type, "Parameter type is undefined");
  137.  
  138.         final String updatedQuery = performAutoReplaces(hql);
  139.         this.query.append(updatedQuery);
  140.  
  141.         final String key = extractParameter(updatedQuery);
  142.         final Object old = parameters.put(key, value);
  143.  
  144.         if (old != null) {
  145.             Assert.isTrue(old.equals(type), "More than one type for the same value: " + key + " old: "
  146.                     + old + "; new: " + type);
  147.             assertValue(value, key, old);
  148.         }
  149.  
  150.         return this;
  151.     }
  152.  
  153.     /**
  154.      * Append not null value and corresponding hql.
  155.      *
  156.      * @param hql the hql
  157.      * @param value the value
  158.      * @return the query builder
  159.      */
  160.     public QueryBuilder appendNotNull(String hql, Object value) {
  161.         if (value != null) {
  162.             append(hql, value);
  163.         }
  164.  
  165.         return this;
  166.     }
  167.  
  168.     /**
  169.      * Append not empty query builder.
  170.      *
  171.      * @param <T>   the type parameter
  172.      * @param hql   the hql
  173.      * @param value the value
  174.      * @return the query builder
  175.      */
  176.     public <T> QueryBuilder appendNotEmpty(String hql, Collection<T> value) {
  177.         if (!CollectionUtils.isEmpty(value)) {
  178.             append(hql, value);
  179.         }
  180.  
  181.         return this;
  182.     }
  183.  
  184.     /**
  185.      * Append not null and not empty values and corresponding hql with IN condition.
  186.      *
  187.      * @param hql   the hql
  188.      * @param values the values
  189.      * @return the query builder
  190.      */
  191.     public QueryBuilder appendInNotNull(String hql, List values) {
  192.         if (values != null && values.size() > 0) {
  193.             append(hql, values);
  194.         }
  195.  
  196.         return this;
  197.     }
  198.  
  199.     /**
  200.      * Append like hql.
  201.      *
  202.      * @param hql   the hql
  203.      * @param value the value
  204.      * @return the query builder
  205.      */
  206.     public QueryBuilder appendLike(String hql, Object value) {
  207.         final String updatedQuery = performAutoReplaces(hql);
  208.         this.query.append(updatedQuery);
  209.  
  210.         final String delimiter = "%";
  211.         final String key = extractParameter(updatedQuery);
  212.         final Object old = parameters.put(key, delimiter + value + delimiter);
  213.  
  214.         if (old != null) {
  215.             assertValue(value, key, old);
  216.         }
  217.  
  218.         return this;
  219.     }
  220.  
  221.     /**
  222.      * Append like hql in case of value is not null.
  223.      *
  224.      * @param hql the hql
  225.      * @param value the value
  226.      * @return the query builder
  227.      */
  228.     public QueryBuilder appendLikeNotNull(String hql, Object value) {
  229.         if (value != null) {
  230.             appendLike(hql, value);
  231.         }
  232.  
  233.         return this;
  234.     }
  235.  
  236.     /**
  237.      * Builds query object.
  238.      *
  239.      * @return the query
  240.      */
  241.     public Query build() {
  242.         final Query query = entityManager.createQuery(this.query.toString());
  243.         return applyParametersToQuery(query);
  244.     }
  245.  
  246.     /**
  247.      * Builds query object with projection of result to specified class.
  248.      *
  249.      * @param resultClass class into which we should map result
  250.      *
  251.      * @return the query
  252.      */
  253.     public <T> Query build(Class<T> resultClass) {
  254.         final Query query = entityManager.createQuery(this.query.toString(), resultClass);
  255.         return applyParametersToQuery(query);
  256.     }
  257.  
  258.     private String performAutoReplaces(String query) {
  259.         if (autoReplaces.isEmpty()) {
  260.             return query;
  261.         }
  262.  
  263.         final Matcher matcher = AUTO_REPLACE_KEY_PATTERN.matcher(query);
  264.  
  265.         final Set<String> replaces = new HashSet<>();
  266.         while (matcher.find()) {
  267.             final String key = matcher.group();
  268.             if (autoReplaces.containsKey(key)) {
  269.                 replaces.add(key);
  270.             }
  271.         }
  272.  
  273.         String res = query;
  274.         for (String key : replaces) {
  275.             res = res.replaceAll(String.format("\\%s", key), autoReplaces.get(key));
  276.         }
  277.  
  278.         return res;
  279.     }
  280.  
  281.     /**
  282.      * Add the requirement to perform an auto replace in any appended part of query, where it contains $<b>replaceId</b>.
  283.      * For example if you call <br>
  284.      * qb.requireAutoReplace("i", 1);<br>
  285.      * And then<br>
  286.      * qb.append(" and s%i.value is null");<br>
  287.      * then string " and s1.value is null" will be appended after replace.
  288.      * @param replaceId id of replacement.
  289.      * @param replacement the toString() value of this object to be substituted for each match
  290.      */
  291.     public void requireAutoReplace(String replaceId, Object replacement) {
  292.         final Matcher matcher = AUTO_REPLACE_ID_PATTERN.matcher(replaceId);
  293.         Assert.isTrue(matcher.find() && matcher.group().equals(replaceId), String.format(
  294.                 "replaceId [%s] should match to pattern: %s", replaceId, AUTO_REPLACE_ID_PATTERN_STRING));
  295.  
  296.         final String key = AUTO_REPLACE_KEY_PREFIX + replaceId;
  297.         autoReplaces.put(key, String.valueOf(replacement));
  298.     }
  299.  
  300.     private <T extends Query> T applyParametersToQuery(T query) {
  301.         for (Map.Entry<String, Object> entry : parameters.entrySet()) {
  302.             query.setParameter(entry.getKey(), entry.getValue());
  303.         }
  304.  
  305.         return query;
  306.     }
  307.  
  308.     /**
  309.      * Extracts parameter.
  310.      *
  311.      * @param hql the hql
  312.      * @return the string
  313.      */
  314.     protected static String extractParameter(String hql) {
  315.         final int i = hql.indexOf(':');
  316.  
  317.         Assert.isTrue(i != -1, "There is no value in the given HQL query part: " + hql);
  318.  
  319.         char ch;
  320.         int j = i + 1;
  321.  
  322.         while (j < hql.length() && ((ch = hql.charAt(j)) == '_' || Character.isLetter(ch) || Character.isDigit(ch))) {
  323.             j++;
  324.         }
  325.  
  326.         Assert.isTrue(j != i + 1, "Empty parameter name is not allowed: " + hql);
  327.  
  328.         return hql.substring(i + 1, j);
  329.     }
  330.  
  331. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement