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

io.github.ashwithpoojary98.BaseQuery Maven / Gradle / Ivy

The newest version!
package io.github.ashwithpoojary98;


import io.github.ashwithpoojary98.clausses.AbstractClause;
import io.github.ashwithpoojary98.clausses.conditions.BasicCondition;
import io.github.ashwithpoojary98.clausses.conditions.BasicDateCondition;
import io.github.ashwithpoojary98.clausses.conditions.BasicStringCondition;
import io.github.ashwithpoojary98.clausses.conditions.BetweenCondition;
import io.github.ashwithpoojary98.clausses.conditions.BooleanCondition;
import io.github.ashwithpoojary98.clausses.conditions.ExistsCondition;
import io.github.ashwithpoojary98.clausses.conditions.InCondition;
import io.github.ashwithpoojary98.clausses.conditions.InQueryCondition;
import io.github.ashwithpoojary98.clausses.conditions.NestedCondition;
import io.github.ashwithpoojary98.clausses.conditions.NullCondition;
import io.github.ashwithpoojary98.clausses.conditions.QueryCondition;
import io.github.ashwithpoojary98.clausses.conditions.RawCondition;
import io.github.ashwithpoojary98.clausses.conditions.SubQueryCondition;
import io.github.ashwithpoojary98.clausses.conditions.TwoColumnsCondition;
import io.github.ashwithpoojary98.clausses.fromclausses.FromClause;
import io.github.ashwithpoojary98.clausses.fromclausses.QueryFromClause;
import io.github.ashwithpoojary98.clausses.fromclausses.RawFromClause;
import lombok.Getter;

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

public abstract class BaseQuery> extends AbstractQuery {

    @Getter
    private List clauses = new ArrayList<>();
    private boolean orFlag = false;
    private boolean notFlag = false;
    protected String engineScope;

    public Q setEngineScope(String engine) {
        this.engineScope = engine;
        return (Q) this;
    }

    public Q setClauses(List clauses) {
        this.clauses = clauses;
        return (Q) this;
    }


    protected BaseQuery() {
    }

    public Q copy() {
        Q q = newQuery();
        q.setClauses(this.getClauses().stream()
                .map(AbstractClause::copy)
                .collect(Collectors.toList()));
        return q;
    }


    public Q setParent(AbstractQuery parent) {
        if (this == parent) {
            throw new IllegalArgumentException("Cannot set the same AbstractQuery as a parent of itself");
        }
        this.parent = parent;
        return (Q) this;
    }

    public abstract Q newQuery();

    public Q newChild() {
        Q newQuery = newQuery().setParent(this);
        newQuery.engineScope = this.engineScope;
        return newQuery;
    }

    public Q addComponent(String component, AbstractClause clause, String engineCode) {
        if (engineCode == null) {
            engineCode = engineScope;
        }
        clause.setEngine(engineCode);
        clause.setComponent(component);
        clauses.add(clause);
        return (Q) this;
    }

    public Q addComponent(String component, AbstractClause clause) {
        return addComponent(component, clause, null);
    }


    public Q addOrReplaceComponent(String component, AbstractClause clause, String engineCode) {
        if (engineCode == null) {
            engineCode = engineScope;
        }

        String finalEngineCode = engineCode;

        AbstractClause current = getComponents(component, engineCode).stream()
                .filter(c -> c.getEngine() != null && c.getEngine().equals(finalEngineCode))
                .findFirst()
                .orElse(null);

        if (current != null) {
            clauses.remove(current);
        }
        return addComponent(component, clause, engineCode);
    }

    public Q addOrReplaceComponent(String component, AbstractClause clause) {
        return addComponent(component, clause, null);
    }

    public  List getComponents(String component, String engineCode) {
        if (engineCode == null) {
            engineCode = engineScope;
        }

        String finalEngineCode = engineCode;
        return clauses.stream()
                .filter(x -> x.getComponent().equals(component) &&
                        (finalEngineCode == null || x.getEngine() == null || finalEngineCode.equals(x.getEngine())))
                .map(c -> (C) c)
                .collect(Collectors.toList());
    }

