fxi(功能用例): 高级搜索部分条件查询有误

--task=1016128 --user=陈建星 高级搜索-视图增删改查-后端 https://www.tapd.cn/55049933/s/1573254
This commit is contained in:
AgAngle 2024-09-12 10:42:46 +08:00 committed by Craftsman
parent 8a9808f541
commit c0400c483d
8 changed files with 213 additions and 84 deletions

View File

@ -1,10 +1,12 @@
package io.metersphere.sdk.dto;
import io.metersphere.sdk.constants.CustomFieldType;
import io.metersphere.sdk.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
@ -35,6 +37,19 @@ public class CombineCondition {
@EnumValue(enumClass = CombineConditionOperator.class)
private String operator;
/**
* 是否是多选自定义字段
* BaseMapper.xml 中调用
* @return
*/
public Boolean isMultipleCustomField() {
if (BooleanUtils.isTrue(customField)) {
return StringUtils.equalsAny(customFieldType, CustomFieldType.MULTIPLE_SELECT.name(),
CustomFieldType.MULTIPLE_INPUT.name(), CustomFieldType.MULTIPLE_MEMBER.name(), CustomFieldType.CHECKBOX.name());
}
return false;
}
public boolean valid() {
if (StringUtils.isBlank(name) || StringUtils.isBlank(operator)) {
return false;

View File

@ -373,13 +373,13 @@
</include>
</if>
<if test="condition.name == 'follower'">
api_definition.id in (
select api_definition_id from api_definition_follower where
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<include refid="io.metersphere.system.mapper.BaseMapper.associationCondition">
<property name="mainIdColumn" value="api_definition.id"/>
<property name="associationTable" value="api_definition_follower"/>
<property name="associationIdColumn" value="api_definition_id"/>
<property name="searchColumn" value="user_id"/>
<property name="condition" value="condition"/>
<property name="column" value="user_id"/>
</include>
)
</if>
<include refid="io.metersphere.system.mapper.BaseMapper.queryType">
<property name="searchMode" value="${combineSearch}.searchMode"/>
@ -418,15 +418,12 @@
<property name="searchMode" value="${combineSearch}.searchMode"/>
</include>
</foreach>
<if test="${combineSearch}.customFiledConditions.size() > 0">
api_definition.id in (
select api_id from api_definition_custom_field where
<include refid="io.metersphere.system.mapper.BaseMapper.customFiledConditions">
<property name="conditions" value="${combineSearch}.customFiledConditions"/>
<property name="searchMode" value="${combineSearch}.searchMode"/>
</include>
)
</if>
<include refid="io.metersphere.system.mapper.BaseMapper.customFiledConditions">
<property name="mainIdColumn" value="api_definition.id"/>
<property name="associationTable" value="api_definition_custom_field"/>
<property name="associationIdColumn" value="api_id"/>
<property name="combineSearch" value="${combineSearch}"/>
</include>
</if>
</trim>
</sql>

View File

@ -144,16 +144,14 @@
<property name="column" value="functional_case.create_user"/>
</include>
</if>
<if test="condition.name == 'reviewUser'">
crfc.case_id in (
select case_id from case_review_functional_case_user
where review_id = #{request.reviewId}
and
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<if test="condition.name == 'reviewers'">
<include refid="io.metersphere.system.mapper.BaseMapper.associationCondition">
<property name="mainIdColumn" value="crfc.case_id"/>
<property name="associationTable" value="case_review_functional_case_user"/>
<property name="associationIdColumn" value="case_id"/>
<property name="searchColumn" value="user_id"/>
<property name="condition" value="condition"/>
<property name="column" value="user_id"/>
</include>
)
</if>
<include refid="io.metersphere.system.mapper.BaseMapper.queryType">
<property name="searchMode" value="${combineSearch}.searchMode"/>
@ -170,37 +168,40 @@
<property name="column" value="crfc.status"/>
</include>
</if>
<if test="condition.name == 'demand'">
functional_case.id in (
select case_id from functional_case_demand where
<if test="condition.name == 'lastExecuteResult'">
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="condition" value="condition"/>
<property name="column" value="demand_name"/>
<property name="column" value="functional_case.last_execute_result"/>
</include>
</if>
<if test="condition.name == 'demand'">
<include refid="io.metersphere.system.mapper.BaseMapper.associationCondition">
<property name="mainIdColumn" value="functional_case.id"/>
<property name="associationTable" value="functional_case_demand"/>
<property name="associationIdColumn" value="case_id"/>
<property name="searchColumn" value="demand_name"/>
<property name="condition" value="condition"/>
</include>
)
</if>
<if test="condition.name == 'attachment'">
functional_case.id in (
select case_id from functional_case_attachment where
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<include refid="io.metersphere.system.mapper.BaseMapper.associationCondition">
<property name="mainIdColumn" value="functional_case.id"/>
<property name="associationTable" value="functional_case_attachment"/>
<property name="associationIdColumn" value="case_id"/>
<property name="searchColumn" value="file_name"/>
<property name="condition" value="condition"/>
<property name="column" value="file_name"/>
</include>
)
</if>
<include refid="io.metersphere.system.mapper.BaseMapper.queryType">
<property name="searchMode" value="${combineSearch}.searchMode"/>
</include>
</foreach>
<if test="${combineSearch}.customFiledConditions.size() > 0">
functional_case.id in (
select case_id from functional_case_custom_field where
<include refid="io.metersphere.system.mapper.BaseMapper.customFiledConditions">
<property name="conditions" value="${combineSearch}.customFiledConditions"/>
<property name="searchMode" value="${combineSearch}.searchMode"/>
</include>
)
</if>
<include refid="io.metersphere.system.mapper.BaseMapper.customFiledConditions">
<property name="mainIdColumn" value="functional_case.id"/>
<property name="associationTable" value="functional_case_custom_field"/>
<property name="associationIdColumn" value="case_id"/>
<property name="combineSearch" value="${combineSearch}"/>
</include>
</if>
</trim>
</sql>

View File

@ -292,13 +292,13 @@
</include>
</if>
<if test="condition.name == 'follower'">
functional_case.id in (
select case_id from functional_case_follower where
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="condition" value="condition"/>
<property name="column" value="user_id"/>
</include>
)
<include refid="io.metersphere.system.mapper.BaseMapper.associationCondition">
<property name="mainIdColumn" value="functional_case.id"/>
<property name="associationTable" value="functional_case_follower"/>
<property name="associationIdColumn" value="case_id"/>
<property name="searchColumn" value="user_id"/>
<property name="condition" value="condition"/>
</include>
</if>
<include refid="io.metersphere.system.mapper.BaseMapper.queryType">
<property name="searchMode" value="${combineSearch}.searchMode"/>
@ -322,36 +322,33 @@
</include>
</if>
<if test="condition.name == 'demand'">
functional_case.id in (
select case_id from functional_case_demand where
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="condition" value="condition"/>
<property name="column" value="demand_name"/>
</include>
)
<include refid="io.metersphere.system.mapper.BaseMapper.associationCondition">
<property name="mainIdColumn" value="functional_case.id"/>
<property name="associationTable" value="functional_case_demand"/>
<property name="associationIdColumn" value="case_id"/>
<property name="searchColumn" value="demand_name"/>
<property name="condition" value="condition"/>
</include>
</if>
<if test="condition.name == 'attachment'">
functional_case.id in (
select case_id from functional_case_attachment where
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<include refid="io.metersphere.system.mapper.BaseMapper.associationCondition">
<property name="mainIdColumn" value="functional_case.id"/>
<property name="associationTable" value="functional_case_attachment"/>
<property name="associationIdColumn" value="case_id"/>
<property name="searchColumn" value="file_name"/>
<property name="condition" value="condition"/>
<property name="column" value="file_name"/>
</include>
)
</if>
<include refid="io.metersphere.system.mapper.BaseMapper.queryType">
<property name="searchMode" value="${combineSearch}.searchMode"/>
</include>
</foreach>
<if test="${combineSearch}.customFiledConditions.size() > 0">
functional_case.id in (
select case_id from functional_case_custom_field where
<include refid="io.metersphere.system.mapper.BaseMapper.customFiledConditions">
<property name="conditions" value="${combineSearch}.customFiledConditions"/>
<property name="searchMode" value="${combineSearch}.searchMode"/>
</include>
)
</if>
<include refid="io.metersphere.system.mapper.BaseMapper.customFiledConditions">
<property name="mainIdColumn" value="functional_case.id"/>
<property name="associationTable" value="functional_case_custom_field"/>
<property name="associationIdColumn" value="case_id"/>
<property name="combineSearch" value="${combineSearch}"/>
</include>
</if>
</trim>
</sql>
@ -394,7 +391,6 @@
group by ref_id
</select>
<update id="batchDelete">
update functional_case
set deleted = 1,

View File

@ -39,7 +39,7 @@ public enum InternalUserView {
MY_REVIEW(() -> {
UserViewDTO userViewDTO = getUserViewDTO("my_review");
CombineCondition condition = new CombineCondition();
condition.setName("reviewUser");
condition.setName("reviewers");
condition.setValue(getCurrentUserArrayValue());
condition.setOperator(CombineCondition.CombineConditionOperator.IN.name());
userViewDTO.setConditions(List.of(condition));

View File

@ -23,7 +23,15 @@ public class DBCombineSearch extends CombineSearch {
*/
private List<CombineCondition> systemFieldConditions;
/**
* 自定义字段筛选条件
* 自定义字段为空的筛选条件
*/
private List<CombineCondition> customFiledEmptyConditions;
/**
* 自定义字段中 NOT_IN NOT_EQUALS NOT_CONTAINS COUNT_LT 的条件
*/
private List<CombineCondition> customFiledNoneConditions;
/**
* 其他的自定义字段筛选条件
*/
private List<CombineCondition> customFiledConditions;
}

View File

@ -18,7 +18,10 @@ import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
/**
* @Author: jianxing
@ -63,13 +66,40 @@ public class BaseConditionFilterAspect {
}
List<CombineCondition> validConditions = getValidConditions(combineSearch.getConditions());
replaceCurrentUser(validConditions);
List<CombineCondition> systemFieldConditions = validConditions.stream().filter(item -> !BooleanUtils.isTrue(item.getCustomField())).toList();
List<CombineCondition> customFieldConditions = validConditions.stream().filter(item -> BooleanUtils.isTrue(item.getCustomField())).toList();
List<CombineCondition> systemFieldConditions = validConditions.stream()
.filter(item -> !BooleanUtils.isTrue(item.getCustomField()))
.toList();
List<CombineCondition> customFieldConditions = validConditions.stream()
.filter(item -> BooleanUtils.isTrue(item.getCustomField()))
.collect(Collectors.toList());
// 拆分系统字段和自定义字段
DBCombineSearch dbCombineSearch = BeanUtils.copyBean(new DBCombineSearch(), combineSearch);
dbCombineSearch.setSystemFieldConditions(systemFieldConditions);
// 拆分自定义字段操作符为空的条件
List<CombineCondition> customFiledEmptyConditions = new ArrayList<>(0);
// 拆分自定义字段操作符为 NOT_IN NOT_EQUALS NOT_CONTAINS 的条件
List<CombineCondition> customFiledNoneConditions = new ArrayList<>(0);
Iterator<CombineCondition> iterator = customFieldConditions.iterator();
while (iterator.hasNext()) {
CombineCondition customFieldCondition = iterator.next();
if (StringUtils.equalsAny(customFieldCondition.getOperator(), CombineCondition.CombineConditionOperator.EMPTY.name())) {
customFiledEmptyConditions.add(customFieldCondition);
iterator.remove();
} else if (StringUtils.equalsAny(customFieldCondition.getOperator(),
CombineCondition.CombineConditionOperator.COUNT_LT.name(),
CombineCondition.CombineConditionOperator.NOT_IN.name(),
CombineCondition.CombineConditionOperator.NOT_EQUALS.name(),
CombineCondition.CombineConditionOperator.NOT_CONTAINS.name())) {
customFiledNoneConditions.add(customFieldCondition);
iterator.remove();
}
}
dbCombineSearch.setCustomFiledEmptyConditions(customFiledEmptyConditions);
dbCombineSearch.setCustomFiledNoneConditions(customFiledNoneConditions);
dbCombineSearch.setCustomFiledConditions(customFieldConditions);
baseCondition.setCombineSearch(dbCombineSearch);
// 处理视图查询条件

View File

@ -54,13 +54,37 @@
</sql>
<sql id="customFiledConditions">
<trim suffixOverrides="AND|OR">
<foreach collection="${conditions}" item="condition">
<trim prefix="(" suffix=")">
field_id = #{condition.name}
and
<if test="${combineSearch}.customFiledEmptyConditions.size() > 0">
<foreach collection="${combineSearch}.customFiledEmptyConditions" item="condition">
${mainIdColumn} not in (
select ${associationIdColumn} from ${associationTable} where
field_id = #{condition.name} and
`value` is not null and `value` != ''
<if test="condition.customFieldType != null and condition.isMultipleCustomField()">
and `value` != '[]'
</if>
)
<include refid="io.metersphere.system.mapper.BaseMapper.queryType">
<property name="searchMode" value="${combineSearch}.searchMode"/>
</include>
</foreach>
</if>
<if test="${combineSearch}.customFiledNoneConditions.size() > 0">
<foreach collection="${combineSearch}.customFiledNoneConditions" item="condition">
${mainIdColumn} not in (
select ${associationIdColumn} from ${associationTable} where
field_id = #{condition.name} and
`value` is not null and `value` != ''
<if test="condition.customFieldType != null and condition.isMultipleCustomField()">
and `value` != '[]'
</if>
) or
${mainIdColumn} in (
select ${associationIdColumn} from ${associationTable} where
field_id = #{condition.name} and
<choose>
<when test="condition.customFieldType != null and (condition.customFieldType == 'MULTIPLE_SELECT' or condition.customFieldType == 'MULTIPLE_SELECT' or condition.customFieldType == 'MULTIPLE_INPUT')">
<when test="condition.customFieldType != null and condition.isMultipleCustomField()">
<include refid="io.metersphere.system.mapper.BaseMapper.arrayValueCondition">
<property name="condition" value="condition"/>
<property name="column" value="value"/>
@ -73,12 +97,42 @@
</include>
</otherwise>
</choose>
</trim>
)
<include refid="io.metersphere.system.mapper.BaseMapper.queryType">
<property name="searchMode" value="${searchMode}"/>
<property name="searchMode" value="${combineSearch}.searchMode"/>
</include>
</foreach>
</trim>
</if>
<if test="${combineSearch}.customFiledConditions.size() > 0">
${mainIdColumn} in (
select ${associationIdColumn} from ${associationTable} where
<trim suffixOverrides="AND|OR">
<foreach collection="${combineSearch}.customFiledConditions" item="condition">
<trim prefix="(" suffix=")">
field_id = #{condition.name} and
<choose>
<when test="condition.customFieldType != null and condition.isMultipleCustomField()">
<include refid="io.metersphere.system.mapper.BaseMapper.arrayValueCondition">
<property name="condition" value="condition"/>
<property name="column" value="value"/>
</include>
</when>
<otherwise>
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="condition" value="condition"/>
<property name="column" value="value"/>
</include>
</otherwise>
</choose>
</trim>
<include refid="io.metersphere.system.mapper.BaseMapper.queryType">
<property name="searchMode" value="${combineSearch}.searchMode"/>
</include>
</foreach>
</trim>
)
</if>
</sql>
<sql id="arrayValueCondition">
@ -117,12 +171,40 @@
${column} is null or ${column} = '[]'
</when>
<when test="${condition}.operator == 'NOT_EMPTY'">
${column} is not null and ${column} = '[]'
${column} is not null and ${column} != '[]'
</when>
</choose>
</trim>
</sql>
<sql id="associationCondition">
<choose>
<when test="${condition}.operator == 'EMPTY'">
${mainIdColumn} not in (
select ${associationIdColumn} from ${associationTable} where
${searchColumn} is not null and ${searchColumn} != ''
)
</when>
<otherwise>
(
<if test="${condition}.operator == 'NOT_IN' or ${condition}.operator == 'NOT_EQUALS' or ${condition}.operator == 'NOT_CONTAINS'">
${mainIdColumn} not in (
select ${associationIdColumn} from ${associationTable} where
${searchColumn} is not null and ${searchColumn} != ''
) or
</if>
${mainIdColumn} in (
select ${associationIdColumn} from ${associationTable} where
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="condition" value="${condition}"/>
<property name="column" value="${searchColumn}"/>
</include>
)
)
</otherwise>
</choose>
</sql>
<sql id="condition">
<trim prefix="(" suffix=")">
<choose>