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

xyz.erupt.jpa.dao.EruptLambdaQuery Maven / Gradle / Ivy

The newest version!
package xyz.erupt.jpa.dao;

import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
import org.apache.commons.lang3.RandomStringUtils;
import xyz.erupt.jpa.constant.SqlLang;
import xyz.erupt.linq.lambda.LambdaInfo;
import xyz.erupt.linq.lambda.LambdaSee;
import xyz.erupt.linq.lambda.SFunction;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author YuePeng
 * date 2024/3/30 23:23
 */
public class EruptLambdaQuery {

    private final QuerySchema querySchema = new QuerySchema();

    private final EntityManager entityManager;

    private final Class eruptClass;

    public EruptLambdaQuery(EntityManager entityManager, Class eruptClass) {
        this.entityManager = entityManager;
        this.eruptClass = eruptClass;
    }

    public  EruptLambdaQuery isNull(SFunction field) {
        querySchema.getWheres().add(LambdaSee.field(field) + " is null");
        return this;
    }

    public  EruptLambdaQuery isNull(boolean condition, SFunction field) {
        if (condition) return this.isNull(field);
        return this;
    }

    public  EruptLambdaQuery isNotNull(SFunction field) {
        querySchema.getWheres().add(LambdaSee.field(field) + " is not null");
        return this;
    }

    public  EruptLambdaQuery isNotNull(boolean condition, SFunction field) {
        if (condition) return this.isNotNull(field);
        return this;
    }

    public  EruptLambdaQuery eq(SFunction field, Object val) {
        String placeholder = this.genePlaceholder();
        querySchema.getWheres().add(geneField(field) + " = :" + placeholder);
        querySchema.getParams().put(placeholder, val);
        return this;
    }

    public  EruptLambdaQuery eq(boolean condition, SFunction field, Object val) {
        if (condition) return this.eq(field, val);
        return this;
    }

    public  EruptLambdaQuery ne(SFunction field, Object val) {
        String placeholder = this.genePlaceholder();
        querySchema.getWheres().add(LambdaSee.field(field) + " <> :" + placeholder);
        querySchema.getParams().put(placeholder, val);
        return this;
    }

    public  EruptLambdaQuery ne(boolean condition, SFunction field, Object val) {
        if (condition) return this.ne(field, val);
        return this;
    }

    public  EruptLambdaQuery gt(SFunction field, Object val) {
        String placeholder = this.genePlaceholder();
        querySchema.getWheres().add(geneField(field) + " > :" + placeholder);
        querySchema.getParams().put(placeholder, val);
        return this;
    }

    public  EruptLambdaQuery gt(boolean condition, SFunction field, Object val) {
        if (condition) return this.gt(field, val);
        return this;
    }

    public  EruptLambdaQuery lt(SFunction field, Object val) {
        String placeholder = this.genePlaceholder();
        querySchema.getWheres().add(geneField(field) + " < :" + placeholder);
        querySchema.getParams().put(placeholder, val);
        return this;
    }

    public  EruptLambdaQuery lt(boolean condition, SFunction field, Object val) {
        if (condition) return this.lt(field, val);
        return this;
    }

    public  EruptLambdaQuery ge(SFunction field, Object val) {
        String placeholder = this.genePlaceholder();
        querySchema.getWheres().add(geneField(field) + " >= :" + placeholder);
        querySchema.getParams().put(placeholder, val);
        return this;
    }

    public  EruptLambdaQuery ge(boolean condition, SFunction field, Object val) {
        if (condition) return this.ge(field, val);
        return this;
    }

    public  EruptLambdaQuery le(SFunction field, Object val) {
        String placeholder = this.genePlaceholder();
        querySchema.getWheres().add(geneField(field) + " <= :" + placeholder);
        querySchema.getParams().put(placeholder, val);
        return this;
    }

    public  EruptLambdaQuery le(boolean condition, SFunction field, Object val) {
        if (condition) return this.le(field, val);
        return this;
    }

    public  EruptLambdaQuery between(SFunction field, Object val1, Object val2) {
        String l = this.genePlaceholder();
        String r = this.genePlaceholder();
        querySchema.getWheres().add(LambdaSee.field(field) + " between :" + l + " and " + ":" + r);
        querySchema.getParams().put(l, val1);
        querySchema.getParams().put(r, val2);
        return this;
    }