    public  List getComponents(String component) {
        return getComponents(component, null);
    }


    public  C getOneComponent(String component, String engineCode) {
        if (engineCode == null) {
            engineCode = engineScope;
        }

        List all = getComponents(component, engineCode);
        String finalEngineCode = engineCode;
        Optional matchingItem = all.stream()
                .filter(c -> c.getEngine() != null && c.getEngine().equals(finalEngineCode))
                .findFirst();

        // If not found, try to find the first item with a null engine
        return matchingItem.orElseGet(() ->
                all.stream()
                        .filter(c -> c.getEngine() == null)
                        .findFirst()
                        .orElse(null));

    }


    public AbstractClause getOneComponent(String component) {
        return getOneComponent(component, null);
    }

    public boolean hasComponent(String component, String engineCode) {
        if (engineCode == null) {
            engineCode = engineScope;
        }
        return !getComponents(component, engineCode).isEmpty();
    }

    public boolean hasComponent(String component) {
        return hasComponent(component, null);
    }

    public Q clearComponent(String component, String engineCode) {
        if (engineCode == null) {
            engineCode = engineScope;
        }
        String finalEngineCode = engineCode;
        clauses = clauses.stream()
                .filter(x -> !(x.getComponent().equals(component) &&
                        (finalEngineCode == null || x.getEngine() == null || finalEngineCode.equals(x.getEngine()))))
                .collect(Collectors.toList());
        return (Q) this;
    }

    public Q clearComponent(String component) {
        return clearComponent(component, null);
    }

    protected Q and() {
        orFlag = false;
        return (Q) this;
    }

    public Q or() {
        orFlag = true;
        return (Q) this;
    }

    public Q not(boolean flag) {
        notFlag = flag;
        return (Q) this;
    }

    public Q not() {
        notFlag = true;
        return (Q) this;
    }

    protected boolean getOr() {
        boolean ret = orFlag;
        orFlag = false;
        return ret;
    }

    protected boolean getNot() {
        boolean ret = notFlag;
        notFlag = false;
        return ret;
    }

    public Q from(String table) {
        return addOrReplaceComponent("from", new FromClause(table), null);
    }

    public Q from(Query query) {
        return from(query, null);
    }

    public Q from(Query query, String alias) {
        query = query.copy();
        query.setParent(this);
        if (alias != null) {
            query.as(alias);
        }
        return addOrReplaceComponent("from", new QueryFromClause(query), null);
    }

    public Q fromRaw(String sql, Object... bindings) {
        return addOrReplaceComponent("from", new RawFromClause(sql, bindings), null);
    }


    public Q from(Function callback, String alias) {
        Query query = new Query();
        query.setParent(this); // Assuming 'this' refers to the current instance of Q
        return from(callback.apply(query), alias);
    }

    public Q from(Function callback) {
        return from(callback, null);
    }


    public Q where(String column, String op, Object value) {
        // If the value is null, we will assume the developer wants to add a where null clause
        if (value == null) {
            return not(!op.equals("=")).whereNull(column);
        }

        if (value instanceof Boolean) {
            Boolean boolValue = (Boolean) value;
            if (!op.equals("=")) {
                not();
            }
            return Boolean.TRUE.equals(boolValue) ? whereTrue(column) : whereFalse(column);
        }

        return addComponent("where", new BasicCondition(column, op, value, getOr(), getNot()));
    }

    public Q whereNot(String column, String op, Object value) {
        return not().where(column, op, value);
    }

    public Q whereNull(String column) {
        return addComponent("where", new NullCondition(column, getOr(), getNot()));
    }

    public Q orWhere(String column, String op, Object value) {
        return or().where(column, op, value);
    }

    public Q orWhereNot(String column, String op, Object value) {
        return this.or().not().where(column, op, value);
    }

    public Q where(String column, Object value) {
        return where(column, "=", value);
    }

    public Q whereNot(String column, Object value) {
        return whereNot(column, "=", value);
    }

