Include attribute values in target search text filter (#736)
* Add specification for like attribute value v2: ensure returned targets are unique v3: remove redundant or Signed-off-by: Stefan Schake <stefan.schake@devolo.de> * Use like attribute value specification with target search text Target attributes are the primary way to relay back metadata, particularly in a plug&play application. They should therefore be included in the target search. Attribute keys are excluded since they are expected to be consistent between targets. v3: remove whitespace changes Signed-off-by: Stefan Schake <stefan.schake@devolo.de> * Add test for target search includes attribute values v2: test targets returned are unique Signed-off-by: Stefan Schake <stefan.schake@devolo.de>
This commit is contained in:
committed by
Stefan Behl
parent
b2dfd4a99e
commit
e9ddcefd4a
@@ -465,7 +465,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
.hasInstalledOrAssignedDistributionSet(filterParams.getFilterByDistributionId()));
|
||||
}
|
||||
if (!StringUtils.isEmpty(filterParams.getFilterBySearchText())) {
|
||||
specList.add(TargetSpecifications.likeIdOrNameOrDescription(filterParams.getFilterBySearchText()));
|
||||
specList.add(TargetSpecifications.likeIdOrNameOrDescriptionOrAttributeValue(filterParams.getFilterBySearchText()));
|
||||
}
|
||||
if (isHasTagsFilterActive(filterParams)) {
|
||||
specList.add(TargetSpecifications.hasTags(filterParams.getFilterByTagNames(),
|
||||
|
||||
@@ -18,6 +18,7 @@ import javax.persistence.criteria.Path;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.persistence.criteria.SetJoin;
|
||||
import javax.persistence.criteria.MapJoin;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
@@ -37,6 +38,7 @@ import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.domain.Specifications;
|
||||
|
||||
/**
|
||||
* Specifications class for {@link Target}s. The class provides Spring Data JPQL
|
||||
@@ -148,6 +150,36 @@ public final class TargetSpecifications {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s by "like attribute
|
||||
* value".
|
||||
*
|
||||
* @param searchText
|
||||
* to be filtered on
|
||||
* @return the {@link Target} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTarget> likeAttributeValue(final String searchText) {
|
||||
return (targetRoot, query, cb) -> {
|
||||
final String searchTextToLower = searchText.toLowerCase();
|
||||
final MapJoin<JpaTarget, String, String> attributeMap = targetRoot.join(JpaTarget_.controllerAttributes,
|
||||
JoinType.LEFT);
|
||||
query.distinct(true);
|
||||
return cb.like(cb.lower(attributeMap.value()), searchTextToLower);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s by "like
|
||||
* controllerId or like name or like description or like attribute value".
|
||||
*
|
||||
* @param searchText
|
||||
* to be filtered on
|
||||
* @return the {@link Target} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTarget> likeIdOrNameOrDescriptionOrAttributeValue(final String searchText) {
|
||||
return Specifications.where(likeIdOrNameOrDescription(searchText)).or(likeAttributeValue(searchText));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s by "like
|
||||
* controllerId".
|
||||
|
||||
@@ -15,10 +15,13 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.repository.FilterParams;
|
||||
import org.eclipse.hawkbit.repository.UpdateMode;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
@@ -95,6 +98,19 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
final String installedC = targCs.iterator().next().getControllerId();
|
||||
final Long actionId = assignDistributionSet(installedSet.getId(), assignedC).getActions().get(0);
|
||||
|
||||
// add attributes to match against only attribute value or attribute
|
||||
// value and name
|
||||
final Map<String, String> attributes = new HashMap<>();
|
||||
attributes.put("key", "targ-C-attribute-value");
|
||||
final Target targAttribute = controllerManagement.updateControllerAttributes(targCs.get(0).getControllerId(),
|
||||
attributes, UpdateMode.REPLACE);
|
||||
// prepare one target with an attribute value equal to controller id
|
||||
Target targAttributeId = targCs.get(15);
|
||||
final Map<String, String> idAttributes = new HashMap<>();
|
||||
idAttributes.put("key", targAttributeId.getControllerId());
|
||||
targAttributeId = controllerManagement.updateControllerAttributes(targAttributeId.getControllerId(),
|
||||
idAttributes, UpdateMode.REPLACE);
|
||||
|
||||
// set one installed DS also
|
||||
controllerManagement.addUpdateActionStatus(
|
||||
entityFactory.actionStatus().create(actionId).status(Status.FINISHED).message("message"));
|
||||
@@ -114,6 +130,8 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
// try to find several targets with different filter settings
|
||||
verifyThat1TargetHasNameAndId("targ-A-special", targSpecialName.getControllerId());
|
||||
verifyThat1TargetHasAttributeValue("%c-attribute%", targAttribute.getControllerId());
|
||||
verifyThat1TargetHasAttributeValue("%" + targAttributeId.getControllerId() + "%", targAttributeId.getControllerId());
|
||||
verifyThatRepositoryContains400Targets();
|
||||
verifyThat200TargetsHaveTagD(targTagW, concat(targBs, targCs));
|
||||
verifyThat100TargetsContainsGivenTextAndHaveTagAssigned(targTagY, targTagW, targBs);
|
||||
@@ -492,6 +510,14 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
targetManagement.countByFilters(null, null, controllerId, null, Boolean.FALSE)));
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat1TargetHasAttributeValue(final String value, final String controllerId) {
|
||||
assertThat(targetManagement.findByFilters(PAGE, new FilterParams(null, null, value, null, Boolean.FALSE))
|
||||
.getContent()).as("has number of elements").hasSize(1).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(
|
||||
targetManagement.countByFilters(null, null, value, null, Boolean.FALSE)));
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat100TargetsContainsGivenTextAndHaveTagAssigned(final TargetTag targTagY,
|
||||
final TargetTag targTagW, final List<Target> expected) {
|
||||
|
||||
Reference in New Issue
Block a user