All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.wizarius.orm.database.actions.builders.WizWhereQueryBuilder Maven / Gradle / Ivy

The newest version!
package com.wizarius.orm.database.actions.builders;

import com.wizarius.orm.database.DBException;
import com.wizarius.orm.database.DBRuntimeException;
import com.wizarius.orm.database.data.*;
import com.wizarius.orm.database.data.fieldfinder.FieldFinder;
import com.wizarius.orm.database.data.fieldfinder.FieldFinderResult;
import com.wizarius.orm.database.entityreader.DBSupportedTypes;
import com.wizarius.orm.database.entityreader.WizEntityManager;
import com.wizarius.orm.database.handlers.WritableHandler;
import com.wizarius.orm.database.handlers.WritableHandlers;
import lombok.Setter;

import java.lang.reflect.Array;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author Vladyslav Shyshkin
 * Date: 2019-10-17
 * Time: 23:23
 */
public class WizWhereQueryBuilder {
    /**
     * List of where queries
     */
    private final List where = new ArrayList<>();
    /**
     * Group stack
     */
    private final Deque groupStack = new ArrayDeque<>();
    /**
     * Field finder
     */
    private final FieldFinder fieldFinder;
    /**
     * DB where type
     */
    @Setter
    private DBWhereType whereType = DBWhereType.AND;
    /**
     * Writable handlers
     */
    private final WritableHandlers writableHandlers;

    public WizWhereQueryBuilder(WritableHandlers writableHandlers, FieldFinder fieldsFinder) {
        this.writableHandlers = writableHandlers;
        this.fieldFinder = fieldsFinder;
    }

    /**
     * Setup where filed
     *
     * @param field filed name
     * @param value field value
     */
    public void where(String field, Object value) {
        if (value == null) {
            throw new DBRuntimeException("Value can't be null");
        }
        addCondition(new WhereBaseCondition<>(whereType, field, value, DBSignType.EQUALS));
    }

    /**
     * Setup where filed
     *
     * @param field    filed name
     * @param value    field value
     * @param signType sign type
     */
    public void where(String field, Object value, DBSignType signType) {
        if (value == null) {
            throw new DBRuntimeException("Value can't be null");
        }
        if (signType == DBSignType.IN || signType == DBSignType.NOT_IN) {
            whereIN(field, value, signType);
        } else {
            addCondition(new WhereBaseCondition<>(whereType, field, value, signType));
        }
    }

    /**
     * Setup where filed
     *
     * @param key   database field name
     * @param value database field value
     * @param clazz instance of object
     * @throws DBException on unable to build where condition
     */
    public void where(String key, Object value, Class clazz) throws DBException {
        if (value == null) {
            throw new DBRuntimeException("Value can't be null");
        }
        where(key, value, DBSignType.EQUALS, clazz);
    }

    /**
     * Start group
     */
    public void startWhereGroup() {
        WhereGroupCondition groupCondition = new WhereGroupCondition(whereType);
        addCondition(groupCondition);
        groupStack.push(groupCondition);
    }

    /**
     * Ends the current group of conditions.
     *
     * @throws DBRuntimeException if no group has been started or the last condition is not a group
     */
    public void endWhereGroup() {
        if (groupStack.isEmpty()) {
            throw new DBRuntimeException("Cannot end group: No group has been started. Please call startGroup() before endGroup().");
        }
        groupStack.pop();
    }

    /**
     * Build where clause
     *
     * @param key      database field name
     * @param value    database field value
     * @param signType where sign type
     * @param clazz    instance of object
     * @throws DBException on unable to build where condition
     */
    public void where(String key,
                      Object value,
                      DBSignType signType,
                      Class clazz) throws DBException {
        if (value == null) {
            throw new DBRuntimeException("Value can't be null");
        }
        FieldFinderResult dbField;
        if (clazz == null) {
            dbField = fieldFinder.findDBField(key);
        } else {
            dbField = fieldFinder.findDBField(key, clazz);
        }
        if (dbField == null) {
            throw new DBRuntimeException("Unable to find field where name = " + key);
        }
        addCondition(new WhereBaseCondition<>(whereType, dbField.getFindField().getDbFieldName(), value, signType));
    }