    public  EruptLambdaQuery between(boolean condition, SFunction field, Object val1, Object val2) {
        if (condition) return this.between(field, val1, val2);
        return this;
    }

    public  EruptLambdaQuery in(SFunction field, Collection val) {
        String placeholder = this.genePlaceholder();
        querySchema.getWheres().add(LambdaSee.field(field) + " in (:" + placeholder + ")");
        querySchema.getParams().put(placeholder, new ArrayList<>(val));
        return this;
    }

    public  EruptLambdaQuery in(boolean condition, SFunction field, Collection val) {
        if (condition) return this.in(field, val);
        return this;
    }

    public  EruptLambdaQuery in(SFunction field, Object... val) {
        return this.in(field, Arrays.stream(val).collect(Collectors.toList()));
    }

    public  EruptLambdaQuery in(boolean condition, SFunction field, Object... val) {
        if (condition) return this.in(field, val);
        return this;
    }

    public  EruptLambdaQuery like(SFunction field, Object val) {
        String placeholder = this.genePlaceholder();
        querySchema.getWheres().add(geneField(field) + " like :" + placeholder);
        querySchema.getParams().put(placeholder, "%" + val + "%");
        return this;
    }

    public  EruptLambdaQuery like(boolean condition, SFunction field, Object val) {
        if (condition) return this.like(field, val);
        return this;
    }

    public  EruptLambdaQuery likeValue(SFunction field, Object val) {
        String placeholder = this.genePlaceholder();
        querySchema.getWheres().add(geneField(field) + " like :" + placeholder);
        querySchema.getParams().put(placeholder, val);
        return this;
    }

    public  EruptLambdaQuery likeValue(boolean condition, SFunction field, Object val) {
        if (condition) return this.likeValue(field, val);
        return this;
    }

    //添加条件
    public EruptLambdaQuery addCondition(String condition) {
        querySchema.getWheres().add(condition);
        return this;
    }

    /**
     * 添加自定义条件
     *
     * @param condition :xxx 的占位符可以被 params参数运行时替换,防止 SQL 注入
     * @param params    条件参数
     */
    public EruptLambdaQuery addCondition(String condition, Map params) {
        querySchema.getWheres().add(condition);
        Optional.ofNullable(params).ifPresent(it -> querySchema.getParams().putAll(params));
        return this;
    }

    public EruptLambdaQuery addParam(String key, Object val) {
        querySchema.getParams().put(key, val);
        return this;
    }

    public EruptLambdaQuery orderBy(SFunction field) {
        querySchema.getOrders().add(LambdaSee.field(field) + " asc");
        return this;
    }

    public EruptLambdaQuery orderBy(boolean condition, SFunction field) {
        if (condition) return this.orderBy(field);
        return this;
    }

    public EruptLambdaQuery orderByAsc(SFunction field) {
        return orderBy(field);
    }

    public EruptLambdaQuery orderByAsc(boolean condition, SFunction field) {
        return orderBy(condition, field);
    }


    public EruptLambdaQuery orderByDesc(SFunction field) {
        querySchema.getOrders().add(LambdaSee.field(field) + " desc");
        return this;
    }

    public EruptLambdaQuery orderByDesc(boolean condition, SFunction field) {
        if (condition) return this.orderByDesc(field);
        return this;
    }

    public EruptLambdaQuery limit(Integer limit) {
        querySchema.setLimit(limit);
        return this;
    }

    public EruptLambdaQuery offset(Integer offset) {
        querySchema.setOffset(offset);
        return this;
    }


    public T one() {
        try {
            return (T) this.geneQuery().getSingleResult();
        } catch (NoResultException e) {
            return null;
        }
    }

    public List list() {
        return this.geneQuery().getResultList();
    }

    public final  S oneSelect(SFunction field) {
        this.querySchema.columns.add(LambdaSee.field(field));
        try {
            return (S) this.geneQuery().getSingleResult();
        } catch (NoResultException e) {
            return null;
        }
    }

    public final  List listSelect(SFunction field) {
        this.querySchema.columns.add(LambdaSee.field(field));
        return this.geneQuery().getResultList();
    }

    @SafeVarargs
    public final  List listSelect(Class requiredType, SFunction... fields) {
        for (SFunction field : fields) this.querySchema.columns.add(LambdaSee.field(field));
        List objects = this.geneQuery().getResultList();
        return objects.stream().map(it -> objectToClazz(requiredType, it, fields)).collect(Collectors.toList());
    }

    @SafeVarargs
    public final  R oneSelect(Class requiredType, SFunction... fields) {
        for (SFunction field : fields) this.querySchema.columns.add(LambdaSee.field(field));
        try {
            return objectToClazz(requiredType, (Object[]) this.geneQuery().getSingleResult(), fields);
        } catch (NoResultException e) {
            return null;
        }
    }

    @Deprecated
    @SafeVarargs
    public final List listSelects(SFunction... fields) {
        for (SFunction field : fields) this.querySchema.columns.add(LambdaSee.field(field));
        return this.geneQuery().getResultList();
    }

    @Deprecated
    @SafeVarargs
    public final Object[] oneSelects(SFunction... fields) {
        for (SFunction field : fields) this.querySchema.columns.add(LambdaSee.field(field));
        try {
            return (Object[]) this.geneQuery().getSingleResult();
        } catch (NoResultException e) {
            return null;
        }
    }

    @SneakyThrows
    private  R objectToClazz(Class clazz, Object[] objects, SFunction... fields) {
        R r = clazz.newInstance();
        for (int i = 0; i < fields.length; i++) {
            Field f = clazz.getDeclaredField(LambdaSee.field(fields[i]));
            f.setAccessible(true);
            f.set(r, objects[i]);
        }
        return r;
    }

    public Long count() {
        this.querySchema.columns.add("count(*)");
        return (Long) geneQuery().getSingleResult();
    }

    public Long count(SFunction field) {
        this.querySchema.columns.add("count(" + LambdaSee.field(field) + ")");
        return (Long) geneQuery().getSingleResult();
    }

    public Object sum(SFunction field) {
        this.querySchema.columns.add("sum(" + LambdaSee.field(field) + ")");
        return geneQuery().getSingleResult();
    }

    public Double avg(SFunction field) {
        this.querySchema.columns.add("avg(" + LambdaSee.field(field) + ")");
        return (Double) geneQuery().getSingleResult();
    }

    public Object min(SFunction field) {
        this.querySchema.columns.add("min(" + LambdaSee.field(field) + ")");
        return geneQuery().getSingleResult();
    }

    public Object max(SFunction field) {
        this.querySchema.columns.add("max(" + LambdaSee.field(field) + ")");
        return geneQuery().getSingleResult();
    }

    private Query geneQuery() {
        StringBuilder select = new StringBuilder();
        if (!querySchema.columns.isEmpty()) {
            select.append(SqlLang.SELECT);
            querySchema.getColumns().forEach(it -> select.append(it).append(SqlLang.COMMA));
            select.deleteCharAt(select.length() - 1);
        }
        StringBuilder expr = new StringBuilder(select + SqlLang.FROM + eruptClass.getSimpleName() + SqlLang.AS + eruptClass.getSimpleName());
        if (!querySchema.getWheres().isEmpty())
            expr.append(SqlLang.WHERE).append(String.join(SqlLang.AND, querySchema.getWheres()));
        if (!querySchema.getOrders().isEmpty())
            expr.append(SqlLang.ORDER_BY).append(String.join(SqlLang.COMMA, querySchema.getOrders()));
        Query query = entityManager.createQuery(expr.toString());
        querySchema.getParams().forEach(query::setParameter);
        Optional.ofNullable(querySchema.getLimit()).ifPresent(query::setMaxResults);
        Optional.ofNullable(querySchema.getOffset()).ifPresent(query::setFirstResult);
        return query;
    }

    private String genePlaceholder() {
        return RandomStringUtils.randomAlphabetic(4);
    }

    private String geneField(SFunction field) {
        LambdaInfo lambdaInfo = LambdaSee.info(field);
        return lambdaInfo.getClazz().getSimpleName() + "." + lambdaInfo.getField();
    }

    @Getter
    @Setter
    public static class QuerySchema {

        private List columns = new ArrayList<>();

        private Map params = new HashMap<>();

        private List wheres = new ArrayList<>();

        private List orders = new ArrayList<>();

        private Integer limit;

        private Integer offset;

    }

}