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

com.github.chengyuxing.sql.dsl.clause.Having Maven / Gradle / Ivy

Go to download

Light wrapper of JDBC, support ddl, dml, query, plsql/procedure/function, transaction and manage sql file.

There is a newer version: 9.0.2
Show newest version
package com.github.chengyuxing.sql.dsl.clause;

import com.github.chengyuxing.common.tuple.Pair;
import com.github.chengyuxing.common.utils.ObjectUtil;
import com.github.chengyuxing.sql.dsl.clause.condition.*;
import com.github.chengyuxing.sql.dsl.types.FieldReference;
import com.github.chengyuxing.sql.dsl.types.Logic;
import com.github.chengyuxing.sql.dsl.types.StandardAggFunction;
import com.github.chengyuxing.sql.dsl.types.StandardOperator;
import com.github.chengyuxing.sql.utils.SqlGenerator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Function;

/**
 * Group by having clause builder.
 *
 * @param  entity type
 */
public abstract class Having extends CriteriaBuilder {
    protected List criteria = new ArrayList<>();

    /**
     * Construct a new Having builder.
     *
     * @param clazz entity class
     */
    protected Having(@NotNull Class clazz) {
        super(clazz);
    }

    /**
     * Construct a new Having builder with initial Having builder.
     *
     * @param clazz entity class
     * @param other having builder
     */
    protected Having(@NotNull Class clazz, Having other) {
        super(clazz);
        this.criteria = other.criteria;
    }

    /**
     * Returns a new Having builder.
     *
     * @return having builder
     */
    protected abstract Having newInstance();

    /**
     * {@code count(*)}
     *
     * @param operator {@link com.github.chengyuxing.sql.dsl.types.StandardOperator StandardOperator}
     * @param value    value
     * @return having builder
     */
    public Having count(StandardOperator operator, Object value) {
        addCondition(StandardAggFunction.COUNT, "*", operator, value);
        return this;
    }

    /**
     * {@code count([column])}
     *
     * @param column   column
     * @param operator {@link com.github.chengyuxing.sql.dsl.types.StandardOperator StandardOperator}
     * @param value    value
     * @return having builder
     */
    public Having count(FieldReference column, StandardOperator operator, Object value) {
        addCondition(StandardAggFunction.COUNT, getColumnName(column), operator, value);
        return this;
    }

    /**
     * {@code sum([column])}
     *
     * @param column   column
     * @param operator {@link com.github.chengyuxing.sql.dsl.types.StandardOperator StandardOperator}
     * @param value    value
     * @return having builder
     */
    public Having sum(FieldReference column, StandardOperator operator, Object value) {
        addCondition(StandardAggFunction.SUM, getColumnName(column), operator, value);
        return this;
    }

    /**
     * {@code avg([column])}
     *
     * @param column   column
     * @param operator {@link com.github.chengyuxing.sql.dsl.types.StandardOperator StandardOperator}
     * @param value    value
     * @return having builder
     */
    public Having avg(FieldReference column, StandardOperator operator, Object value) {
        addCondition(StandardAggFunction.AVG, getColumnName(column), operator, value);
        return this;
    }

    /**
     * {@code min([column])}
     *
     * @param column   column
     * @param operator {@link com.github.chengyuxing.sql.dsl.types.StandardOperator StandardOperator}
     * @param value    value
     * @return having builder
     */
    public Having min(FieldReference column, StandardOperator operator, Object value) {
        addCondition(StandardAggFunction.MIN, getColumnName(column), operator, value);
        return this;
    }

    /**
     * {@code max([column])}
     *
     * @param column   column
     * @param operator {@link com.github.chengyuxing.sql.dsl.types.StandardOperator StandardOperator}
     * @param value    value
     * @return having builder
     */
    public Having max(FieldReference column, StandardOperator operator, Object value) {
        addCondition(StandardAggFunction.MAX, getColumnName(column), operator, value);
        return this;
    }

    /**
     * And group, all condition will be concat with {@code or}, {@code and (...or...or...or...)}
     *
     * @param andGroup and group
     * @return having builder
     * @see Where#and(Function, boolean...)
     */
    public Having and(Function, Having> andGroup) {
        List criteriaList = andGroup.apply(newInstance()).criteria;
        criteria.add(new AndGroup(criteriaList));
        return this;
    }

    /**
     * Or group, all condition will be concat with {@code and}, {@code or (...and...and...and...)}
     *
     * @param orGroup or group
     * @return having builder
     * @see Where#or(Function, boolean...)
     */
    public Having or(Function, Having> orGroup) {
        List criteriaList = orGroup.apply(newInstance()).criteria;
        criteria.add(new OrGroup(criteriaList));
        return this;
    }

    /**
     * Returns a having condition consisting of the having builder, check the built result currently.
     *
     * @param consumer built result consumer (sql, (name parameter sql, params)) -> _
     * @return self
     */
    public Having peek(BiConsumer>> consumer) {
        Pair> where = build();
        String sql = new SqlGenerator(namedParamPrefix()).generateSql(where.getItem1(), where.getItem2());
        consumer.accept(sql, where);
        return this;
    }

    protected @NotNull @Unmodifiable Pair> build() {
        Pair> having = build(new AtomicInteger(1000), criteria, Logic.AND, 0);
        if (!having.getItem1().isEmpty()) {
            return Pair.of("\nhaving " + having.getItem1(), Collections.unmodifiableMap(having.getItem2()));
        }
        return having;
    }

    private void addCondition(StandardAggFunction agg, String column, StandardOperator operator, Object value) {
        String aggColumn = agg.apply(column);
        String valueKey = column.equals("*") ? "all" : column;
        if (operator == StandardOperator.BETWEEN || operator == StandardOperator.NOT_BETWEEN) {
            Object[] arr = ObjectUtil.toArray(value);
            if (arr.length != 2) {
                throw new IllegalArgumentException("between operator must takes two values");
            }
            criteria.add(new BetweenCondition(aggColumn, operator, Pair.of(arr[0], arr[1]), valueKey));
            return;
        }
        if (operator == StandardOperator.IN || operator == StandardOperator.NOT_IN) {
            criteria.add(new InCondition<>(aggColumn, operator, Arrays.asList(ObjectUtil.toArray(value)), valueKey));
            return;
        }
        criteria.add(new Condition<>(aggColumn, operator, value, valueKey));
    }

    @Override
    protected void doCheck(Condition condition) {
        // Unnecessary check.
    }

    @Override
    protected Set columnWhiteList() {
        return Collections.emptySet();
    }

    @Override
    protected Set operatorWhiteList() {
        return Collections.emptySet();
    }
}