    /**
     * Setup where query
     *
     * @param query custom query
     */
    public void where(String query) {
        addCondition(new WhereQueryCondition(whereType, query));
    }

    /**
     * Setup where field in array
     *
     * @param field  field name
     * @param values values array
     */
    public void whereIN(String field, Object values) {
        whereIN(field, values, DBSignType.IN);
    }

    /**
     * Setup where NOT IN array
     *
     * @param field  db field name
     * @param values values array
     */
    public void whereNotIN(String field, Object values) {
        whereIN(field, values, DBSignType.NOT_IN);
    }

    /**
     * Setup where IN or NOT IN query
     *
     * @param values values array
     * @param field  database field name
     * @param sign   sign type IN or NOT IN
     */
    private void whereIN(String field, Object values, DBSignType sign) {
        if (values == null) {
            throw new DBRuntimeException("Array must be present in where condition");
        }
        if (!values.getClass().isArray()) {
            throw new DBRuntimeException("Class is not array");
        }
        Object[] array = buildArray(values);
        if (array.length == 0) {
            throw new DBRuntimeException("Array can't be empty for condition");
        }
        addCondition(new WhereInCondition<>(whereType, field, array, sign));
    }

    /**
     * Setup where field is null
     *
     * @param field database field name
     */
    public void whereNull(String field) {
        addCondition(new WhereNullCondition(whereType, field, true));
    }

    /**
     * Setup where field is not null
     *
     * @param field database field name
     */
    public void whereIsNotNull(String field) {
        addCondition(new WhereNullCondition(whereType, field, false));
    }

    /**
     * Setup where field between values
     *
     * @param field  field name
     * @param value1 value1
     * @param value2 value2
     */
    public void whereBetween(String field, Object value1, Object value2) {
        if (value1 == null || value2 == null) {
            throw new DBRuntimeException("Array must be present in where condition");
        }
        addCondition(new WhereBetweenCondition(whereType, field, value1, value2));
    }

    /**
     * Setup prepared query where values
     *
     * @param index     index in prepared statement
     * @param statement prepared query
     * @throws DBException on unable to set up where values
     */
    public void setupWhereValues(AtomicInteger index, PreparedStatement statement) throws DBException {
        setupWhereValues(where, index, statement);
    }

    /**
     * Recursive setup query where values
     *
     * @param conditions conditions
     * @param index      index
     * @param statement  statement
     * @throws DBException on unable to set value in query
     */
    private void setupWhereValues(List conditions, AtomicInteger index, PreparedStatement statement) throws DBException {
        for (WhereCondition condition : conditions) {
            if (condition instanceof WhereBaseCondition) {
                WhereBaseCondition item = (WhereBaseCondition) condition;
                Object value = item.getValue();
                setupIndexValue(index, statement, value);
            } else if (condition instanceof WhereInCondition) {
                WhereInCondition item = (WhereInCondition) condition;
                for (Object value : item.getValues()) {
                    setupIndexValue(index, statement, value);
                }
            } else if (condition instanceof WhereBetweenCondition) {
                WhereBetweenCondition item = (WhereBetweenCondition) condition;
                setupIndexValue(index, statement, item.getValue1());
                setupIndexValue(index, statement, item.getValue2());
            } else if (condition instanceof WhereGroupCondition) {
                WhereGroupCondition item = (WhereGroupCondition) condition;
                setupWhereValues(item.getConditions(), index, statement);
            }
        }
    }

    /**
     * Setup value for index
     *
     * @param index     index
     * @param statement statement
     * @param value     value
     * @throws DBException on unable to setup value
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    private void setupIndexValue(AtomicInteger index, PreparedStatement statement, Object value) throws DBException {
        DBSupportedTypes supportedType = WizEntityManager.javaTypeToDBType(value.getClass());
        WritableHandler handlerByType = writableHandlers.getHandlerByType(supportedType);
        try {
            handlerByType.set(value, index.getAndIncrement(), statement);
        } catch (SQLException e) {
            throw new DBException("Unable to setup value to prepared statement", e);
        }
    }

    /**
     * Recursive build conditions
     *
     * @param conditions list of conditions
     * @param sb         StringBuilder to build sql
     */
    private void buildConditions(List conditions, StringBuilder sb, boolean isGroup) {
        boolean first = true;
        for (WhereCondition condition : conditions) {
            if (!first) {
                String space = isGroup ? " " : "\n";
                sb.append(space).append(condition.getType()).append(space);
            }
            if (condition instanceof WhereBaseCondition) {
                WhereBaseCondition item = (WhereBaseCondition) condition;
                sb.append(item.getDbFieldName()).append(" ")
                        .append(item.getSignType().getSign())
                        .append(" ?");
            } else if (condition instanceof WhereInCondition) {
                WhereInCondition item = (WhereInCondition) condition;
                sb.append(item.getDbFieldName())
                        .append(" ")
                        .append(item.getSignType().getSign())
                        .append(" (")
                        .append(buildQuestionsCount(item.getValues().length))
                        .append(")");
            } else if (condition instanceof WhereNullCondition) {
                WhereNullCondition item = (WhereNullCondition) condition;
                sb.append(item.getDbFieldName()).append(" ").append(item.isNull() ? "IS NULL" : "IS NOT NULL");
            } else if (condition instanceof WhereBetweenCondition) {
                WhereBetweenCondition item = (WhereBetweenCondition) condition;
                sb.append(item.getDbFieldName()).append(" ").append("BETWEEN ? AND ?");
            } else if (condition instanceof WhereQueryCondition) {
                WhereQueryCondition item = (WhereQueryCondition) condition;
                sb.append(item.getQuery());
            } else if (condition instanceof WhereGroupCondition) {
                WhereGroupCondition groupCondition = (WhereGroupCondition) condition;
                sb.append("(");
                buildConditions(groupCondition.getConditions(), sb, true);
                sb.append(")");
            }
            first = false;
        }
    }

    /**
     * Build where clause
     *
     * @return where prepared string
     */
    public String getWhereQuery() {
        if (where.isEmpty()) {
            return "";
        }
        if (!groupStack.isEmpty()) {
            throw new DBRuntimeException("Not all condition groups have been closed. Please ensure that for every call to startGroup(), there is a corresponding endGroup().");
        }
        StringBuilder sb = new StringBuilder("WHERE\n");
        buildConditions(where, sb, false);
        return sb.toString();
    }

    /**
     * Returns a string with the given number of question characters
     *
     * @param length questions count
     * @return string like ?,?,?
     */
    private String buildQuestionsCount(int length) {
        if (length == 1) {
            return "?";
        }
        StringBuilder sb = new StringBuilder();
        for (int i = length; i > 0; i--) {
            sb.append("?").append(",");
        }
        sb.setLength(sb.length() - 1);
        return sb.toString();
    }

    /**
     * Convert values array
     *
     * @param values value object
     * @return object array for value
     */
    private Object[] buildArray(Object values) {
        if (values instanceof Object[]) {
            return (Object[]) values;
        }
        int length = Array.getLength(values);
        Object[] result = new Object[length];
        for (int i = 0; i < length; ++i) {
            result[i] = Array.get(values, i);
        }
        return result;
    }

    /**
     * Add condition in build current query
     *
     * @param condition condition
     */
    private void addCondition(WhereCondition condition) {
        if (!groupStack.isEmpty()) {
            groupStack.peek().getConditions().add(condition);
        } else {
            where.add(condition);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy