Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package org.matr.microservice.dao.util;
- import org.hibernate.type.Type;
- import org.springframework.util.Assert;
- import org.springframework.util.CollectionUtils;
- import javax.persistence.EntityManager;
- import javax.persistence.Query;
- import java.util.*;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- /**
- * Builds Query.
- */
- public class QueryBuilder {
- private static final String AUTO_REPLACE_KEY_PREFIX = "$";
- private static final String AUTO_REPLACE_ID_PATTERN_STRING = "[a-z,A-Z]+";
- private static final Pattern AUTO_REPLACE_ID_PATTERN = Pattern.compile(AUTO_REPLACE_ID_PATTERN_STRING);
- private static final Pattern AUTO_REPLACE_KEY_PATTERN = Pattern.compile("\\" + AUTO_REPLACE_KEY_PREFIX
- + AUTO_REPLACE_ID_PATTERN_STRING);
- private final EntityManager entityManager;
- private final StringBuilder query;
- private final Map<String, Object> parameters = new HashMap<String, Object>();
- private final Map<String, String> autoReplaces = new HashMap<>();
- /**
- * Instantiates a new Query builder.
- *
- * @param entityManager the entityManager
- */
- public QueryBuilder(EntityManager entityManager) {
- this(entityManager, "");
- }
- /**
- * Instantiates a new Query builder.
- *
- * @param entityManager the entityManager
- * @param hql the hql
- */
- public QueryBuilder(EntityManager entityManager, String hql) {
- Assert.notNull(entityManager, "EntityManager is undefined");
- this.entityManager = entityManager;
- this.query = new StringBuilder(hql);
- }
- /**
- * Append hql to query builder.
- *
- * @param hql the hql
- * @return the query builder
- */
- public QueryBuilder append(String hql) {
- this.query.append(performAutoReplaces(hql));
- return this;
- }
- /**
- * Append hql and parameter value to query builder.
- *
- * @param hql the hql
- * @param value the value
- * @return the query builder
- */
- public QueryBuilder append(String hql, Object value) {
- final String updatedQuery = performAutoReplaces(hql);
- this.query.append(updatedQuery);
- final String key = extractParameter(updatedQuery);
- final Object old = parameters.put(key, value);
- if (old != null) {
- assertValue(value, key, old);
- }
- return this;
- }
- private void assertValue(Object value, String key, Object old) {
- Assert.isTrue(old.equals(value),
- String.format("More than one value for the same value: %s old: %s; new: %s", key, old, value));
- }
- /**
- * Append different hqls to query builder depends on value(null or not null).
- *
- * @param hqlNotNull the hql not null
- * @param hqlNull the hql null
- * @param value the value
- * @return the query builder
- */
- public QueryBuilder append(String hqlNotNull, String hqlNull, Object value) {
- if (value == null) {
- append(hqlNull);
- } else {
- append(hqlNotNull, value);
- }
- return this;
- }
- /**
- * Append different hqls to query builder depends on value(null or not null) nad it's type.
- *
- * @param hqlNotNull the hql not null
- * @param hqlNull the hql null
- * @param value the value
- * @param type the type
- * @return the query builder
- */
- public QueryBuilder append(String hqlNotNull, String hqlNull, Object value, Type type) {
- if (value == null) {
- append(hqlNull);
- } else {
- append(hqlNotNull, value, type);
- }
- return this;
- }
- /**
- * Append hql to query builder, parameter value and it's type.
- *
- * @param hql the hql
- * @param value the value
- * @param type the type
- * @return the query builder
- */
- public QueryBuilder append(String hql, Object value, Type type) {
- Assert.notNull(type, "Parameter type is undefined");
- final String updatedQuery = performAutoReplaces(hql);
- this.query.append(updatedQuery);
- final String key = extractParameter(updatedQuery);
- final Object old = parameters.put(key, value);
- if (old != null) {
- Assert.isTrue(old.equals(type), "More than one type for the same value: " + key + " old: "
- + old + "; new: " + type);
- assertValue(value, key, old);
- }
- return this;
- }
- /**
- * Append not null value and corresponding hql.
- *
- * @param hql the hql
- * @param value the value
- * @return the query builder
- */
- public QueryBuilder appendNotNull(String hql, Object value) {
- if (value != null) {
- append(hql, value);
- }
- return this;
- }
- /**
- * Append not empty query builder.
- *
- * @param <T> the type parameter
- * @param hql the hql
- * @param value the value
- * @return the query builder
- */
- public <T> QueryBuilder appendNotEmpty(String hql, Collection<T> value) {
- if (!CollectionUtils.isEmpty(value)) {
- append(hql, value);
- }
- return this;
- }
- /**
- * Append not null and not empty values and corresponding hql with IN condition.
- *
- * @param hql the hql
- * @param values the values
- * @return the query builder
- */
- public QueryBuilder appendInNotNull(String hql, List values) {
- if (values != null && values.size() > 0) {
- append(hql, values);
- }
- return this;
- }
- /**
- * Append like hql.
- *
- * @param hql the hql
- * @param value the value
- * @return the query builder
- */
- public QueryBuilder appendLike(String hql, Object value) {
- final String updatedQuery = performAutoReplaces(hql);
- this.query.append(updatedQuery);
- final String delimiter = "%";
- final String key = extractParameter(updatedQuery);
- final Object old = parameters.put(key, delimiter + value + delimiter);
- if (old != null) {
- assertValue(value, key, old);
- }
- return this;
- }
- /**
- * Append like hql in case of value is not null.
- *
- * @param hql the hql
- * @param value the value
- * @return the query builder
- */
- public QueryBuilder appendLikeNotNull(String hql, Object value) {
- if (value != null) {
- appendLike(hql, value);
- }
- return this;
- }
- /**
- * Builds query object.
- *
- * @return the query
- */
- public Query build() {
- final Query query = entityManager.createQuery(this.query.toString());
- return applyParametersToQuery(query);
- }
- /**
- * Builds query object with projection of result to specified class.
- *
- * @param resultClass class into which we should map result
- *
- * @return the query
- */
- public <T> Query build(Class<T> resultClass) {
- final Query query = entityManager.createQuery(this.query.toString(), resultClass);
- return applyParametersToQuery(query);
- }
- private String performAutoReplaces(String query) {
- if (autoReplaces.isEmpty()) {
- return query;
- }
- final Matcher matcher = AUTO_REPLACE_KEY_PATTERN.matcher(query);
- final Set<String> replaces = new HashSet<>();
- while (matcher.find()) {
- final String key = matcher.group();
- if (autoReplaces.containsKey(key)) {
- replaces.add(key);
- }
- }
- String res = query;
- for (String key : replaces) {
- res = res.replaceAll(String.format("\\%s", key), autoReplaces.get(key));
- }
- return res;
- }
- /**
- * Add the requirement to perform an auto replace in any appended part of query, where it contains $<b>replaceId</b>.
- * For example if you call <br>
- * qb.requireAutoReplace("i", 1);<br>
- * And then<br>
- * qb.append(" and s%i.value is null");<br>
- * then string " and s1.value is null" will be appended after replace.
- * @param replaceId id of replacement.
- * @param replacement the toString() value of this object to be substituted for each match
- */
- public void requireAutoReplace(String replaceId, Object replacement) {
- final Matcher matcher = AUTO_REPLACE_ID_PATTERN.matcher(replaceId);
- Assert.isTrue(matcher.find() && matcher.group().equals(replaceId), String.format(
- "replaceId [%s] should match to pattern: %s", replaceId, AUTO_REPLACE_ID_PATTERN_STRING));
- final String key = AUTO_REPLACE_KEY_PREFIX + replaceId;
- autoReplaces.put(key, String.valueOf(replacement));
- }
- private <T extends Query> T applyParametersToQuery(T query) {
- for (Map.Entry<String, Object> entry : parameters.entrySet()) {
- query.setParameter(entry.getKey(), entry.getValue());
- }
- return query;
- }
- /**
- * Extracts parameter.
- *
- * @param hql the hql
- * @return the string
- */
- protected static String extractParameter(String hql) {
- final int i = hql.indexOf(':');
- Assert.isTrue(i != -1, "There is no value in the given HQL query part: " + hql);
- char ch;
- int j = i + 1;
- while (j < hql.length() && ((ch = hql.charAt(j)) == '_' || Character.isLetter(ch) || Character.isDigit(ch))) {
- j++;
- }
- Assert.isTrue(j != i + 1, "Empty parameter name is not allowed: " + hql);
- return hql.substring(i + 1, j);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement