Align target queries to only use specifications (#1148)

* Add additional specifications to cover use cases of queries

Signed-off-by: Alexander Dobler <alexander.dobler3@bosch.io>

* Replace reading target queries by spec, use empty spec in default repo calls

Signed-off-by: Alexander Dobler <alexander.dobler3@bosch.io>

* Use correct NonNull annotation

Signed-off-by: Alexander Dobler <alexander.dobler3@bosch.io>

* Added default exists based on spec count to TargetRepository

Signed-off-by: Alexander Dobler <alexander.dobler3@bosch.io>
This commit is contained in:
Alexander Dobler
2021-08-04 17:47:23 +02:00
committed by GitHub
parent 8c0bd2ffd2
commit 101401a6a8
9 changed files with 259 additions and 212 deletions

View File

@@ -66,6 +66,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications; import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications;
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper; import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper; import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
@@ -310,7 +311,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
} }
private void throwExceptionIfTargetDoesNotExist(final String controllerId) { private void throwExceptionIfTargetDoesNotExist(final String controllerId) {
if (!targetRepository.existsByControllerId(controllerId)) { if (!targetRepository.exists(TargetSpecifications.hasControllerId(controllerId))) {
throw new EntityNotFoundException(Target.class, controllerId); throw new EntityNotFoundException(Target.class, controllerId);
} }
} }
@@ -367,9 +368,9 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
@Override @Override
public void deleteExistingTarget(@NotEmpty final String controllerId) { public void deleteExistingTarget(@NotEmpty final String controllerId) {
final Target target = targetRepository.findByControllerId(controllerId) final Target target = targetRepository.findOne(TargetSpecifications.hasControllerId(controllerId))
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId)); .orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
targetRepository.deleteById(target.getId()); targetRepository.deleteById(target.getId());
} }
@Override @Override
@@ -738,7 +739,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
throw new InvalidTargetAttributeException(); throw new InvalidTargetAttributeException();
} }
final JpaTarget target = (JpaTarget) targetRepository.findByControllerId(controllerId) final JpaTarget target = (JpaTarget) targetRepository.findOne(TargetSpecifications.hasControllerId(controllerId))
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId)); .orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
// get the modifiable attribute map // get the modifiable attribute map
@@ -884,7 +885,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
@Override @Override
public Optional<Target> getByControllerId(final String controllerId) { public Optional<Target> getByControllerId(final String controllerId) {
return targetRepository.findByControllerId(controllerId); return targetRepository.findOne(TargetSpecifications.hasControllerId(controllerId)).map(Target.class::cast);
} }
@Override @Override

View File

@@ -55,6 +55,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper; import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper; import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
import org.eclipse.hawkbit.repository.jpa.utils.TenantConfigHelper; import org.eclipse.hawkbit.repository.jpa.utils.TenantConfigHelper;
@@ -289,8 +290,8 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
.distinct().collect(Collectors.toList()); .distinct().collect(Collectors.toList());
final List<String> existingTargetIds = Lists.partition(providedTargetIds, Constants.MAX_ENTRIES_IN_STATEMENT) final List<String> existingTargetIds = Lists.partition(providedTargetIds, Constants.MAX_ENTRIES_IN_STATEMENT)
.stream().map(targetRepository::filterNonExistingControllerIds).flatMap(List::stream) .stream().map(ids -> targetRepository.findAll(TargetSpecifications.hasControllerIdIn(ids)))
.collect(Collectors.toList()); .flatMap(List::stream).map(JpaTarget::getControllerId).collect(Collectors.toList());
final List<JpaTarget> targetEntities = assignmentStrategy.findTargetsForAssignment(existingTargetIds, final List<JpaTarget> targetEntities = assignmentStrategy.findTargetsForAssignment(existingTargetIds,
distributionSetEntity.getId()); distributionSetEntity.getId());
@@ -701,7 +702,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
} }
private void throwExceptionIfTargetDoesNotExist(final String controllerId) { private void throwExceptionIfTargetDoesNotExist(final String controllerId) {
if (!targetRepository.existsByControllerId(controllerId)) { if (!targetRepository.exists(TargetSpecifications.hasControllerId(controllerId))) {
throw new EntityNotFoundException(Target.class, controllerId); throw new EntityNotFoundException(Target.class, controllerId);
} }
} }