    public Q orWhere(String column, Object value) {
        return orWhere(column, "=", value);
    }

    public Q orWhereNot(String column, Object value) {
        return orWhereNot(column, "=", value);
    }

    public Q where(Object constraints) {
        Map dictionary = new HashMap<>();
        try {
            for (PropertyDescriptor property : Introspector.getBeanInfo(constraints.getClass()).getPropertyDescriptors()) {
                String propertyName = property.getName();
                Object propertyValue = property.getReadMethod().invoke(constraints);
                dictionary.put(propertyName, propertyValue);
            }
        } catch (IntrospectionException | IllegalAccessException | InvocationTargetException introspectionException) {
            //ignore this exception
        }
        return where(dictionary);
    }

    public Q where(Map values) {
        Q currentQuery = (Q) this;
        boolean isOr = getOr();
        boolean isNot = getNot();

        for (Map.Entry entry : values.entrySet()) {
            if (isOr) {
                currentQuery = currentQuery.or();
            } else {
                currentQuery.and();
            }

            currentQuery = this.not(isNot).where(entry.getKey(), entry.getValue());
        }

        return currentQuery;
    }

    public Q whereRaw(String sql, Object... bindings) {
        return addComponent("where", new RawCondition(sql, bindings, getOr(), getNot()));
    }

    public Q orWhereRaw(String sql, Object... bindings) {
        return or().whereRaw(sql, bindings);
    }

    public Q where(Function callback) {
        Q query = callback.apply(newChild());

        // omit empty queries
        if (query.getClauses().stream().noneMatch(x -> "where".equals(x.getComponent()))) {
            return (Q) this;
        }

        return addComponent("where", new NestedCondition<>(query, getNot(), getOr()));
    }


    public Q whereNot(Function callback) {
        return not().where(callback);
    }

    public Q orWhere(Function callback) {
        return or().where(callback);
    }

    public Q orWhereNot(Function callback) {
        return not().or().where(callback);
    }

    public Q whereColumns(String first, String op, String second) {
        return addComponent("where", new TwoColumnsCondition(first, second, op, getOr(), getNot()));
    }

    public Q OrWhereColumns(String first, String op, String second) {
        return or().whereColumns(first, op, second);
    }

    public Q whereNotNull(String column) {
        return not().whereNull(column);
    }

    public Q OrWhereNull(String column) {
        return this.or().whereNull(column);
    }

    public Q OrWhereNotNull(String column) {
        return or().not().whereNull(column);
    }

    public Q whereTrue(String column) {
        return addComponent("where", new BooleanCondition(column, true, getOr(), getNot()));
    }

    public Q OrWhereTrue(String column) {
        return or().whereTrue(column);
    }

    public Q whereFalse(String column) {
        return addComponent("where", new BooleanCondition(column, false, getOr(), getNot()));
    }


    public Q OrWhereFalse(String column) {
        return or().whereFalse(column);
    }

    public Q whereLike(String column, Object value, boolean caseSensitive, String escapeCharacter) {
        return addComponent("where", new BasicStringCondition(
                "like",
                column,
                value,
                caseSensitive,
                escapeCharacter,
                getOr(),
                getNot()
        ));
    }


    // Overloaded method for default values
    public Q whereLike(String column, Object value) {
        return whereLike(column, value, false, null);
    }

    public Q whereNotLike(String column, Object value, boolean caseSensitive, String escapeCharacter) {
        return not().whereLike(column, value, caseSensitive, escapeCharacter);
    }

    public Q whereNotLike(String column, Object value) {
        return whereNotLike(column, value, false, null);
    }

    public Q orWhereLike(String column, Object value, boolean caseSensitive, String escapeCharacter) {
        return or().whereLike(column, value, caseSensitive, escapeCharacter);
    }

    public Q orWhereLike(String column, Object value, boolean caseSensitive) {
        return orWhereLike(column, value, caseSensitive, null);
    }

    public Q orWhereLike(String column, Object value) {
        return orWhereLike(column, value, false, null);
    }


    public Q orWhereNotLike(String column, Object value, boolean caseSensitive, String escapeCharacter) {
        return or().not().whereLike(column, value, caseSensitive, escapeCharacter);
    }

    public Q orWhereNotLike(String column, Object value) {
        return orWhereNotLike(column, value, false, null);
    }

    public Q whereStarts(String column, Object value, boolean caseSensitive, String escapeCharacter) {
        return addComponent("where", new BasicStringCondition(
                "starts",
                column,
                value,
                caseSensitive,
                escapeCharacter,
                getOr(),
                getNot()
        ));
    }

    // Overloaded method for default values
    public Q whereStarts(String column, Object value) {
        return whereStarts(column, value, false, null);
    }

    public Q whereNotStarts(String column, Object value, boolean caseSensitive, String escapeCharacter) {
        return not().whereStarts(column, value, caseSensitive, escapeCharacter);
    }

    public Q orWhereStarts(String column, Object value, boolean caseSensitive, String escapeCharacter) {
        return or().whereStarts(column, value, caseSensitive, escapeCharacter);
    }

    public Q orWhereNotStarts(String column, Object value, boolean caseSensitive, String escapeCharacter) {
        return or().not().whereStarts(column, value, caseSensitive, escapeCharacter);
    }

    // Overloaded methods for default values
    public Q whereNotStarts(String column, Object value) {
        return whereNotStarts(column, value, false, null);
    }

    public Q orWhereStarts(String column, Object value) {
        return orWhereStarts(column, value, false, null);
    }

    public Q orWhereNotStarts(String column, Object value) {
        return orWhereNotStarts(column, value, false, null);
    }

    public Q whereEnds(String column, Object value, boolean caseSensitive, String escapeCharacter) {
        return addComponent("where", new BasicStringCondition(
                "ends",
                column,
                value,
                caseSensitive,
                escapeCharacter,
                getOr(),
                getNot()
        ));
    }

    // Overloaded method for default values
    public Q whereEnds(String column, Object value) {
        return whereEnds(column, value, false, null);
    }

    public Q whereNotEnds(String column, Object value, boolean caseSensitive, String escapeCharacter) {
        return not().whereEnds(column, value, caseSensitive, escapeCharacter);
    }

    public Q orWhereEnds(String column, Object value, boolean caseSensitive, String escapeCharacter) {
        return or().whereEnds(column, value, caseSensitive, escapeCharacter);
    }

    public Q orWhereNotEnds(String column, Object value, boolean caseSensitive, String escapeCharacter) {
        return or().not().whereEnds(column, value, caseSensitive, escapeCharacter);
    }

    // Overloaded methods for default values
    public Q whereNotEnds(String column, Object value) {
        return whereNotEnds(column, value, false, null);
    }

    public Q orWhereEnds(String column, Object value) {
        return orWhereEnds(column, value, false, null);
    }

    public Q orWhereNotEnds(String column, Object value) {
        return orWhereNotEnds(column, value, false, null);
    }

    public Q whereContains(String column, Object value, boolean caseSensitive, String escapeCharacter) {
        return addComponent("where", new BasicStringCondition(
                "contains",
                column,
                value,
                caseSensitive,
                escapeCharacter,
                getOr(),
                getNot()
        ));
    }

    // Overloaded method for default values
    public Q whereContains(String column, Object value) {
        return whereContains(column, value, false, null);
    }


    public Q whereNotContains(String column, Object value, boolean caseSensitive, String escapeCharacter) {
        return not().whereContains(column, value, caseSensitive, escapeCharacter);
    }

    public Q orWhereContains(String column, Object value, boolean caseSensitive, String escapeCharacter) {
        return or().whereContains(column, value, caseSensitive, escapeCharacter);
    }

    public Q orWhereNotContains(String column, Object value, boolean caseSensitive, String escapeCharacter) {
        return or().not().whereContains(column, value, caseSensitive, escapeCharacter);
    }

    // Overloaded methods for default values
    public Q whereNotContains(String column, Object value) {
        return whereNotContains(column, value, false, null);
    }

    public Q orWhereContains(String column, Object value) {
        return orWhereContains(column, value, false, null);
    }

    public Q orWhereNotContains(String column, Object value) {
        return orWhereNotContains(column, value, false, null);
    }


    public  Q whereBetween(String column, T lower, T higher) {
        return addComponent("where", new BetweenCondition<>(
                column,
                getOr(),
                getNot(),
                lower,
                higher
        ));
    }

    public  Q orWhereBetween(String column, T lower, T higher) {
        return or().whereBetween(column, lower, higher);
    }

    public  Q whereNotBetween(String column, T lower, T higher) {
        return not().whereBetween(column, lower, higher);
    }

    public  Q orWhereNotBetween(String column, T lower, T higher) {
        return or().not().whereBetween(column, lower, higher);
    }

    public  Q whereIn(String column, List values) {
        List distinctValues = new ArrayList<>();
        for (T value : values) {
            if (!distinctValues.contains(value)) {
                distinctValues.add(value);
            }
        }
        return addComponent("where", new InCondition(
                column,
                getOr(),
                getNot(),
                distinctValues
        ));
    }


    public  Q whereIn(String column, T value) {
        return whereIn(column, List.of(value));
    }

    public  Q orWhereIn(String column, List values) {
        return or().whereIn(column, values);
    }

    public  Q whereNotIn(String column, List values) {
        return not().whereIn(column, values);
    }

    public  Q orWhereNotIn(String column, List values) {
        return or().not().whereIn(column, values);
    }

    public Q whereIn(String column, Query query) {
        return addComponent("where", new InQueryCondition(
                column,
                getOr(),
                getNot(),
                query
        ));
    }

    public Q whereIn(String column, Function callback) {
        Query query = callback.apply(new Query().setParent(this));
        return whereIn(column, query);
    }

    public Q orWhereIn(String column, Query query) {
        return or().whereIn(column, query);
    }

    public Q orWhereIn(String column, Function callback) {
        return or().whereIn(column, callback);
    }

    public Q whereNotIn(String column, Query query) {
        return not().whereIn(column, query);
    }

    public Q whereNotIn(String column, Function callback) {
        return not().whereIn(column, callback);
    }

    public Q orWhereNotIn(String column, Query query) {
        return or().not().whereIn(column, query);
    }

    public Q orWhereNotIn(String column, Function callback) {
        return or().not().whereIn(column, callback);
    }

    public Q where(String column, String op, Function callback) {
        Q query = callback.apply(newChild());
        return where(column, op, query);
    }

    public Q where(String column, String op, Query query) {
        return addComponent("where", new QueryCondition(
                column,
                op,
                query,
                getOr(),
                getNot()
        ));
    }

    public Q whereSub(Query query, Object value) {
        return whereSub(query, "=", value);
    }

    public Q whereSub(Query query, String op, Object value) {
        return addComponent("where", new SubQueryCondition(
                value,
                op,
                query,
                getOr(),
                getNot()
        ));
    }

    public Q orWhereSub(Query query, Object value) {
        return or().whereSub(query, value);
    }

    public Q orWhereSub(Query query, String op, Object value) {
        return or().whereSub(query, op, value);
    }

    public Q orWhere(String column, String op, Query query) {
        return or().where(column, op, query);
    }

    public Q orWhere(String column, String op, Function callback) {
        return or().where(column, op, callback);
    }

    public Q whereExists(Query query) {
        if (!query.hasComponent("from")) {
            throw new IllegalArgumentException("'" + FromClause.class.getSimpleName() + "' cannot be empty if used inside a whereExists' condition");
        }

        return addComponent("where", new ExistsCondition(
                query,
                getOr(),
                getNot()
        ));
    }

    public Q whereExists(Function callback) {
        Query childQuery = new Query().setParent(this);
        return whereExists(callback.apply(childQuery));
    }

