diff --git a/application/src/main/java/org/thingsboard/server/controller/CalculatedFieldController.java b/application/src/main/java/org/thingsboard/server/controller/CalculatedFieldController.java index 46abed29c8..2d3c0dde5f 100644 --- a/application/src/main/java/org/thingsboard/server/controller/CalculatedFieldController.java +++ b/application/src/main/java/org/thingsboard/server/controller/CalculatedFieldController.java @@ -25,6 +25,7 @@ import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.exception.ExceptionUtils; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -203,14 +204,15 @@ public class CalculatedFieldController extends BaseController { @RequestParam(required = false) EntityType entityType, @Parameter(description = "Entities filter. If not specified, calculated fields for entity type filter will be returned.") @RequestParam(required = false) List entities, - @Parameter(description = "Name filter.") - @RequestParam(required = false) String name, + @Parameter(description = "Name filter. To specify multiple names, duplicate 'name' parameter for each name, for example '?name=name1&name=name2") + @RequestParam(required = false) String name, // for Swagger only, retrieved from MultiValueMap params (due to issues when name contains comma) @Parameter(description = CF_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, @Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name"})) @RequestParam(required = false) String sortProperty, @Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"})) - @RequestParam(required = false) String sortOrder) throws ThingsboardException { + @RequestParam(required = false) String sortOrder, + @RequestParam MultiValueMap params) throws ThingsboardException { PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); SecurityUser user = getCurrentUser(); Set entityTypes; @@ -224,7 +226,7 @@ public class CalculatedFieldController extends BaseController { .type(type) .entityTypes(entityTypes) .entityIds(entities) - .name(name) + .names(params.get("name")) .build(); return calculatedFieldService.findCalculatedFieldsByTenantIdAndFilter(user.getTenantId(), filter, pageLink); } diff --git a/application/src/test/java/org/thingsboard/server/controller/CalculatedFieldControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/CalculatedFieldControllerTest.java index 85da8810bc..b472a0099a 100644 --- a/application/src/test/java/org/thingsboard/server/controller/CalculatedFieldControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/CalculatedFieldControllerTest.java @@ -51,6 +51,7 @@ import org.thingsboard.server.dao.service.DaoSqlTest; import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.containsString; @@ -223,28 +224,36 @@ public class CalculatedFieldControllerTest extends AbstractControllerTest { "Profile A" ); - List allCalculatedFields = getCalculatedFields(CalculatedFieldType.SIMPLE, null, null, null); + List allCalculatedFields = getCalculatedFields(CalculatedFieldType.SIMPLE, + null, null, null); assertThat(allCalculatedFields).contains(deviceCalculatedField, profileCalculatedField); - List profileLevelCalculatedFields = getCalculatedFields(CalculatedFieldType.SIMPLE, EntityType.DEVICE_PROFILE, null, null); + List profileLevelCalculatedFields = getCalculatedFields(CalculatedFieldType.SIMPLE, + EntityType.DEVICE_PROFILE, null, null); assertThat(profileLevelCalculatedFields).containsOnly(profileCalculatedField); - List specificDeviceCalculatedFields = getCalculatedFields(CalculatedFieldType.SIMPLE, EntityType.DEVICE, List.of(device.getUuidId()), null); + List specificDeviceCalculatedFields = getCalculatedFields(CalculatedFieldType.SIMPLE, + EntityType.DEVICE, List.of(device.getUuidId()), null); assertThat(specificDeviceCalculatedFields).containsOnly(deviceCalculatedField); - List byNameCalculatedFields = getCalculatedFields(CalculatedFieldType.SIMPLE, null, null, deviceCalculatedField.getName()); + List byNameCalculatedFields = getCalculatedFields(CalculatedFieldType.SIMPLE, + null, null, List.of(deviceCalculatedField.getName())); assertThat(byNameCalculatedFields).containsOnly(deviceCalculatedField); + + byNameCalculatedFields = getCalculatedFields(CalculatedFieldType.SIMPLE, null, null, + List.of(deviceCalculatedField.getName(), profileCalculatedField.getName())); + assertThat(byNameCalculatedFields).contains(deviceCalculatedField, profileCalculatedField); } private List getCalculatedFields(CalculatedFieldType type, EntityType entityType, List entities, - String name) throws Exception { + List names) throws Exception { return doGetTypedWithPageLink("/api/calculatedFields?type=" + type + "&" + (entityType != null ? "entityType=" + entityType + "&" : "") + (entities != null ? "entities=" + String.join(",", entities.stream().map(UUID::toString).toList()) + "&" : "") + - (name != null ? "name=" + name + "&" : ""), + (names != null ? names.stream().map(name -> "name=" + name + "&").collect(Collectors.joining("")) : ""), new TypeReference>() {}, new PageLink(10)).getData(); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/cf/CalculatedFieldFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/cf/CalculatedFieldFilter.java index e99ceeeed9..40283cbaa3 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/cf/CalculatedFieldFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/cf/CalculatedFieldFilter.java @@ -36,6 +36,6 @@ public class CalculatedFieldFilter { @Nullable private final List entityIds; @Nullable - private final String name; + private final List names; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java index 9f1f583108..76a7906b03 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java @@ -93,7 +93,7 @@ public abstract class DataValidator> { } public void validateString(String exceptionPrefix, String name) { - if (StringUtils.isEmpty(name) || name.trim().length() == 0) { + if (StringUtils.isBlank(name)) { throw new DataValidationException(exceptionPrefix + " should be specified!"); } if (StringUtils.contains0x00(name)) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/cf/CalculatedFieldRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/cf/CalculatedFieldRepository.java index 31478666c2..1d214db7c1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/cf/CalculatedFieldRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/cf/CalculatedFieldRepository.java @@ -46,10 +46,10 @@ public interface CalculatedFieldRepository extends JpaRepository findByTenantIdAndFilter(UUID tenantId, String type, List entityTypes, - List entityIds, String name, String textSearch, Pageable pageable); + List entityIds, List names, String textSearch, Pageable pageable); List findAllByTenantId(UUID tenantId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/cf/JpaCalculatedFieldDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/cf/JpaCalculatedFieldDao.java index a2a95bdf77..b8434913b4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/cf/JpaCalculatedFieldDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/cf/JpaCalculatedFieldDao.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.dao.sql.cf; -import com.google.common.base.Strings; import jakarta.transaction.Transactional; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -110,7 +109,7 @@ public class JpaCalculatedFieldDao extends JpaAbstractDao