View File

@@ -37,6 +37,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup; import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup;
import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup_; import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup_;
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus; import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus;
@@ -232,9 +233,11 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
// in case of status ready the action has not been created yet and // in case of status ready the action has not been created yet and
// the relation information between target and rollout-group is // the relation information between target and rollout-group is
// stored in the #TargetRolloutGroup. // stored in the #TargetRolloutGroup.
return targetRepository.findByRolloutTargetGroupRolloutGroupId(rolloutGroupId, page); return JpaTargetManagement.convertPage(
targetRepository.findAll(TargetSpecifications.isInRolloutGroup(rolloutGroupId), page), page);
} }
return targetRepository.findByActionsRolloutGroupId(rolloutGroupId, page); return JpaTargetManagement.convertPage(
targetRepository.findAll(TargetSpecifications.isInActionRolloutGroup(rolloutGroupId), page), page);
} }
private static boolean isRolloutStatusReady(final RolloutGroup rolloutGroup) { private static boolean isRolloutStatusReady(final RolloutGroup rolloutGroup) {

View File

@@ -144,11 +144,11 @@ public class JpaTargetManagement implements TargetManagement {
@Override @Override
public Optional<Target> getByControllerID(final String controllerId) { public Optional<Target> getByControllerID(final String controllerId) {
return targetRepository.findByControllerId(controllerId); return targetRepository.findOne(TargetSpecifications.hasControllerId(controllerId)).map(Target.class::cast);
} }
private JpaTarget getByControllerIdAndThrowIfNotFound(final String controllerId) { private JpaTarget getByControllerIdAndThrowIfNotFound(final String controllerId) {
return targetRepository.findByControllerId(controllerId).map(JpaTarget.class::cast) return targetRepository.findOne(TargetSpecifications.hasControllerId(controllerId))
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId)); .orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
} }
@@ -342,7 +342,7 @@ public class JpaTargetManagement implements TargetManagement {
@Retryable(include = { @Retryable(include = {
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public void delete(final Collection<Long> targetIDs) { public void delete(final Collection<Long> targetIDs) {
final List<JpaTarget> targets = targetRepository.findAllById(targetIDs); final List<JpaTarget> targets = targetRepository.findAll(TargetSpecifications.hasIdIn(targetIDs));
if (targets.size() < targetIDs.size()) { if (targets.size() < targetIDs.size()) {
throw new EntityNotFoundException(Target.class, targetIDs, throw new EntityNotFoundException(Target.class, targetIDs,
@@ -373,7 +373,9 @@ public class JpaTargetManagement implements TargetManagement {
public Page<Target> findByAssignedDistributionSet(final Pageable pageReq, final long distributionSetID) { public Page<Target> findByAssignedDistributionSet(final Pageable pageReq, final long distributionSetID) {
throwEntityNotFoundIfDsDoesNotExist(distributionSetID); throwEntityNotFoundIfDsDoesNotExist(distributionSetID);
return targetRepository.findByAssignedDistributionSetId(pageReq, distributionSetID); return convertPage(
targetRepository.findAll(TargetSpecifications.hasAssignedDistributionSet(distributionSetID), pageReq),
pageReq);
} }
@Override @Override
@@ -399,7 +401,7 @@ public class JpaTargetManagement implements TargetManagement {
} }
} }
private static Page<Target> convertPage(final Page<JpaTarget> findAll, final Pageable pageable) { public static Page<Target> convertPage(final Page<JpaTarget> findAll, final Pageable pageable) {
return new PageImpl<>(Collections.unmodifiableList(findAll.getContent()), pageable, findAll.getTotalElements()); return new PageImpl<>(Collections.unmodifiableList(findAll.getContent()), pageable, findAll.getTotalElements());
} }
@@ -410,7 +412,9 @@ public class JpaTargetManagement implements TargetManagement {
@Override @Override
public Page<Target> findByInstalledDistributionSet(final Pageable pageReq, final long distributionSetID) { public Page<Target> findByInstalledDistributionSet(final Pageable pageReq, final long distributionSetID) {
throwEntityNotFoundIfDsDoesNotExist(distributionSetID); throwEntityNotFoundIfDsDoesNotExist(distributionSetID);
return targetRepository.findByInstalledDistributionSetId(pageReq, distributionSetID); return convertPage(
targetRepository.findAll(TargetSpecifications.hasInstalledDistributionSet(distributionSetID), pageReq),
pageReq);
} }
@Override @Override
@@ -432,7 +436,8 @@ public class JpaTargetManagement implements TargetManagement {
@Override @Override
public Page<Target> findByUpdateStatus(final Pageable pageable, final TargetUpdateStatus status) { public Page<Target> findByUpdateStatus(final Pageable pageable, final TargetUpdateStatus status) {
return targetRepository.findByUpdateStatus(pageable, status); return convertPage(targetRepository.findAll(TargetSpecifications.hasTargetUpdateStatus(status), pageable),
pageable);
} }
@Override @Override
@@ -515,8 +520,8 @@ public class JpaTargetManagement implements TargetManagement {
allTargets.stream().map(Target::getControllerId).collect(Collectors.toList())); allTargets.stream().map(Target::getControllerId).collect(Collectors.toList()));
} }
final List<JpaTarget> alreadyAssignedTargets = targetRepository.findByTagNameAndControllerIdIn(tagName, final List<JpaTarget> alreadyAssignedTargets = targetRepository.findAll(
controllerIds); TargetSpecifications.hasTagName(tagName).and(TargetSpecifications.hasControllerIdIn(controllerIds)));
// all are already assigned -> unassign // all are already assigned -> unassign
if (alreadyAssignedTargets.size() == allTargets.size()) { if (alreadyAssignedTargets.size() == allTargets.size()) {
@@ -633,21 +638,21 @@ public class JpaTargetManagement implements TargetManagement {
public long countByAssignedDistributionSet(final long distId) { public long countByAssignedDistributionSet(final long distId) {
throwEntityNotFoundIfDsDoesNotExist(distId); throwEntityNotFoundIfDsDoesNotExist(distId);
return targetRepository.countByAssignedDistributionSetId(distId); return targetRepository.count(TargetSpecifications.hasAssignedDistributionSet(distId));
} }
@Override @Override
public long countByInstalledDistributionSet(final long distId) { public long countByInstalledDistributionSet(final long distId) {
throwEntityNotFoundIfDsDoesNotExist(distId); throwEntityNotFoundIfDsDoesNotExist(distId);
return targetRepository.countByInstalledDistributionSetId(distId); return targetRepository.count(TargetSpecifications.hasInstalledDistributionSet(distId));
} }
@Override @Override
public boolean existsByInstalledOrAssignedDistributionSet(final long distId) { public boolean existsByInstalledOrAssignedDistributionSet(final long distId) {
throwEntityNotFoundIfDsDoesNotExist(distId); throwEntityNotFoundIfDsDoesNotExist(distId);
return targetRepository.existsByInstalledOrAssignedDistributionSet(distId); return targetRepository.exists(TargetSpecifications.hasInstalledOrAssignedDistributionSet(distId));
} }
@Override @Override
@@ -733,7 +738,7 @@ public class JpaTargetManagement implements TargetManagement {
public Page<Target> findByTag(final Pageable pageable, final long tagId) { public Page<Target> findByTag(final Pageable pageable, final long tagId) {
throwEntityNotFoundExceptionIfTagDoesNotExist(tagId); throwEntityNotFoundExceptionIfTagDoesNotExist(tagId);
return convertPage(targetRepository.findByTag(pageable, tagId), pageable); return convertPage(targetRepository.findAll(TargetSpecifications.hasTag(tagId), pageable), pageable);
} }
private void throwEntityNotFoundExceptionIfTagDoesNotExist(final Long tagId) { private void throwEntityNotFoundExceptionIfTagDoesNotExist(final Long tagId) {
@@ -782,7 +787,7 @@ public class JpaTargetManagement implements TargetManagement {
@Override @Override
public List<Target> get(final Collection<Long> ids) { public List<Target> get(final Collection<Long> ids) {
return Collections.unmodifiableList(targetRepository.findAllById(ids)); return Collections.unmodifiableList(targetRepository.findAll(TargetSpecifications.hasIdIn(ids)));
} }
@Override @Override
@@ -824,12 +829,13 @@ public class JpaTargetManagement implements TargetManagement {
@Override @Override
public boolean existsByControllerId(final String controllerId) { public boolean existsByControllerId(final String controllerId) {
return targetRepository.existsByControllerId(controllerId); return targetRepository.exists(TargetSpecifications.hasControllerId(controllerId));
} }
@Override @Override
public Page<Target> findByControllerAttributesRequested(final Pageable pageReq) { public Page<Target> findByControllerAttributesRequested(final Pageable pageReq) {
return targetRepository.findByRequestControllerAttributesIsTrue(pageReq); return convertPage(targetRepository.findAll(TargetSpecifications.hasRequestControllerAttributesTrue(), pageReq),
pageReq);
} }
} }

View File

@@ -25,6 +25,7 @@ import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
import org.eclipse.hawkbit.repository.jpa.specifications.TagSpecification; import org.eclipse.hawkbit.repository.jpa.specifications.TagSpecification;
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TargetTag;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
@@ -154,7 +155,7 @@ public class JpaTargetTagManagement implements TargetTagManagement {
@Override @Override
public Page<TargetTag> findByTarget(final Pageable pageable, final String controllerId) { public Page<TargetTag> findByTarget(final Pageable pageable, final String controllerId) {
if (!targetRepository.existsByControllerId(controllerId)) { if (!targetRepository.exists(TargetSpecifications.hasControllerId(controllerId))) {
throw new EntityNotFoundException(Target.class, controllerId); throw new EntityNotFoundException(Target.class, controllerId);
} }

View File

@@ -62,7 +62,7 @@ public class OfflineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
public List<JpaTarget> findTargetsForAssignment(final List<String> controllerIDs, final long setId) { public List<JpaTarget> findTargetsForAssignment(final List<String> controllerIDs, final long setId) {
final Function<List<String>, List<JpaTarget>> mapper; final Function<List<String>, List<JpaTarget>> mapper;
if (isMultiAssignmentsEnabled()) { if (isMultiAssignmentsEnabled()) {
mapper = targetRepository::findAllByControllerId; mapper = ids -> targetRepository.findAll(TargetSpecifications.hasControllerIdIn(ids));
} else { } else {
mapper = ids -> targetRepository.findAll(SpecificationsBuilder.combineWithAnd( mapper = ids -> targetRepository.findAll(SpecificationsBuilder.combineWithAnd(
Arrays.asList(TargetSpecifications.hasControllerIdAndAssignedDistributionSetIdNot(ids, setId), Arrays.asList(TargetSpecifications.hasControllerIdAndAssignedDistributionSetIdNot(ids, setId),

View File

@@ -32,7 +32,6 @@ import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status; import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult; import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.repository.model.TargetWithActionType; import org.eclipse.hawkbit.repository.model.TargetWithActionType;
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder; import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
@@ -98,7 +97,7 @@ public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
List<JpaTarget> findTargetsForAssignment(final List<String> controllerIDs, final long setId) { List<JpaTarget> findTargetsForAssignment(final List<String> controllerIDs, final long setId) {
final Function<List<String>, List<JpaTarget>> mapper; final Function<List<String>, List<JpaTarget>> mapper;
if (isMultiAssignmentsEnabled()) { if (isMultiAssignmentsEnabled()) {
mapper = targetRepository::findAllByControllerId; mapper = ids -> targetRepository.findAll(TargetSpecifications.hasControllerIdIn(ids));
} else { } else {
mapper = ids -> targetRepository mapper = ids -> targetRepository
.findAll(TargetSpecifications.hasControllerIdAndAssignedDistributionSetIdNot(ids, setId)); .findAll(TargetSpecifications.hasControllerIdAndAssignedDistributionSetIdNot(ids, setId));

View File

@@ -10,24 +10,27 @@ package org.eclipse.hawkbit.repository.jpa;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
import org.eclipse.hawkbit.repository.model.Tag;
import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
import org.springframework.lang.NonNull;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
/** /**
@@ -80,28 +83,6 @@ public interface TargetRepository extends BaseEntityRepository<JpaTarget, Long>,
@Param("set") JpaDistributionSet set, @Param("lastModifiedAt") Long modifiedAt, @Param("set") JpaDistributionSet set, @Param("lastModifiedAt") Long modifiedAt,
@Param("lastModifiedBy") String modifiedBy, @Param("targets") Collection<Long> targets); @Param("lastModifiedBy") String modifiedBy, @Param("targets") Collection<Long> targets);
/**
* Loads {@link Target} by given ID.
*
* @param controllerID
* to search for
* @return found {@link Target} or <code>null</code> if not found.
*/
Optional<Target> findByControllerId(String controllerID);
@Query("SELECT t.controllerAttributes FROM JpaTarget t WHERE t.controllerId=:controllerId")
Map<String, String> getControllerAttributes(@Param("controllerId") String controllerId);
/**
* Checks if target with given id exists.
*
* @param controllerId
* to check
* @return <code>true</code> if target with given id exists
*/
@Query("SELECT CASE WHEN COUNT(t)>0 THEN 'true' ELSE 'false' END FROM JpaTarget t WHERE t.controllerId=:controllerId")
boolean existsByControllerId(@Param("controllerId") String controllerId);
/** /**
* Deletes the {@link Target}s with the given target IDs. * Deletes the {@link Target}s with the given target IDs.
* *
@@ -114,165 +95,116 @@ public interface TargetRepository extends BaseEntityRepository<JpaTarget, Long>,
@Query("DELETE FROM JpaTarget t WHERE t.id IN ?1") @Query("DELETE FROM JpaTarget t WHERE t.id IN ?1")
void deleteByIdIn(Collection<Long> targetIDs); void deleteByIdIn(Collection<Long> targetIDs);
/**
* Finds {@link Target}s by assigned {@link Tag}.
*
* @param page
* pages query and sorting information
*
* @param tagId
* to be found
* @return page of found targets
*/
@Query(value = "SELECT DISTINCT t FROM JpaTarget t JOIN t.tags tt WHERE tt.id = :tag")
Page<JpaTarget> findByTag(Pageable page, @Param("tag") Long tagId);
/**
* Finds all {@link Target}s based on given {@link Target#getControllerId()}
* list and assigned {@link Tag#getName()}.
*
* @param tag
* to search for
* @param controllerIds
* to search for
* @return {@link List} of found {@link Target}s.
*/
@Query(value = "SELECT DISTINCT t from JpaTarget t JOIN t.tags tt WHERE tt.name = :tagname AND t.controllerId IN :targets")
List<JpaTarget> findByTagNameAndControllerIdIn(@Param("tagname") String tag,
@Param("targets") Collection<String> controllerIds);
/**
* Used by UI to filter based on selected status.
*
* @param pageable
* for page configuration
* @param status
* to filter for
*
* @return found targets
*/
Page<Target> findByUpdateStatus(Pageable pageable, TargetUpdateStatus status);
/**
* retrieves the {@link Target}s which has the {@link DistributionSet}
* installed with the given ID.
*
* @param pageable
* parameter
* @param setID
* the ID of the {@link DistributionSet}
* @return the found {@link Target}s
*/
Page<Target> findByInstalledDistributionSetId(Pageable pageable, Long setID);
/**
* Finds all targets that have defined {@link DistributionSet} assigned.
*
* @param pageable
* for page configuration
* @param setID
* is the ID of the {@link DistributionSet} to filter for.
*
* @return page of found targets
*/
Page<Target> findByAssignedDistributionSetId(Pageable pageable, Long setID);
/**
* retrieves {@link Target}s where
* {@link JpaTarget#isRequestControllerAttributes()}.
*
* @param pageReq
* page parameter
*
* @return the found {@link Target}s
*
*/
Page<Target> findByRequestControllerAttributesIsTrue(Pageable pageable);
/**
* Counts number of targets with given distribution set Id.
*
* @param distId
* to search for
*
* @return number of found {@link Target}s.
*/
Long countByAssignedDistributionSetId(Long distId);
/**
* Counts number of targets with given distribution set Id.
*
* @param distId
* to search for
* @return number of found {@link Target}s.
*/
Long countByInstalledDistributionSetId(Long distId);
/**
* Checks if there is already a {@link Target} that has the given distribution set Id assigned or installed.
*
* @param distId
* to check
* @return <code>true</code> if a {@link Target} exists.
*/
@Query("SELECT CASE WHEN COUNT(t)>0 THEN 'true' ELSE 'false' END FROM JpaTarget t WHERE t.installedDistributionSet.id=:distId OR t.assignedDistributionSet.id=:distId")
boolean existsByInstalledOrAssignedDistributionSet(@Param("distId") Long distId);
/** /**
* Finds all {@link Target}s in the repository. * Finds all {@link Target}s in the repository.
* *
* Calls version with (empty) spec to allow injecting further specs
*
* @return {@link List} of {@link Target}s * @return {@link List} of {@link Target}s
*
* @see org.springframework.data.repository.CrudRepository#findAll()
*/ */
@Override @Override
List<JpaTarget> findAll(); @NonNull
default List<JpaTarget> findAll() {
return this.findAll(Specification.where(null));
}
/**
* Finds all {@link Target}s in the repository sorted.
*
* Calls version with (empty) spec to allow injecting further specs
*
* @param sort instructions to sort result by
* @return {@link List} of {@link Target}s
*/
@Override @Override
// Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477 @NonNull
@Query("SELECT t FROM JpaTarget t WHERE t.id IN ?1") default Iterable<JpaTarget> findAll(@NonNull Sort sort) {
List<JpaTarget> findAllById(Iterable<Long> ids); return this.findAll(Specification.where(null), sort);
}
/** /**
* Finds all targets for the given list of controller IDs. * Finds a page of {@link Target}s in the repository.
* *
* @param controllerIds * Calls version with (empty) spec to allow injecting further specs
* The controller IDs to look for.
* *
* @return The list of matching targets. * @param pageable paging context
* @return {@link List} of {@link Target}s
*/ */
@Query("SELECT t FROM JpaTarget t WHERE t.controllerId IN ?1") @Override
List<JpaTarget> findAllByControllerId(Iterable<String> controllerIds); @NonNull
default Page<JpaTarget> findAll(@NonNull Pageable pageable) {
return this.findAll(Specification.where(null), pageable);
}
/** /**
* Finds {@link Target}s in the repository matching a list of ids.
* *
* Finds all targets of a rollout group. * Calls version based on spec to allow injecting further specs
* *
* @param rolloutGroupId * @param ids ids to filter for
* the ID of the rollout group * @return {@link List} of {@link Target}s
* @param page
* the page request parameter
* @return a page of all targets related to a rollout group
*/ */
Page<Target> findByRolloutTargetGroupRolloutGroupId(Long rolloutGroupId, Pageable page); @Override
@NonNull
default List<JpaTarget> findAllById(Iterable<Long> ids) {
final List<Long> collectedIds = StreamSupport.stream(ids.spliterator(), true).collect(Collectors.toList());
return this.findAll(Specification.where(TargetSpecifications.hasIdIn(collectedIds)));
}
/** /**
* Finds all targets related to a target rollout group stored for a specific * Finds {@link Target} in the repository matching an id.
* rollout.
* *
* @param rolloutGroupId * Calls version based on spec to allow injecting further specs
* the rollout group the targets should belong to *
* @param page * @param id id to filter for
* the page request parameter * @return {@link Optional} of {@link Target}
* @return a page of all targets related to a rollout group
*/ */
Page<Target> findByActionsRolloutGroupId(Long rolloutGroupId, Pageable page); @Override
@NonNull
default Optional<JpaTarget> findById(@NonNull Long id) {
return this.findOne(Specification.where(TargetSpecifications.hasId(id)));
}
/**
* Checks whether {@link Target} in the repository matching an id exists or not.
*
* Calls version based on spec to allow injecting further specs
*
* @param id id to check for
* @return true if target with id exists
*/
@Override
default boolean existsById(@NonNull Long id) {
return this.exists(TargetSpecifications.hasId(id));
}
/**
* Checks whether {@link Target} in the repository matching a spec exists or not.
*
* @param spec to check for existence
* @return true if target with id exists
*/
default boolean exists(@NonNull Specification<JpaTarget> spec) {
return this.count(spec) > 0;
}
/**
* Count number of {@link Target}s in the repository.
*
* Calls version with an empty spec to allow injecting further specs
*
* @return number of targets in the repository
*/
@Override
default long count() {
return this.count(Specification.where(null));
}
/** /**
* Deletes all {@link TenantAwareBaseEntity} of a given tenant. For safety * Deletes all {@link TenantAwareBaseEntity} of a given tenant. For safety
* reasons (this is a "delete everything" query after all) we add the tenant * reasons (this is a "delete everything" query after all) we add the tenant
* manually to query even if this will by done by {@link EntityManager} * manually to query even if this will by done by {@link EntityManager} anyhow.
* anyhow. The DB should take care of optimizing this away. * The DB should take care of optimizing this away.
* *
* @param tenant * @param tenant
* to delete data from * to delete data from
@@ -281,14 +213,4 @@ public interface TargetRepository extends BaseEntityRepository<JpaTarget, Long>,
@Transactional @Transactional
@Query("DELETE FROM JpaTarget t WHERE t.tenant = :tenant") @Query("DELETE FROM JpaTarget t WHERE t.tenant = :tenant")
void deleteByTenant(@Param("tenant") String tenant); void deleteByTenant(@Param("tenant") String tenant);
/**
* Filters a given list of controllerIds and returns only the existing IDs.
*
* @param controllerIds
* The IDs to be filtered
* @return only the existing controllerIds
*/
@Query("SELECT t.controllerId FROM JpaTarget t WHERE t.controllerId IN ?1")
List<String> filterNonExistingControllerIds(Iterable<String> controllerIds);
} }

View File

@@ -68,6 +68,64 @@ public final class TargetSpecifications {
}; };
} }
/**
* {@link Specification} for retrieving {@link Target}s by controllerId
*
* @param controllerID
* to search for
*
* @return the {@link Target} {@link Specification}
*/
public static Specification<JpaTarget> hasControllerId(final String controllerID) {
return (targetRoot, query, cb) -> cb.equal(targetRoot.get(JpaTarget_.controllerId), controllerID);
}
/**
* {@link Specification} for retrieving {@link Target}s by controllerId
*
* @param controllerIDs
* to search for
*
* @return the {@link Target} {@link Specification}
*/
public static Specification<JpaTarget> hasControllerIdIn(final Collection<String> controllerIDs) {
return (targetRoot, query, cb) -> targetRoot.get(JpaTarget_.controllerId).in(controllerIDs);
}
/**
* {@link Specification} for retrieving {@link Target}s by controllerId
*
* @param id
* to search for
*
* @return the {@link Target} {@link Specification}
*/
public static Specification<JpaTarget> hasId(final Long id) {
return (targetRoot, query, cb) -> cb.equal(targetRoot.get(JpaTarget_.id), id);
}
/**
* {@link Specification} for retrieving {@link Target}s by controllerId
*
* @param ids
* to search for
*
* @return the {@link Target} {@link Specification}
*/
public static Specification<JpaTarget> hasIdIn(final Collection<Long> ids) {
return (targetRoot, query, cb) -> targetRoot.get(JpaTarget_.id).in(ids);
}
/**
* {@link Specification} for retrieving {@link Target}s that have the request
* controller attributes flag set
*
* @return the {@link Target} {@link Specification}
*/
public static Specification<JpaTarget> hasRequestControllerAttributesTrue() {
return (targetRoot, query, cb) -> cb.equal(targetRoot.get(JpaTarget_.requestControllerAttributes), true);
}
/** /**
* {@link Specification} for retrieving {@link JpaTarget}s including * {@link Specification} for retrieving {@link JpaTarget}s including
* {@link JpaTarget#getAssignedDistributionSet()}. * {@link JpaTarget#getAssignedDistributionSet()}.
@@ -87,7 +145,7 @@ public final class TargetSpecifications {
} }
/** /**
* {@link Specification} for retrieving {@link Target}s by "equal to given * {@link Specification} for retrieving {@link Target}s by "equal to any given
* {@link TargetUpdateStatus}". * {@link TargetUpdateStatus}".
* *
* @param updateStatus * @param updateStatus
@@ -100,8 +158,21 @@ public final class TargetSpecifications {
} }
/** /**
* {@link Specification} for retrieving {@link Target}s by "not equal to * {@link Specification} for retrieving {@link Target}s by "equal to given
* given {@link TargetUpdateStatus}". * {@link TargetUpdateStatus}".
*
* @param updateStatus
* to be filtered on
*
* @return the {@link Target} {@link Specification}
*/
public static Specification<JpaTarget> hasTargetUpdateStatus(final TargetUpdateStatus updateStatus) {
return (targetRoot, query, cb) -> cb.equal(targetRoot.get(JpaTarget_.updateStatus), updateStatus);
}
/**
* {@link Specification} for retrieving {@link Target}s by "not equal to given
* {@link TargetUpdateStatus}".
* *
* @param updateStatus * @param updateStatus
* to be filtered on * to be filtered on
@@ -189,11 +260,7 @@ public final class TargetSpecifications {
* @return the {@link Target} {@link Specification} * @return the {@link Target} {@link Specification}
*/ */
public static Specification<JpaTarget> hasInstalledOrAssignedDistributionSet(@NotNull final Long distributionId) { public static Specification<JpaTarget> hasInstalledOrAssignedDistributionSet(@NotNull final Long distributionId) {
return (targetRoot, query, cb) -> cb.or( return hasInstalledDistributionSet(distributionId).or(hasAssignedDistributionSet(distributionId));
cb.equal(targetRoot.get(JpaTarget_.installedDistributionSet).get(JpaDistributionSet_.id),
distributionId),
cb.equal(targetRoot.<JpaDistributionSet> get(JpaTarget_.assignedDistributionSet)
.get(JpaDistributionSet_.id), distributionId));
} }
/** /**
@@ -214,6 +281,22 @@ public final class TargetSpecifications {
cb.isNull(targetRoot.<JpaDistributionSet> get(JpaTarget_.assignedDistributionSet)))); cb.isNull(targetRoot.<JpaDistributionSet> get(JpaTarget_.assignedDistributionSet))));
} }
/**
* {@link Specification} for retrieving {@link Target}s based on a
* {@link TargetTag} name.
*
* @param tagName
* to search for
*
* @return the {@link Target} {@link Specification}
*/
public static Specification<JpaTarget> hasTagName(final String tagName) {
return (targetRoot, query, cb) -> {
final SetJoin<JpaTarget, JpaTargetTag> join = targetRoot.join(JpaTarget_.tags);
return cb.equal(join.get(JpaTargetTag_.name), tagName);
};
}
/** /**
* {@link Specification} for retrieving {@link Target}s by "has no tag * {@link Specification} for retrieving {@link Target}s by "has no tag
* names"or "has at least on of the given tag names". * names"or "has at least on of the given tag names".
@@ -289,6 +372,37 @@ public final class TargetSpecifications {
}; };
} }
/**
* {@link Specification} for retrieving {@link Target}s that are in a given
* {@link RolloutGroup}
*
* @param group
* the {@link RolloutGroup}
* @return the {@link Target} {@link Specification}
*/
public static Specification<JpaTarget> isInRolloutGroup(final Long group) {
return (targetRoot, query, cb) -> {
final ListJoin<JpaTarget, RolloutTargetGroup> targetGroupJoin = targetRoot
.join(JpaTarget_.rolloutTargetGroup);
return cb.equal(targetGroupJoin.get(RolloutTargetGroup_.rolloutGroup).get(JpaRolloutGroup_.id), group);
};
}
/**
* {@link Specification} for retrieving {@link Target}s that are in an action
* for a given {@link RolloutGroup}
*
* @param group
* the {@link RolloutGroup}
* @return the {@link Target} {@link Specification}
*/
public static Specification<JpaTarget> isInActionRolloutGroup(final Long group) {
return (targetRoot, query, cb) -> {
final ListJoin<JpaTarget, JpaAction> targetActionJoin = targetRoot.join(JpaTarget_.actions);
return cb.equal(targetActionJoin.get(JpaAction_.rolloutGroup).get(JpaRolloutGroup_.id), group);
};
}
/** /**
* {@link Specification} for retrieving {@link Target}s that are not in the * {@link Specification} for retrieving {@link Target}s that are not in the
* given {@link RolloutGroup}s * given {@link RolloutGroup}s
@@ -347,7 +461,7 @@ public final class TargetSpecifications {
* {@link Specification} for retrieving {@link Target}s by tag. * {@link Specification} for retrieving {@link Target}s by tag.
* *
* @param tagId * @param tagId
* the ID of the distribution set which must be assigned * the ID of the tag that should be to be assigned to target
* @return the {@link Target} {@link Specification} * @return the {@link Target} {@link Specification}
*/ */
public static Specification<JpaTarget> hasTag(final Long tagId) { public static Specification<JpaTarget> hasTag(final Long tagId) {