    public Q whereNotExists(Query query) {
        return not().whereExists(query);
    }

    public Q whereNotExists(Function callback) {
        return not().whereExists(callback);
    }

    public Q orWhereExists(Query query) {
        return or().whereExists(query);
    }

    public Q orWhereExists(Function callback) {
        return or().whereExists(callback);
    }

    public Q orWhereNotExists(Query query) {
        return or().not().whereExists(query);
    }

    public Q orWhereNotExists(Function callback) {
        return or().not().whereExists(callback);
    }


    public Q whereDatePart(String part, String column, String op, Object value) {
        return addComponent("where", new BasicDateCondition(
                op,
                column,
                value,
                part != null ? part.toLowerCase() : null,
                getOr(),
                getNot()
        ));
    }

    // WhereNotDatePart
    public Q whereNotDatePart(String part, String column, String op, Object value) {
        return not().whereDatePart(part, column, op, value);
    }

    // OrWhereDatePart
    public Q orWhereDatePart(String part, String column, String op, Object value) {
        return or().whereDatePart(part, column, op, value);
    }

    // OrWhereNotDatePart
    public Q orWhereNotDatePart(String part, String column, String op, Object value) {
        return or().not().whereDatePart(part, column, op, value);
    }

    // WhereDate
    public Q whereDate(String column, String op, Object value) {
        return whereDatePart("date", column, op, value);
    }

    // WhereNotDate
    public Q whereNotDate(String column, String op, Object value) {
        return not().whereDate(column, op, value);
    }

    // OrWhereDate
    public Q orWhereDate(String column, String op, Object value) {
        return or().whereDate(column, op, value);
    }

    // OrWhereNotDate
    public Q orWhereNotDate(String column, String op, Object value) {
        return or().not().whereDate(column, op, value);
    }

    // WhereTime
    public Q whereTime(String column, String op, Object value) {
        return whereDatePart("time", column, op, value);
    }

    // WhereNotTime
    public Q whereNotTime(String column, String op, Object value) {
        return not().whereTime(column, op, value);
    }

    // OrWhereTime
    public Q orWhereTime(String column, String op, Object value) {
        return or().whereTime(column, op, value);
    }

    // OrWhereNotTime
    public Q orWhereNotTime(String column, String op, Object value) {
        return or().not().whereTime(column, op, value);
    }

    // WhereDatePart with equality
    public Q whereDatePart(String part, String column, Object value) {
        return whereDatePart(part, column, "=", value);
    }

    // WhereNotDatePart with equality
    public Q whereNotDatePart(String part, String column, Object value) {
        return whereNotDatePart(part, column, "=", value);
    }

    // OrWhereDatePart with equality
    public Q orWhereDatePart(String part, String column, Object value) {
        return orWhereDatePart(part, column, "=", value);
    }

    // OrWhereNotDatePart with equality
    public Q orWhereNotDatePart(String part, String column, Object value) {
        return orWhereNotDatePart(part, column, "=", value);
    }

    // WhereDate with equality
    public Q whereDate(String column, Object value) {
        return whereDate(column, "=", value);
    }

    // WhereNotDate with equality
    public Q whereNotDate(String column, Object value) {
        return whereNotDate(column, "=", value);
    }

    // OrWhereDate with equality
    public Q orWhereDate(String column, Object value) {
        return orWhereDate(column, "=", value);
    }

    // OrWhereNotDate with equality
    public Q orWhereNotDate(String column, Object value) {
        return orWhereNotDate(column, "=", value);
    }

    // WhereTime with equality
    public Q whereTime(String column, Object value) {
        return whereTime(column, "=", value);
    }

    // WhereNotTime with equality
    public Q whereNotTime(String column, Object value) {
        return whereNotTime(column, "=", value);
    }

    // OrWhereTime with equality
    public Q orWhereTime(String column, Object value) {
        return orWhereTime(column, "=", value);
    }

    // OrWhereNotTime with equality
    public Q orWhereNotTime(String column, Object value) {
        return orWhereNotTime(column, "=", value);
    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy