mirror of
https://github.com/dromara/RuoYi-Vue-Plus.git
synced 2026-07-22 04:26:08 +00:00
update 支持 链式调用select sum max min avg count函数
update 支持 select (select *) 与 where (select *) 子查询
This commit is contained in:
+376
@@ -13,7 +13,10 @@ import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
|
||||
import org.dromara.common.mybatis.core.query.AggregateSelectUtils;
|
||||
import org.dromara.common.mybatis.core.query.LambdaQueryCondition;
|
||||
import org.dromara.common.mybatis.core.query.SqlAggregateFunction;
|
||||
import org.dromara.common.mybatis.core.query.SubQuery;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
@@ -21,6 +24,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@@ -124,6 +128,338 @@ public class LambdaCrudChainWrapper<T, V> extends AbstractLambdaWrapper<T, Lambd
|
||||
return select(condition, CollectionUtils.toList(columns));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 SUM 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @return this
|
||||
*/
|
||||
public LambdaCrudChainWrapper<T, V> selectSum(SFunction<T, ?> column) {
|
||||
return selectSum(column, AggregateSelectUtils.aliasName(column));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 SUM 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return this
|
||||
*/
|
||||
public LambdaCrudChainWrapper<T, V> selectSum(SFunction<T, ?> column, String alias) {
|
||||
return selectAggregate(SqlAggregateFunction.SUM, column, alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 SUM 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名字段
|
||||
* @param <A> 查询结果类型
|
||||
* @return this
|
||||
*/
|
||||
public <A> LambdaCrudChainWrapper<T, V> selectSum(SFunction<T, ?> column, SFunction<A, ?> alias) {
|
||||
return selectSum(column, AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 MAX 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @return this
|
||||
*/
|
||||
public LambdaCrudChainWrapper<T, V> selectMax(SFunction<T, ?> column) {
|
||||
return selectMax(column, AggregateSelectUtils.aliasName(column));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 MAX 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return this
|
||||
*/
|
||||
public LambdaCrudChainWrapper<T, V> selectMax(SFunction<T, ?> column, String alias) {
|
||||
return selectAggregate(SqlAggregateFunction.MAX, column, alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 MAX 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名字段
|
||||
* @param <A> 查询结果类型
|
||||
* @return this
|
||||
*/
|
||||
public <A> LambdaCrudChainWrapper<T, V> selectMax(SFunction<T, ?> column, SFunction<A, ?> alias) {
|
||||
return selectMax(column, AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 MIN 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @return this
|
||||
*/
|
||||
public LambdaCrudChainWrapper<T, V> selectMin(SFunction<T, ?> column) {
|
||||
return selectMin(column, AggregateSelectUtils.aliasName(column));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 MIN 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return this
|
||||
*/
|
||||
public LambdaCrudChainWrapper<T, V> selectMin(SFunction<T, ?> column, String alias) {
|
||||
return selectAggregate(SqlAggregateFunction.MIN, column, alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 MIN 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名字段
|
||||
* @param <A> 查询结果类型
|
||||
* @return this
|
||||
*/
|
||||
public <A> LambdaCrudChainWrapper<T, V> selectMin(SFunction<T, ?> column, SFunction<A, ?> alias) {
|
||||
return selectMin(column, AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 AVG 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @return this
|
||||
*/
|
||||
public LambdaCrudChainWrapper<T, V> selectAvg(SFunction<T, ?> column) {
|
||||
return selectAvg(column, AggregateSelectUtils.aliasName(column));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 AVG 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return this
|
||||
*/
|
||||
public LambdaCrudChainWrapper<T, V> selectAvg(SFunction<T, ?> column, String alias) {
|
||||
return selectAggregate(SqlAggregateFunction.AVG, column, alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 AVG 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名字段
|
||||
* @param <A> 查询结果类型
|
||||
* @return this
|
||||
*/
|
||||
public <A> LambdaCrudChainWrapper<T, V> selectAvg(SFunction<T, ?> column, SFunction<A, ?> alias) {
|
||||
return selectAvg(column, AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 COUNT 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @return this
|
||||
*/
|
||||
public LambdaCrudChainWrapper<T, V> selectCount(SFunction<T, ?> column) {
|
||||
return selectCount(column, AggregateSelectUtils.aliasName(column));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 COUNT 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return this
|
||||
*/
|
||||
public LambdaCrudChainWrapper<T, V> selectCount(SFunction<T, ?> column, String alias) {
|
||||
return selectAggregate(SqlAggregateFunction.COUNT, column, alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 COUNT 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名字段
|
||||
* @param <A> 查询结果类型
|
||||
* @return this
|
||||
*/
|
||||
public <A> LambdaCrudChainWrapper<T, V> selectCount(SFunction<T, ?> column, SFunction<A, ?> alias) {
|
||||
return selectCount(column, AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 COUNT(*) 聚合查询字段。
|
||||
*
|
||||
* @param alias 查询别名
|
||||
* @return this
|
||||
*/
|
||||
public LambdaCrudChainWrapper<T, V> selectCountAll(String alias) {
|
||||
return selectAggregate(SqlAggregateFunction.COUNT, "*", alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 COUNT(*) 聚合查询字段。
|
||||
*
|
||||
* @param alias 查询别名字段
|
||||
* @param <A> 查询结果类型
|
||||
* @return this
|
||||
*/
|
||||
public <A> LambdaCrudChainWrapper<T, V> selectCountAll(SFunction<A, ?> alias) {
|
||||
return selectCountAll(AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 COUNT(DISTINCT column) 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return this
|
||||
*/
|
||||
public LambdaCrudChainWrapper<T, V> selectCountDistinct(SFunction<T, ?> column, String alias) {
|
||||
return selectAggregate(SqlAggregateFunction.COUNT, "DISTINCT " + columnToString(column), alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 COUNT(DISTINCT column) 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名字段
|
||||
* @param <A> 查询结果类型
|
||||
* @return this
|
||||
*/
|
||||
public <A> LambdaCrudChainWrapper<T, V> selectCountDistinct(SFunction<T, ?> column, SFunction<A, ?> alias) {
|
||||
return selectCountDistinct(column, AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定子查询字段。
|
||||
* <pre>{@code
|
||||
* userMapper.lambda()
|
||||
* .select(SysUser::getUserId, SysUser::getUserName)
|
||||
* .selectSub(SysUserRole.class, sub -> sub
|
||||
* .selectCountAll()
|
||||
* .eqColumn(SysUserRole::getUserId, SysUser::getUserId),
|
||||
* UserStatVo::getRoleCount)
|
||||
* .voList();
|
||||
* }</pre>
|
||||
*
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param alias 查询别名
|
||||
* @param <S> 子查询实体类型
|
||||
* @return this
|
||||
*/
|
||||
public <S> LambdaCrudChainWrapper<T, V> selectSub(Class<S> entityClass, Consumer<SubQuery<S>> consumer, String alias) {
|
||||
sqlSelect.setStringValue(AggregateSelectUtils.appendSelect(sqlSelect.getStringValue(),
|
||||
AggregateSelectUtils.subquerySelect(buildSubQuery(entityClass, consumer), alias)));
|
||||
return typedThis;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定子查询字段。
|
||||
*
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param alias 查询别名字段
|
||||
* @param <S> 子查询实体类型
|
||||
* @param <A> 查询结果类型
|
||||
* @return this
|
||||
*/
|
||||
public <S, A> LambdaCrudChainWrapper<T, V> selectSub(Class<S> entityClass, Consumer<SubQuery<S>> consumer, SFunction<A, ?> alias) {
|
||||
return selectSub(entityClass, consumer, AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加等于子查询条件。
|
||||
* <pre>{@code
|
||||
* userMapper.lambda()
|
||||
* .eqSub(SysUser::getDeptId, SysDept.class, sub -> sub
|
||||
* .select(SysDept::getDeptId)
|
||||
* .eq(SysDept::getDeptName, deptName))
|
||||
* .voList();
|
||||
* }</pre>
|
||||
*
|
||||
* @param column 字段
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param <S> 子查询实体类型
|
||||
* @return this
|
||||
*/
|
||||
public <S> LambdaCrudChainWrapper<T, V> eqSub(SFunction<T, ?> column, Class<S> entityClass, Consumer<SubQuery<S>> consumer) {
|
||||
return super.eqSql(true, column, buildSubQuery(entityClass, consumer));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 IN 子查询条件。
|
||||
* <pre>{@code
|
||||
* userMapper.lambda()
|
||||
* .inSub(SysUser::getUserId, SysUserRole.class, sub -> sub
|
||||
* .select(SysUserRole::getUserId)
|
||||
* .eq(SysUserRole::getRoleId, roleId))
|
||||
* .voList();
|
||||
* }</pre>
|
||||
*
|
||||
* @param column 字段
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param <S> 子查询实体类型
|
||||
* @return this
|
||||
*/
|
||||
public <S> LambdaCrudChainWrapper<T, V> inSub(SFunction<T, ?> column, Class<S> entityClass, Consumer<SubQuery<S>> consumer) {
|
||||
return super.inSql(true, column, buildSubQuery(entityClass, consumer));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 NOT IN 子查询条件。
|
||||
*
|
||||
* @param column 字段
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param <S> 子查询实体类型
|
||||
* @return this
|
||||
*/
|
||||
public <S> LambdaCrudChainWrapper<T, V> notInSub(SFunction<T, ?> column, Class<S> entityClass, Consumer<SubQuery<S>> consumer) {
|
||||
return super.notInSql(true, column, buildSubQuery(entityClass, consumer));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 EXISTS 子查询条件。
|
||||
* <pre>{@code
|
||||
* userMapper.lambda()
|
||||
* .existsSub(SysUserRole.class, sub -> sub
|
||||
* .selectCountAll()
|
||||
* .eqColumn(SysUserRole::getUserId, SysUser::getUserId)
|
||||
* .eq(SysUserRole::getRoleId, roleId))
|
||||
* .voList();
|
||||
* }</pre>
|
||||
*
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param <S> 子查询实体类型
|
||||
* @return this
|
||||
*/
|
||||
public <S> LambdaCrudChainWrapper<T, V> existsSub(Class<S> entityClass, Consumer<SubQuery<S>> consumer) {
|
||||
return super.exists(true, buildSubQuery(entityClass, consumer));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 NOT EXISTS 子查询条件。
|
||||
*
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param <S> 子查询实体类型
|
||||
* @return this
|
||||
*/
|
||||
public <S> LambdaCrudChainWrapper<T, V> notExistsSub(Class<S> entityClass, Consumer<SubQuery<S>> consumer) {
|
||||
return super.notExists(true, buildSubQuery(entityClass, consumer));
|
||||
}
|
||||
|
||||
/**
|
||||
* 按字段过滤条件选择查询字段。
|
||||
*
|
||||
@@ -153,6 +489,46 @@ public class LambdaCrudChainWrapper<T, V> extends AbstractLambdaWrapper<T, Lambd
|
||||
return sqlSelect.getStringValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定聚合查询字段。
|
||||
*
|
||||
* @param function 聚合函数
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return this
|
||||
*/
|
||||
private LambdaCrudChainWrapper<T, V> selectAggregate(SqlAggregateFunction function, SFunction<T, ?> column, String alias) {
|
||||
return selectAggregate(function, columnToString(column), alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定聚合查询字段。
|
||||
*
|
||||
* @param function 聚合函数
|
||||
* @param column 聚合字段 SQL
|
||||
* @param alias 查询别名
|
||||
* @return this
|
||||
*/
|
||||
private LambdaCrudChainWrapper<T, V> selectAggregate(SqlAggregateFunction function, String column, String alias) {
|
||||
sqlSelect.setStringValue(AggregateSelectUtils.appendSelect(sqlSelect.getStringValue(),
|
||||
AggregateSelectUtils.aggregateSelect(function, column, alias)));
|
||||
return typedThis;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建子查询 SQL。
|
||||
*
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param <S> 子查询实体类型
|
||||
* @return 子查询 SQL
|
||||
*/
|
||||
private <S> String buildSubQuery(Class<S> entityClass, Consumer<SubQuery<S>> consumer) {
|
||||
SubQuery<S> subQuery = SubQuery.of(entityClass, value -> formatParam(null, value));
|
||||
consumer.accept(subQuery);
|
||||
return subQuery.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 按条件设置更新字段。
|
||||
*
|
||||
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
package org.dromara.common.mybatis.core.query;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
|
||||
|
||||
/**
|
||||
* 支持追加聚合查询字段的 Lambda 查询包装器。
|
||||
*
|
||||
* @param <T> 实体类型
|
||||
* @author Lion Li
|
||||
*/
|
||||
class AggregateLambdaQueryWrapper<T> extends LambdaQueryWrapper<T> {
|
||||
|
||||
private String aggregateSqlSelect;
|
||||
|
||||
AggregateLambdaQueryWrapper(Class<T> entityClass) {
|
||||
super(entityClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加聚合查询字段。
|
||||
*
|
||||
* @param columnSql 查询字段 SQL
|
||||
*/
|
||||
void appendSelectSql(String columnSql) {
|
||||
aggregateSqlSelect = AggregateSelectUtils.appendSelect(getSqlSelect(), columnSql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加子查询字段。
|
||||
*
|
||||
* @param subquerySql 子查询 SQL
|
||||
* @param alias 查询别名
|
||||
* @param params 子查询参数
|
||||
*/
|
||||
void appendSelectSub(String subquerySql, String alias, Object... params) {
|
||||
appendSelectSql(AggregateSelectUtils.subquerySelect(formatSqlMaybeWithParam(subquerySql, params), alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化子查询 SQL。
|
||||
*
|
||||
* @param subquerySql 子查询 SQL
|
||||
* @param params 子查询参数
|
||||
* @return 格式化后的子查询 SQL
|
||||
*/
|
||||
String formatSubquerySql(String subquerySql, Object... params) {
|
||||
return formatSqlMaybeWithParam(subquerySql, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化子查询参数。
|
||||
*
|
||||
* @param value 参数值
|
||||
* @return MyBatis 参数占位符
|
||||
*/
|
||||
String formatSubqueryParam(Object value) {
|
||||
return formatParam(null, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空聚合查询字段。
|
||||
*/
|
||||
void resetAggregateSelect() {
|
||||
aggregateSqlSelect = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字段对应的数据库列名。
|
||||
*
|
||||
* @param column 字段
|
||||
* @return 数据库列名
|
||||
*/
|
||||
String columnName(SFunction<T, ?> column) {
|
||||
return columnToString(column);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSqlSelect() {
|
||||
if (aggregateSqlSelect != null) {
|
||||
return aggregateSqlSelect;
|
||||
}
|
||||
return super.getSqlSelect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
super.clear();
|
||||
aggregateSqlSelect = null;
|
||||
}
|
||||
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package org.dromara.common.mybatis.core.query;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Assert;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.LambdaMeta;
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
|
||||
import org.apache.ibatis.reflection.property.PropertyNamer;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 聚合查询字段 SQL 构造工具。
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public final class AggregateSelectUtils {
|
||||
|
||||
private static final Pattern ALIAS_PATTERN = Pattern.compile("[A-Za-z_][A-Za-z0-9_]*");
|
||||
|
||||
private AggregateSelectUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加查询字段 SQL。
|
||||
*
|
||||
* @param current 已有查询字段 SQL
|
||||
* @param fragment 新增查询字段 SQL
|
||||
* @return 合并后的查询字段 SQL
|
||||
*/
|
||||
public static String appendSelect(String current, String fragment) {
|
||||
if (StringUtils.isBlank(current)) {
|
||||
return fragment;
|
||||
}
|
||||
return current + Constants.COMMA + fragment;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成聚合查询字段 SQL。
|
||||
*
|
||||
* @param function 聚合函数
|
||||
* @param column 字段 SQL
|
||||
* @param alias 查询别名
|
||||
* @return 聚合查询字段 SQL
|
||||
*/
|
||||
public static String aggregateSelect(SqlAggregateFunction function, String column, String alias) {
|
||||
return function.format(column) + " AS " + checkAlias(alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成子查询字段 SQL。
|
||||
*
|
||||
* @param subquerySql 子查询 SQL
|
||||
* @param alias 查询别名
|
||||
* @return 子查询字段 SQL
|
||||
*/
|
||||
public static String subquerySelect(String subquerySql, String alias) {
|
||||
return "(" + subquerySql + ") AS " + checkAlias(alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 Lambda Getter 解析属性名作为查询别名。
|
||||
*
|
||||
* @param alias 别名字段 Getter
|
||||
* @return 查询别名
|
||||
*/
|
||||
public static String aliasName(SFunction<?, ?> alias) {
|
||||
LambdaMeta meta = com.baomidou.mybatisplus.core.toolkit.LambdaUtils.extract(alias);
|
||||
return PropertyNamer.methodToProperty(meta.getImplMethodName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查查询别名是否为通用 SQL 标识符。
|
||||
*
|
||||
* @param alias 查询别名
|
||||
* @return 查询别名
|
||||
*/
|
||||
public static String checkAlias(String alias) {
|
||||
Assert.isTrue(StringUtils.isNotBlank(alias) && ALIAS_PATTERN.matcher(alias).matches(),
|
||||
"查询别名只能包含字母、数字、下划线且不能以数字开头: %s", alias);
|
||||
return alias;
|
||||
}
|
||||
|
||||
}
|
||||
+350
@@ -1,10 +1,12 @@
|
||||
package org.dromara.common.mybatis.core.query;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.StringPool;
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
|
||||
import com.github.yulichang.toolkit.LambdaUtils;
|
||||
import com.github.yulichang.toolkit.support.ColumnCache;
|
||||
import com.github.yulichang.wrapper.MPJLambdaWrapper;
|
||||
import com.github.yulichang.wrapper.enums.DefaultFuncEnum;
|
||||
import com.github.yulichang.wrapper.segments.SelectCache;
|
||||
import com.github.yulichang.wrapper.segments.SelectNormal;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
@@ -149,6 +151,343 @@ public final class LambdaJoinQueryBuilder<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定子查询字段。
|
||||
* <pre>{@code
|
||||
* QueryBuilder.lambdaJoin("u", SysUser.class)
|
||||
* .selectAs("u", SysUser::getUserId, UserStatVo::getUserId)
|
||||
* .selectSub(SysUserRole.class, sub -> sub
|
||||
* .selectCountAll()
|
||||
* .eqColumn(SysUserRole::getUserId, "u", SysUser::getUserId),
|
||||
* UserStatVo::getRoleCount)
|
||||
* .list(UserStatVo.class);
|
||||
* }</pre>
|
||||
*
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param alias 查询别名
|
||||
* @param <S> 子查询实体类型
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <S> LambdaJoinQueryBuilder<T> selectSub(Class<S> entityClass, Consumer<SubQuery<S>> consumer, String alias) {
|
||||
SubQuery<S> subQuery = buildPlaceholderSubQuery(entityClass, consumer);
|
||||
wrapper.selectFunc("(" + subQuery.build() + ")", func -> func.values(subQuery.params()),
|
||||
AggregateSelectUtils.checkAlias(alias));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定子查询字段。
|
||||
*
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param alias 查询别名字段
|
||||
* @param <S> 子查询实体类型
|
||||
* @param <X> 查询结果类型
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <S, X> LambdaJoinQueryBuilder<T> selectSub(Class<S> entityClass, Consumer<SubQuery<S>> consumer, SFunction<X, ?> alias) {
|
||||
return selectSub(entityClass, consumer, AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 SUM 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <S> LambdaJoinQueryBuilder<T> selectSum(SFunction<S, ?> column, String alias) {
|
||||
wrapper.selectSum(column, AggregateSelectUtils.checkAlias(alias));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 SUM 聚合查询字段。
|
||||
*
|
||||
* @param tableAlias 表别名
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <S> LambdaJoinQueryBuilder<T> selectSum(String tableAlias, SFunction<S, ?> column, String alias) {
|
||||
wrapper.selectFunc(DefaultFuncEnum.SUM, tableAlias, column, AggregateSelectUtils.checkAlias(alias));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 SUM 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名字段
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <S, X> LambdaJoinQueryBuilder<T> selectSum(SFunction<S, ?> column, SFunction<X, ?> alias) {
|
||||
return selectSum(column, AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 MAX 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <S> LambdaJoinQueryBuilder<T> selectMax(SFunction<S, ?> column, String alias) {
|
||||
wrapper.selectMax(column, AggregateSelectUtils.checkAlias(alias));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 MAX 聚合查询字段。
|
||||
*
|
||||
* @param tableAlias 表别名
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <S> LambdaJoinQueryBuilder<T> selectMax(String tableAlias, SFunction<S, ?> column, String alias) {
|
||||
wrapper.selectFunc(DefaultFuncEnum.MAX, tableAlias, column, AggregateSelectUtils.checkAlias(alias));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 MAX 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名字段
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <S, X> LambdaJoinQueryBuilder<T> selectMax(SFunction<S, ?> column, SFunction<X, ?> alias) {
|
||||
return selectMax(column, AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 MIN 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <S> LambdaJoinQueryBuilder<T> selectMin(SFunction<S, ?> column, String alias) {
|
||||
wrapper.selectMin(column, AggregateSelectUtils.checkAlias(alias));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 MIN 聚合查询字段。
|
||||
*
|
||||
* @param tableAlias 表别名
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <S> LambdaJoinQueryBuilder<T> selectMin(String tableAlias, SFunction<S, ?> column, String alias) {
|
||||
wrapper.selectFunc(DefaultFuncEnum.MIN, tableAlias, column, AggregateSelectUtils.checkAlias(alias));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 MIN 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名字段
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <S, X> LambdaJoinQueryBuilder<T> selectMin(SFunction<S, ?> column, SFunction<X, ?> alias) {
|
||||
return selectMin(column, AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 AVG 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <S> LambdaJoinQueryBuilder<T> selectAvg(SFunction<S, ?> column, String alias) {
|
||||
wrapper.selectAvg(column, AggregateSelectUtils.checkAlias(alias));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 AVG 聚合查询字段。
|
||||
*
|
||||
* @param tableAlias 表别名
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <S> LambdaJoinQueryBuilder<T> selectAvg(String tableAlias, SFunction<S, ?> column, String alias) {
|
||||
wrapper.selectFunc(DefaultFuncEnum.AVG, tableAlias, column, AggregateSelectUtils.checkAlias(alias));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 AVG 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名字段
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <S, X> LambdaJoinQueryBuilder<T> selectAvg(SFunction<S, ?> column, SFunction<X, ?> alias) {
|
||||
return selectAvg(column, AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 COUNT 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <S> LambdaJoinQueryBuilder<T> selectCount(SFunction<S, ?> column, String alias) {
|
||||
wrapper.selectCount(column, AggregateSelectUtils.checkAlias(alias));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 COUNT 聚合查询字段。
|
||||
*
|
||||
* @param tableAlias 表别名
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <S> LambdaJoinQueryBuilder<T> selectCount(String tableAlias, SFunction<S, ?> column, String alias) {
|
||||
wrapper.selectFunc(DefaultFuncEnum.COUNT, tableAlias, column, AggregateSelectUtils.checkAlias(alias));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 COUNT 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名字段
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <S, X> LambdaJoinQueryBuilder<T> selectCount(SFunction<S, ?> column, SFunction<X, ?> alias) {
|
||||
return selectCount(column, AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 COUNT(*) 聚合查询字段。
|
||||
*
|
||||
* @param alias 查询别名
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public LambdaJoinQueryBuilder<T> selectCountAll(String alias) {
|
||||
wrapper.select(AggregateSelectUtils.aggregateSelect(SqlAggregateFunction.COUNT, "*", alias));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 COUNT(*) 聚合查询字段。
|
||||
*
|
||||
* @param alias 查询别名字段
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <X> LambdaJoinQueryBuilder<T> selectCountAll(SFunction<X, ?> alias) {
|
||||
return selectCountAll(AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加等于子查询条件。
|
||||
*
|
||||
* @param alias 表别名
|
||||
* @param column 字段
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param <S> 字段实体类型
|
||||
* @param <Q> 子查询实体类型
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <S, Q> LambdaJoinQueryBuilder<T> eqSub(String alias, SFunction<S, ?> column, Class<Q> entityClass,
|
||||
Consumer<SubQuery<Q>> consumer) {
|
||||
SubQuery<Q> subQuery = buildPlaceholderSubQuery(entityClass, consumer);
|
||||
wrapper.apply(true, qualifiedColumn(alias, column) + " = (" + subQuery.build() + ")", subQuery.params());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 IN 子查询条件。
|
||||
* <pre>{@code
|
||||
* QueryBuilder.lambdaJoin("u", SysUser.class)
|
||||
* .inSub("u", SysUser::getUserId, SysUserRole.class, sub -> sub
|
||||
* .select(SysUserRole::getUserId)
|
||||
* .eq(SysUserRole::getRoleId, roleId))
|
||||
* .list(SysUserVo.class);
|
||||
* }</pre>
|
||||
*
|
||||
* @param alias 表别名
|
||||
* @param column 字段
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param <S> 字段实体类型
|
||||
* @param <Q> 子查询实体类型
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <S, Q> LambdaJoinQueryBuilder<T> inSub(String alias, SFunction<S, ?> column, Class<Q> entityClass,
|
||||
Consumer<SubQuery<Q>> consumer) {
|
||||
SubQuery<Q> subQuery = buildPlaceholderSubQuery(entityClass, consumer);
|
||||
wrapper.apply(true, qualifiedColumn(alias, column) + " IN (" + subQuery.build() + ")", subQuery.params());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 NOT IN 子查询条件。
|
||||
*
|
||||
* @param alias 表别名
|
||||
* @param column 字段
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param <S> 字段实体类型
|
||||
* @param <Q> 子查询实体类型
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <S, Q> LambdaJoinQueryBuilder<T> notInSub(String alias, SFunction<S, ?> column, Class<Q> entityClass,
|
||||
Consumer<SubQuery<Q>> consumer) {
|
||||
SubQuery<Q> subQuery = buildPlaceholderSubQuery(entityClass, consumer);
|
||||
wrapper.apply(true, qualifiedColumn(alias, column) + " NOT IN (" + subQuery.build() + ")", subQuery.params());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 EXISTS 子查询条件。
|
||||
* <pre>{@code
|
||||
* QueryBuilder.lambdaJoin("u", SysUser.class)
|
||||
* .existsSub(SysUserRole.class, sub -> sub
|
||||
* .selectCountAll()
|
||||
* .eqColumn(SysUserRole::getUserId, "u", SysUser::getUserId)
|
||||
* .eq(SysUserRole::getRoleId, roleId))
|
||||
* .list(SysUserVo.class);
|
||||
* }</pre>
|
||||
*
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param <Q> 子查询实体类型
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <Q> LambdaJoinQueryBuilder<T> existsSub(Class<Q> entityClass, Consumer<SubQuery<Q>> consumer) {
|
||||
SubQuery<Q> subQuery = buildPlaceholderSubQuery(entityClass, consumer);
|
||||
wrapper.apply(true, "EXISTS (" + subQuery.build() + ")", subQuery.params());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 NOT EXISTS 子查询条件。
|
||||
*
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param <Q> 子查询实体类型
|
||||
* @return 当前联表查询构造辅助对象
|
||||
*/
|
||||
public <Q> LambdaJoinQueryBuilder<T> notExistsSub(Class<Q> entityClass, Consumer<SubQuery<Q>> consumer) {
|
||||
SubQuery<Q> subQuery = buildPlaceholderSubQuery(entityClass, consumer);
|
||||
wrapper.apply(true, "NOT EXISTS (" + subQuery.build() + ")", subQuery.params());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加左联表。
|
||||
*
|
||||
@@ -577,4 +916,15 @@ public final class LambdaJoinQueryBuilder<T> {
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
private <Q> SubQuery<Q> buildPlaceholderSubQuery(Class<Q> entityClass, Consumer<SubQuery<Q>> consumer) {
|
||||
SubQuery<Q> subQuery = SubQuery.ofPlaceholders(entityClass);
|
||||
consumer.accept(subQuery);
|
||||
return subQuery;
|
||||
}
|
||||
|
||||
private <S> String qualifiedColumn(String alias, SFunction<S, ?> column) {
|
||||
return AggregateSelectUtils.checkAlias(alias) + StringPool.DOT + ColumnCache.getMapField(LambdaUtils.getEntityClass(column))
|
||||
.get(LambdaUtils.getName(column)).getColumn();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+386
@@ -39,10 +39,347 @@ public final class LambdaQueryBuilder<T> implements LambdaQueryCondition<T, Lamb
|
||||
*/
|
||||
@SafeVarargs
|
||||
public final LambdaQueryBuilder<T> select(SFunction<T, ?>... columns) {
|
||||
aggregateWrapper().resetAggregateSelect();
|
||||
wrapper.select(columns);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 SUM 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public LambdaQueryBuilder<T> selectSum(SFunction<T, ?> column) {
|
||||
return selectSum(column, AggregateSelectUtils.aliasName(column));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 SUM 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public LambdaQueryBuilder<T> selectSum(SFunction<T, ?> column, String alias) {
|
||||
return selectAggregate(SqlAggregateFunction.SUM, column, alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 SUM 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名字段
|
||||
* @param <A> 查询结果类型
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public <A> LambdaQueryBuilder<T> selectSum(SFunction<T, ?> column, SFunction<A, ?> alias) {
|
||||
return selectSum(column, AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 MAX 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public LambdaQueryBuilder<T> selectMax(SFunction<T, ?> column) {
|
||||
return selectMax(column, AggregateSelectUtils.aliasName(column));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 MAX 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public LambdaQueryBuilder<T> selectMax(SFunction<T, ?> column, String alias) {
|
||||
return selectAggregate(SqlAggregateFunction.MAX, column, alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 MAX 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名字段
|
||||
* @param <A> 查询结果类型
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public <A> LambdaQueryBuilder<T> selectMax(SFunction<T, ?> column, SFunction<A, ?> alias) {
|
||||
return selectMax(column, AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 MIN 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public LambdaQueryBuilder<T> selectMin(SFunction<T, ?> column) {
|
||||
return selectMin(column, AggregateSelectUtils.aliasName(column));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 MIN 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public LambdaQueryBuilder<T> selectMin(SFunction<T, ?> column, String alias) {
|
||||
return selectAggregate(SqlAggregateFunction.MIN, column, alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 MIN 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名字段
|
||||
* @param <A> 查询结果类型
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public <A> LambdaQueryBuilder<T> selectMin(SFunction<T, ?> column, SFunction<A, ?> alias) {
|
||||
return selectMin(column, AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 AVG 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public LambdaQueryBuilder<T> selectAvg(SFunction<T, ?> column) {
|
||||
return selectAvg(column, AggregateSelectUtils.aliasName(column));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 AVG 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public LambdaQueryBuilder<T> selectAvg(SFunction<T, ?> column, String alias) {
|
||||
return selectAggregate(SqlAggregateFunction.AVG, column, alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 AVG 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名字段
|
||||
* @param <A> 查询结果类型
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public <A> LambdaQueryBuilder<T> selectAvg(SFunction<T, ?> column, SFunction<A, ?> alias) {
|
||||
return selectAvg(column, AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 COUNT 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public LambdaQueryBuilder<T> selectCount(SFunction<T, ?> column) {
|
||||
return selectCount(column, AggregateSelectUtils.aliasName(column));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 COUNT 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public LambdaQueryBuilder<T> selectCount(SFunction<T, ?> column, String alias) {
|
||||
return selectAggregate(SqlAggregateFunction.COUNT, column, alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 COUNT 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名字段
|
||||
* @param <A> 查询结果类型
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public <A> LambdaQueryBuilder<T> selectCount(SFunction<T, ?> column, SFunction<A, ?> alias) {
|
||||
return selectCount(column, AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 COUNT(*) 聚合查询字段。
|
||||
*
|
||||
* @param alias 查询别名
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public LambdaQueryBuilder<T> selectCountAll(String alias) {
|
||||
return selectAggregate(SqlAggregateFunction.COUNT, "*", alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 COUNT(*) 聚合查询字段。
|
||||
*
|
||||
* @param alias 查询别名字段
|
||||
* @param <A> 查询结果类型
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public <A> LambdaQueryBuilder<T> selectCountAll(SFunction<A, ?> alias) {
|
||||
return selectCountAll(AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 COUNT(DISTINCT column) 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public LambdaQueryBuilder<T> selectCountDistinct(SFunction<T, ?> column, String alias) {
|
||||
return selectAggregate(SqlAggregateFunction.COUNT, "DISTINCT " + aggregateWrapper().columnName(column), alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 COUNT(DISTINCT column) 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名字段
|
||||
* @param <A> 查询结果类型
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public <A> LambdaQueryBuilder<T> selectCountDistinct(SFunction<T, ?> column, SFunction<A, ?> alias) {
|
||||
return selectCountDistinct(column, AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定子查询字段。
|
||||
* <pre>{@code
|
||||
* QueryBuilder.lambda(SysUser.class)
|
||||
* .select(SysUser::getUserId, SysUser::getUserName)
|
||||
* .selectSub(SysUserRole.class, sub -> sub
|
||||
* .selectCountAll()
|
||||
* .eqColumn(SysUserRole::getUserId, SysUser::getUserId),
|
||||
* UserStatVo::getRoleCount)
|
||||
* .build();
|
||||
* }</pre>
|
||||
*
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param alias 查询别名
|
||||
* @param <S> 子查询实体类型
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public <S> LambdaQueryBuilder<T> selectSub(Class<S> entityClass, Consumer<SubQuery<S>> consumer, String alias) {
|
||||
aggregateWrapper().appendSelectSql(AggregateSelectUtils.subquerySelect(buildSubQuery(entityClass, consumer), alias));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定子查询字段。
|
||||
*
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param alias 查询别名字段
|
||||
* @param <S> 子查询实体类型
|
||||
* @param <A> 查询结果类型
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public <S, A> LambdaQueryBuilder<T> selectSub(Class<S> entityClass, Consumer<SubQuery<S>> consumer, SFunction<A, ?> alias) {
|
||||
return selectSub(entityClass, consumer, AggregateSelectUtils.aliasName(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加等于子查询条件。
|
||||
* <pre>{@code
|
||||
* QueryBuilder.lambda(SysUser.class)
|
||||
* .eqSub(SysUser::getDeptId, SysDept.class, sub -> sub
|
||||
* .select(SysDept::getDeptId)
|
||||
* .eq(SysDept::getDeptName, deptName))
|
||||
* .build();
|
||||
* }</pre>
|
||||
*
|
||||
* @param column 字段
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param <S> 子查询实体类型
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public <S> LambdaQueryBuilder<T> eqSub(SFunction<T, ?> column, Class<S> entityClass, Consumer<SubQuery<S>> consumer) {
|
||||
wrapper.eqSql(column, buildSubQuery(entityClass, consumer));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 IN 子查询条件。
|
||||
* <pre>{@code
|
||||
* QueryBuilder.lambda(SysUser.class)
|
||||
* .inSub(SysUser::getUserId, SysUserRole.class, sub -> sub
|
||||
* .select(SysUserRole::getUserId)
|
||||
* .eq(SysUserRole::getRoleId, roleId))
|
||||
* .build();
|
||||
* }</pre>
|
||||
*
|
||||
* @param column 字段
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param <S> 子查询实体类型
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public <S> LambdaQueryBuilder<T> inSub(SFunction<T, ?> column, Class<S> entityClass, Consumer<SubQuery<S>> consumer) {
|
||||
wrapper.inSql(column, buildSubQuery(entityClass, consumer));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 NOT IN 子查询条件。
|
||||
*
|
||||
* @param column 字段
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param <S> 子查询实体类型
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public <S> LambdaQueryBuilder<T> notInSub(SFunction<T, ?> column, Class<S> entityClass, Consumer<SubQuery<S>> consumer) {
|
||||
wrapper.notInSql(column, buildSubQuery(entityClass, consumer));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 EXISTS 子查询条件。
|
||||
* <pre>{@code
|
||||
* QueryBuilder.lambda(SysUser.class)
|
||||
* .existsSub(SysUserRole.class, sub -> sub
|
||||
* .selectCountAll()
|
||||
* .eqColumn(SysUserRole::getUserId, SysUser::getUserId)
|
||||
* .eq(SysUserRole::getRoleId, roleId))
|
||||
* .build();
|
||||
* }</pre>
|
||||
*
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param <S> 子查询实体类型
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public <S> LambdaQueryBuilder<T> existsSub(Class<S> entityClass, Consumer<SubQuery<S>> consumer) {
|
||||
wrapper.exists(buildSubQuery(entityClass, consumer));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 NOT EXISTS 子查询条件。
|
||||
*
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param <S> 子查询实体类型
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
public <S> LambdaQueryBuilder<T> notExistsSub(Class<S> entityClass, Consumer<SubQuery<S>> consumer) {
|
||||
wrapper.notExists(buildSubQuery(entityClass, consumer));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加等于条件。
|
||||
*
|
||||
@@ -987,4 +1324,53 @@ public final class LambdaQueryBuilder<T> implements LambdaQueryCondition<T, Lamb
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定聚合查询字段。
|
||||
*
|
||||
* @param function 聚合函数
|
||||
* @param column 聚合字段
|
||||
* @param alias 查询别名
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
private LambdaQueryBuilder<T> selectAggregate(SqlAggregateFunction function, SFunction<T, ?> column, String alias) {
|
||||
return selectAggregate(function, aggregateWrapper().columnName(column), alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定聚合查询字段。
|
||||
*
|
||||
* @param function 聚合函数
|
||||
* @param column 聚合字段 SQL
|
||||
* @param alias 查询别名
|
||||
* @return 当前查询构造辅助对象
|
||||
*/
|
||||
private LambdaQueryBuilder<T> selectAggregate(SqlAggregateFunction function, String column, String alias) {
|
||||
aggregateWrapper().appendSelectSql(AggregateSelectUtils.aggregateSelect(function, column, alias));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建子查询 SQL。
|
||||
*
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param consumer 子查询构造函数
|
||||
* @param <S> 子查询实体类型
|
||||
* @return 子查询 SQL
|
||||
*/
|
||||
private <S> String buildSubQuery(Class<S> entityClass, Consumer<SubQuery<S>> consumer) {
|
||||
SubQuery<S> subQuery = SubQuery.of(entityClass, aggregateWrapper()::formatSubqueryParam);
|
||||
consumer.accept(subQuery);
|
||||
return subQuery.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取支持聚合查询字段的包装器。
|
||||
*
|
||||
* @return 聚合查询包装器
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private AggregateLambdaQueryWrapper<T> aggregateWrapper() {
|
||||
return (AggregateLambdaQueryWrapper<T>) wrapper;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-2
@@ -1,6 +1,5 @@
|
||||
package org.dromara.common.mybatis.core.query;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.github.yulichang.toolkit.JoinWrappers;
|
||||
|
||||
/**
|
||||
@@ -21,7 +20,7 @@ public final class QueryBuilder {
|
||||
* @return Lambda 查询构造辅助对象
|
||||
*/
|
||||
public static <T> LambdaQueryBuilder<T> lambda(Class<T> entityClass) {
|
||||
return new LambdaQueryBuilder<>(Wrappers.lambdaQuery(entityClass));
|
||||
return new LambdaQueryBuilder<>(new AggregateLambdaQueryWrapper<>(entityClass));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package org.dromara.common.mybatis.core.query;
|
||||
|
||||
/**
|
||||
* SQL 标准聚合函数。
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public enum SqlAggregateFunction {
|
||||
|
||||
/**
|
||||
* 求和。
|
||||
*/
|
||||
SUM("SUM"),
|
||||
|
||||
/**
|
||||
* 最大值。
|
||||
*/
|
||||
MAX("MAX"),
|
||||
|
||||
/**
|
||||
* 最小值。
|
||||
*/
|
||||
MIN("MIN"),
|
||||
|
||||
/**
|
||||
* 平均值。
|
||||
*/
|
||||
AVG("AVG"),
|
||||
|
||||
/**
|
||||
* 计数。
|
||||
*/
|
||||
COUNT("COUNT");
|
||||
|
||||
private final String name;
|
||||
|
||||
SqlAggregateFunction(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成聚合函数 SQL 片段。
|
||||
*
|
||||
* @param expression 函数入参表达式
|
||||
* @return 聚合函数 SQL
|
||||
*/
|
||||
public String format(String expression) {
|
||||
return name + "(" + expression + ")";
|
||||
}
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package org.dromara.common.mybatis.core.query;
|
||||
|
||||
/**
|
||||
* SQL 参数格式化器。
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface SqlParamFormatter {
|
||||
|
||||
/**
|
||||
* 格式化 SQL 参数。
|
||||
*
|
||||
* @param value 参数值
|
||||
* @return MyBatis 参数占位符
|
||||
*/
|
||||
String format(Object value);
|
||||
|
||||
}
|
||||
+447
@@ -0,0 +1,447 @@
|
||||
package org.dromara.common.mybatis.core.query;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfo;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Assert;
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.baomidou.mybatisplus.core.toolkit.LambdaUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.StringPool;
|
||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.ColumnCache;
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.LambdaMeta;
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
|
||||
import org.apache.ibatis.reflection.property.PropertyNamer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Lambda 子查询构造器。
|
||||
* <p>
|
||||
* 常用于外层查询的 {@code selectSub}、{@code inSub}、{@code existsSub} 等方法中。
|
||||
* </p>
|
||||
* <p>
|
||||
* 注意:子查询 SQL 由本构造器直接生成,默认会根据 MyBatis-Plus 表元数据追加逻辑删除条件,
|
||||
* 但不会自动追加项目数据权限条件;如果子查询实体也需要数据权限过滤,请在子查询条件中显式添加。
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
* userMapper.lambda()
|
||||
* .inSub(SysUser::getUserId, SysUserRole.class, sub -> sub
|
||||
* .select(SysUserRole::getUserId)
|
||||
* .eq(SysUserRole::getRoleId, roleId))
|
||||
* .voList();
|
||||
*
|
||||
* userMapper.lambda()
|
||||
* .select(SysUser::getUserId, SysUser::getUserName)
|
||||
* .selectSub(SysUserRole.class, sub -> sub
|
||||
* .selectCountAll()
|
||||
* .eqColumn(SysUserRole::getUserId, SysUser::getUserId),
|
||||
* UserStatVo::getRoleCount)
|
||||
* .voList();
|
||||
* }</pre>
|
||||
*
|
||||
* @param <T> 子查询实体类型
|
||||
* @author Lion Li
|
||||
*/
|
||||
public final class SubQuery<T> {
|
||||
|
||||
private final Class<T> entityClass;
|
||||
private final SqlParamFormatter paramFormatter;
|
||||
private final boolean placeholderParamMode;
|
||||
private final List<String> selects = new ArrayList<>();
|
||||
private final List<String> conditions = new ArrayList<>();
|
||||
private final List<Object> params = new ArrayList<>();
|
||||
private boolean withLogicDelete = true;
|
||||
|
||||
private SubQuery(Class<T> entityClass, SqlParamFormatter paramFormatter) {
|
||||
this(entityClass, paramFormatter, false);
|
||||
}
|
||||
|
||||
private SubQuery(Class<T> entityClass, SqlParamFormatter paramFormatter, boolean placeholderParamMode) {
|
||||
this.entityClass = entityClass;
|
||||
this.paramFormatter = paramFormatter;
|
||||
this.placeholderParamMode = placeholderParamMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建子查询。
|
||||
*
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param <T> 子查询实体类型
|
||||
* @return 子查询构造器
|
||||
*/
|
||||
public static <T> SubQuery<T> of(Class<T> entityClass) {
|
||||
return new SubQuery<>(entityClass, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建子查询。
|
||||
*
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param paramFormatter SQL 参数格式化器
|
||||
* @param <T> 子查询实体类型
|
||||
* @return 子查询构造器
|
||||
*/
|
||||
public static <T> SubQuery<T> of(Class<T> entityClass, SqlParamFormatter paramFormatter) {
|
||||
return new SubQuery<>(entityClass, paramFormatter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建使用 {@code {0}} 参数占位符的子查询。
|
||||
*
|
||||
* @param entityClass 子查询实体类型
|
||||
* @param <T> 子查询实体类型
|
||||
* @return 子查询构造器
|
||||
*/
|
||||
static <T> SubQuery<T> ofPlaceholders(Class<T> entityClass) {
|
||||
return new SubQuery<>(entityClass, null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定子查询字段。
|
||||
* <pre>{@code
|
||||
* sub.select(SysUserRole::getUserId)
|
||||
* }</pre>
|
||||
*
|
||||
* @param column 查询字段
|
||||
* @return 当前子查询构造器
|
||||
*/
|
||||
public SubQuery<T> select(SFunction<T, ?> column) {
|
||||
selects.add(columnName(column));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 COUNT(*) 查询字段。
|
||||
* <pre>{@code
|
||||
* sub.selectCountAll()
|
||||
* }</pre>
|
||||
*
|
||||
* @return 当前子查询构造器
|
||||
*/
|
||||
public SubQuery<T> selectCountAll() {
|
||||
selects.add(SqlAggregateFunction.COUNT.format("*"));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 SUM 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @return 当前子查询构造器
|
||||
*/
|
||||
public SubQuery<T> selectSum(SFunction<T, ?> column) {
|
||||
return selectAggregate(SqlAggregateFunction.SUM, column);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 MAX 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @return 当前子查询构造器
|
||||
*/
|
||||
public SubQuery<T> selectMax(SFunction<T, ?> column) {
|
||||
return selectAggregate(SqlAggregateFunction.MAX, column);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 MIN 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @return 当前子查询构造器
|
||||
*/
|
||||
public SubQuery<T> selectMin(SFunction<T, ?> column) {
|
||||
return selectAggregate(SqlAggregateFunction.MIN, column);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 AVG 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @return 当前子查询构造器
|
||||
*/
|
||||
public SubQuery<T> selectAvg(SFunction<T, ?> column) {
|
||||
return selectAggregate(SqlAggregateFunction.AVG, column);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定 COUNT 聚合查询字段。
|
||||
*
|
||||
* @param column 聚合字段
|
||||
* @return 当前子查询构造器
|
||||
*/
|
||||
public SubQuery<T> selectCount(SFunction<T, ?> column) {
|
||||
return selectAggregate(SqlAggregateFunction.COUNT, column);
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁用子查询逻辑删除条件。
|
||||
* <pre>{@code
|
||||
* sub.disableLogicDelete()
|
||||
* }</pre>
|
||||
*
|
||||
* @return 当前子查询构造器
|
||||
*/
|
||||
public SubQuery<T> disableLogicDelete() {
|
||||
this.withLogicDelete = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加等于条件。
|
||||
* <pre>{@code
|
||||
* sub.eq(SysUserRole::getRoleId, roleId)
|
||||
* }</pre>
|
||||
*
|
||||
* @param column 字段
|
||||
* @param value 条件值
|
||||
* @return 当前子查询构造器
|
||||
*/
|
||||
public SubQuery<T> eq(SFunction<T, ?> column, Object value) {
|
||||
return condition(column, Constants.EQUALS, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加大于条件。
|
||||
*
|
||||
* @param column 字段
|
||||
* @param value 条件值
|
||||
* @return 当前子查询构造器
|
||||
*/
|
||||
public SubQuery<T> gt(SFunction<T, ?> column, Object value) {
|
||||
return condition(column, ">", value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加大于等于条件。
|
||||
*
|
||||
* @param column 字段
|
||||
* @param value 条件值
|
||||
* @return 当前子查询构造器
|
||||
*/
|
||||
public SubQuery<T> ge(SFunction<T, ?> column, Object value) {
|
||||
return condition(column, ">=", value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加小于条件。
|
||||
*
|
||||
* @param column 字段
|
||||
* @param value 条件值
|
||||
* @return 当前子查询构造器
|
||||
*/
|
||||
public SubQuery<T> lt(SFunction<T, ?> column, Object value) {
|
||||
return condition(column, "<", value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加小于等于条件。
|
||||
*
|
||||
* @param column 字段
|
||||
* @param value 条件值
|
||||
* @return 当前子查询构造器
|
||||
*/
|
||||
public SubQuery<T> le(SFunction<T, ?> column, Object value) {
|
||||
return condition(column, "<=", value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加模糊匹配条件。
|
||||
*
|
||||
* @param column 字段
|
||||
* @param value 条件值
|
||||
* @return 当前子查询构造器
|
||||
*/
|
||||
public SubQuery<T> like(SFunction<T, ?> column, Object value) {
|
||||
return condition(column, "LIKE", "%" + value + "%");
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 IN 条件。
|
||||
* <pre>{@code
|
||||
* sub.in(SysUserRole::getRoleId, roleIds)
|
||||
* }</pre>
|
||||
*
|
||||
* @param column 字段
|
||||
* @param values 条件值集合
|
||||
* @return 当前子查询构造器
|
||||
*/
|
||||
public SubQuery<T> in(SFunction<T, ?> column, Collection<?> values) {
|
||||
if (CollectionUtils.isEmpty(values)) {
|
||||
return this;
|
||||
}
|
||||
conditions.add(columnName(column) + " IN (" + values.stream()
|
||||
.map(this::formatParam)
|
||||
.collect(Collectors.joining(Constants.COMMA)) + ")");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 IN 条件。
|
||||
*
|
||||
* @param column 字段
|
||||
* @param values 条件值数组
|
||||
* @return 当前子查询构造器
|
||||
*/
|
||||
public SubQuery<T> in(SFunction<T, ?> column, Object... values) {
|
||||
if (values == null || values.length == 0) {
|
||||
return this;
|
||||
}
|
||||
return in(column, Arrays.asList(values));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 BETWEEN 条件。
|
||||
*
|
||||
* @param column 字段
|
||||
* @param begin 起始值
|
||||
* @param end 结束值
|
||||
* @return 当前子查询构造器
|
||||
*/
|
||||
public SubQuery<T> between(SFunction<T, ?> column, Object begin, Object end) {
|
||||
conditions.add(columnName(column) + " BETWEEN " + formatParam(begin) + " AND " + formatParam(end));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加字段相等条件,用于关联外层查询字段。
|
||||
* <pre>{@code
|
||||
* sub.eqColumn(SysUserRole::getUserId, SysUser::getUserId)
|
||||
* }</pre>
|
||||
*
|
||||
* @param column 子查询字段
|
||||
* @param otherColumn 其他表字段
|
||||
* @param <O> 其他表实体类型
|
||||
* @return 当前子查询构造器
|
||||
*/
|
||||
public <O> SubQuery<T> eqColumn(SFunction<T, ?> column, SFunction<O, ?> otherColumn) {
|
||||
conditions.add(columnName(column) + Constants.EQUALS + qualifiedColumnName(otherColumn));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加字段相等条件,用于关联外层查询字段。
|
||||
* <pre>{@code
|
||||
* sub.eqColumn(SysUserRole::getUserId, "u", SysUser::getUserId)
|
||||
* }</pre>
|
||||
*
|
||||
* @param column 子查询字段
|
||||
* @param tableAlias 其他表别名
|
||||
* @param otherColumn 其他表字段
|
||||
* @param <O> 其他表实体类型
|
||||
* @return 当前子查询构造器
|
||||
*/
|
||||
public <O> SubQuery<T> eqColumn(SFunction<T, ?> column, String tableAlias, SFunction<O, ?> otherColumn) {
|
||||
conditions.add(columnName(column) + Constants.EQUALS + AggregateSelectUtils.checkAlias(tableAlias)
|
||||
+ StringPool.DOT + columnName(otherColumn));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按条件添加子查询条件。
|
||||
*
|
||||
* @param condition 是否添加
|
||||
* @param consumer 子查询条件
|
||||
* @return 当前子查询构造器
|
||||
*/
|
||||
public SubQuery<T> when(boolean condition, Consumer<SubQuery<T>> consumer) {
|
||||
if (condition) {
|
||||
consumer.accept(this);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建子查询 SQL。
|
||||
*
|
||||
* @return 子查询 SQL
|
||||
*/
|
||||
public String build() {
|
||||
Assert.notEmpty(selects, "子查询必须指定查询字段");
|
||||
String sql = "SELECT " + String.join(Constants.COMMA, selects) + " FROM " + tableName();
|
||||
List<String> whereConditions = buildWhereConditions();
|
||||
if (!whereConditions.isEmpty()) {
|
||||
sql += " WHERE " + String.join(" AND ", whereConditions);
|
||||
}
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取子查询参数。
|
||||
*
|
||||
* @return 子查询参数数组
|
||||
*/
|
||||
Object[] params() {
|
||||
return params.toArray();
|
||||
}
|
||||
|
||||
private SubQuery<T> selectAggregate(SqlAggregateFunction function, SFunction<T, ?> column) {
|
||||
selects.add(function.format(columnName(column)));
|
||||
return this;
|
||||
}
|
||||
|
||||
private SubQuery<T> condition(SFunction<T, ?> column, String operator, Object value) {
|
||||
conditions.add(columnName(column) + StringPool.SPACE + operator + StringPool.SPACE + formatParam(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
private String formatParam(Object value) {
|
||||
if (placeholderParamMode) {
|
||||
params.add(value);
|
||||
return "{" + (params.size() - 1) + "}";
|
||||
}
|
||||
Assert.notNull(paramFormatter, "子查询参数需要在外层查询方法中构造");
|
||||
return paramFormatter.format(value);
|
||||
}
|
||||
|
||||
private String tableName() {
|
||||
return tableInfo().getTableName();
|
||||
}
|
||||
|
||||
private List<String> buildWhereConditions() {
|
||||
List<String> whereConditions = new ArrayList<>();
|
||||
String logicDeleteSql = logicDeleteSql();
|
||||
if (StringUtils.isNotBlank(logicDeleteSql)) {
|
||||
whereConditions.add(logicDeleteSql);
|
||||
}
|
||||
whereConditions.addAll(conditions);
|
||||
return whereConditions;
|
||||
}
|
||||
|
||||
private String logicDeleteSql() {
|
||||
if (!withLogicDelete) {
|
||||
return StringPool.EMPTY;
|
||||
}
|
||||
return tableInfo().getLogicDeleteSql(false, true);
|
||||
}
|
||||
|
||||
private TableInfo tableInfo() {
|
||||
TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
|
||||
Assert.notNull(tableInfo, "无法获取实体表信息: %s", entityClass.getName());
|
||||
return tableInfo;
|
||||
}
|
||||
|
||||
private String qualifiedColumnName(SFunction<?, ?> column) {
|
||||
Class<?> columnEntityClass = LambdaUtils.extract(column).getInstantiatedClass();
|
||||
TableInfo tableInfo = TableInfoHelper.getTableInfo(columnEntityClass);
|
||||
Assert.notNull(tableInfo, "无法获取实体表信息: %s", columnEntityClass.getName());
|
||||
return tableInfo.getTableName() + StringPool.DOT + columnName(column);
|
||||
}
|
||||
|
||||
private static String columnName(SFunction<?, ?> column) {
|
||||
LambdaMeta meta = LambdaUtils.extract(column);
|
||||
String fieldName = PropertyNamer.methodToProperty(meta.getImplMethodName());
|
||||
Map<String, ColumnCache> columnMap = LambdaUtils.getColumnMap(meta.getInstantiatedClass());
|
||||
Assert.notNull(columnMap, "can not find lambda cache for this entity [%s]", meta.getInstantiatedClass().getName());
|
||||
ColumnCache cache = columnMap.get(LambdaUtils.formatKey(fieldName));
|
||||
Assert.notNull(cache, "can not find lambda cache for this property [%s]", fieldName);
|
||||
return cache.getColumn();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user