Implement topics sorting (backend) (#1498)
* [ISSUE-1383]Create parameters of request for sorting topics. (backend) * [ISSUE-1383]Create parameters of request for sorting topics. (backend) Co-authored-by: Roman Zabaluev <rzabaluev@provectus.com>
This commit is contained in:
parent
540b8eb79b
commit
7cdcacf5d5
4 changed files with 68 additions and 12 deletions
|
@ -5,6 +5,7 @@ import com.provectus.kafka.ui.model.PartitionsIncreaseDTO;
|
|||
import com.provectus.kafka.ui.model.PartitionsIncreaseResponseDTO;
|
||||
import com.provectus.kafka.ui.model.ReplicationFactorChangeDTO;
|
||||
import com.provectus.kafka.ui.model.ReplicationFactorChangeResponseDTO;
|
||||
import com.provectus.kafka.ui.model.SortOrderDTO;
|
||||
import com.provectus.kafka.ui.model.TopicColumnsToSortDTO;
|
||||
import com.provectus.kafka.ui.model.TopicConfigDTO;
|
||||
import com.provectus.kafka.ui.model.TopicCreationDTO;
|
||||
|
@ -66,6 +67,7 @@ public class TopicsController extends AbstractController implements TopicsApi {
|
|||
@Valid Boolean showInternal,
|
||||
@Valid String search,
|
||||
@Valid TopicColumnsToSortDTO orderBy,
|
||||
@Valid SortOrderDTO sortOrder,
|
||||
ServerWebExchange exchange) {
|
||||
return topicsService
|
||||
.getTopics(
|
||||
|
@ -74,7 +76,8 @@ public class TopicsController extends AbstractController implements TopicsApi {
|
|||
Optional.ofNullable(perPage),
|
||||
Optional.ofNullable(showInternal),
|
||||
Optional.ofNullable(search),
|
||||
Optional.ofNullable(orderBy)
|
||||
Optional.ofNullable(orderBy),
|
||||
Optional.ofNullable(sortOrder)
|
||||
).map(ResponseEntity::ok);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import com.provectus.kafka.ui.model.PartitionsIncreaseDTO;
|
|||
import com.provectus.kafka.ui.model.PartitionsIncreaseResponseDTO;
|
||||
import com.provectus.kafka.ui.model.ReplicationFactorChangeDTO;
|
||||
import com.provectus.kafka.ui.model.ReplicationFactorChangeResponseDTO;
|
||||
import com.provectus.kafka.ui.model.SortOrderDTO;
|
||||
import com.provectus.kafka.ui.model.TopicColumnsToSortDTO;
|
||||
import com.provectus.kafka.ui.model.TopicConfigDTO;
|
||||
import com.provectus.kafka.ui.model.TopicCreationDTO;
|
||||
|
@ -67,10 +68,11 @@ public class TopicsService {
|
|||
Optional<Integer> nullablePerPage,
|
||||
Optional<Boolean> showInternal,
|
||||
Optional<String> search,
|
||||
Optional<TopicColumnsToSortDTO> sortBy) {
|
||||
Optional<TopicColumnsToSortDTO> sortBy,
|
||||
Optional<SortOrderDTO> sortOrder) {
|
||||
return adminClientService.get(cluster).flatMap(ac ->
|
||||
new Pagination(ac, metricsCache.get(cluster))
|
||||
.getPage(pageNum, nullablePerPage, showInternal, search, sortBy)
|
||||
.getPage(pageNum, nullablePerPage, showInternal, search, sortBy, sortOrder)
|
||||
.flatMap(page ->
|
||||
loadTopics(cluster, page.getTopics())
|
||||
.map(topics ->
|
||||
|
@ -409,12 +411,15 @@ public class TopicsService {
|
|||
Optional<Integer> nullablePerPage,
|
||||
Optional<Boolean> showInternal,
|
||||
Optional<String> search,
|
||||
Optional<TopicColumnsToSortDTO> sortBy) {
|
||||
Optional<TopicColumnsToSortDTO> sortBy,
|
||||
Optional<SortOrderDTO> sortOrder) {
|
||||
return geTopicsForPagination()
|
||||
.map(paginatingTopics -> {
|
||||
Predicate<Integer> positiveInt = i -> i > 0;
|
||||
int perPage = nullablePerPage.filter(positiveInt).orElse(DEFAULT_PAGE_SIZE);
|
||||
var topicsToSkip = (pageNum.filter(positiveInt).orElse(1) - 1) * perPage;
|
||||
var comparator = sortOrder.isEmpty() || !sortOrder.get().equals(SortOrderDTO.DESC)
|
||||
? getComparatorForTopic(sortBy) : getComparatorForTopic(sortBy).reversed();
|
||||
List<InternalTopic> topics = paginatingTopics.stream()
|
||||
.filter(topic -> !topic.isInternal()
|
||||
|| showInternal.map(i -> topic.isInternal() == i).orElse(true))
|
||||
|
@ -422,7 +427,7 @@ public class TopicsService {
|
|||
search
|
||||
.map(s -> StringUtils.containsIgnoreCase(topic.getName(), s))
|
||||
.orElse(true))
|
||||
.sorted(getComparatorForTopic(sortBy))
|
||||
.sorted(comparator)
|
||||
.collect(toList());
|
||||
var totalPages = (topics.size() / perPage)
|
||||
+ (topics.size() % perPage == 0 ? 0 : 1);
|
||||
|
|
|
@ -4,8 +4,10 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.provectus.kafka.ui.model.SortOrderDTO;
|
||||
import com.provectus.kafka.ui.model.TopicColumnsToSortDTO;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
@ -46,12 +48,35 @@ class TopicsServicePaginationTest {
|
|||
|
||||
var topics = pagination.getPage(
|
||||
Optional.empty(), Optional.empty(), Optional.empty(),
|
||||
Optional.empty(), Optional.empty()).block();
|
||||
Optional.empty(), Optional.empty(), Optional.empty()).block();
|
||||
assertThat(topics.getTotalPages()).isEqualTo(4);
|
||||
assertThat(topics.getTopics()).hasSize(25);
|
||||
assertThat(topics.getTopics()).isSorted();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldListFirst25TopicsSortedByNameDescendingOrder() {
|
||||
var topicDescriptions = IntStream.rangeClosed(1, 100).boxed()
|
||||
.map(Objects::toString)
|
||||
.map(name -> new TopicDescription(name, false, List.of()))
|
||||
.collect(Collectors.toList());
|
||||
init(topicDescriptions);
|
||||
|
||||
var topics = pagination.getPage(
|
||||
Optional.empty(), Optional.empty(), Optional.empty(),
|
||||
Optional.empty(), Optional.of(TopicColumnsToSortDTO.NAME), Optional.of(SortOrderDTO.DESC)).block();
|
||||
assertThat(topics.getTotalPages()).isEqualTo(4);
|
||||
assertThat(topics.getTopics()).hasSize(25);
|
||||
assertThat(topics.getTopics()).isSortedAccordingTo(Comparator.reverseOrder());
|
||||
assertThat(topics.getTopics()).containsExactlyElementsOf(
|
||||
topicDescriptions.stream()
|
||||
.map(TopicDescription::name)
|
||||
.sorted(Comparator.reverseOrder())
|
||||
.limit(25)
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCalculateCorrectPageCountForNonDivisiblePageSize() {
|
||||
init(
|
||||
|
@ -62,7 +87,7 @@ class TopicsServicePaginationTest {
|
|||
);
|
||||
|
||||
var topics = pagination.getPage(Optional.of(4), Optional.of(33),
|
||||
Optional.empty(), Optional.empty(), Optional.empty()).block();
|
||||
Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty()).block();
|
||||
assertThat(topics.getTotalPages()).isEqualTo(4);
|
||||
assertThat(topics.getTopics()).hasSize(1)
|
||||
.first().isEqualTo("99");
|
||||
|
@ -78,7 +103,7 @@ class TopicsServicePaginationTest {
|
|||
);
|
||||
|
||||
var topics = pagination.getPage(Optional.of(0), Optional.of(-1),
|
||||
Optional.empty(), Optional.empty(), Optional.empty()).block();
|
||||
Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty()).block();
|
||||
assertThat(topics.getTotalPages()).isEqualTo(4);
|
||||
assertThat(topics.getTopics()).hasSize(25);
|
||||
assertThat(topics.getTopics()).isSorted();
|
||||
|
@ -95,7 +120,7 @@ class TopicsServicePaginationTest {
|
|||
|
||||
var topics = pagination.getPage(
|
||||
Optional.empty(), Optional.empty(), Optional.of(true),
|
||||
Optional.empty(), Optional.empty()).block();
|
||||
Optional.empty(), Optional.empty(), Optional.empty()).block();
|
||||
assertThat(topics.getTotalPages()).isEqualTo(4);
|
||||
assertThat(topics.getTopics()).hasSize(25);
|
||||
assertThat(topics.getTopics()).isSorted();
|
||||
|
@ -113,7 +138,7 @@ class TopicsServicePaginationTest {
|
|||
|
||||
var topics = pagination.getPage(
|
||||
Optional.empty(), Optional.empty(), Optional.of(true),
|
||||
Optional.empty(), Optional.empty()).block();
|
||||
Optional.empty(), Optional.empty(), Optional.empty()).block();
|
||||
assertThat(topics.getTotalPages()).isEqualTo(4);
|
||||
assertThat(topics.getTopics()).hasSize(25);
|
||||
assertThat(topics.getTopics()).isSorted();
|
||||
|
@ -131,7 +156,7 @@ class TopicsServicePaginationTest {
|
|||
|
||||
var topics = pagination.getPage(
|
||||
Optional.empty(), Optional.empty(), Optional.empty(),
|
||||
Optional.of("1"), Optional.empty()).block();
|
||||
Optional.of("1"), Optional.empty(), Optional.empty()).block();
|
||||
assertThat(topics.getTotalPages()).isEqualTo(1);
|
||||
assertThat(topics.getTopics()).hasSize(20);
|
||||
assertThat(topics.getTopics()).isSorted();
|
||||
|
@ -151,7 +176,7 @@ class TopicsServicePaginationTest {
|
|||
|
||||
var topics = pagination.getPage(
|
||||
Optional.empty(), Optional.empty(), Optional.empty(),
|
||||
Optional.empty(), Optional.of(TopicColumnsToSortDTO.TOTAL_PARTITIONS)).block();
|
||||
Optional.empty(), Optional.of(TopicColumnsToSortDTO.TOTAL_PARTITIONS), Optional.empty()).block();
|
||||
assertThat(topics.getTotalPages()).isEqualTo(4);
|
||||
assertThat(topics.getTopics()).hasSize(25);
|
||||
assertThat(topics.getTopics()).containsExactlyElementsOf(
|
||||
|
@ -159,6 +184,18 @@ class TopicsServicePaginationTest {
|
|||
.map(TopicDescription::name)
|
||||
.limit(25)
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
var topicsSortedDesc = pagination.getPage(
|
||||
Optional.empty(), Optional.empty(), Optional.empty(),
|
||||
Optional.empty(), Optional.of(TopicColumnsToSortDTO.TOTAL_PARTITIONS), Optional.of(SortOrderDTO.DESC)).block();
|
||||
assertThat(topicsSortedDesc.getTotalPages()).isEqualTo(4);
|
||||
assertThat(topicsSortedDesc.getTopics()).hasSize(25);
|
||||
assertThat(topicsSortedDesc.getTopics()).containsExactlyElementsOf(
|
||||
topicDescriptions.stream()
|
||||
.sorted((a, b) -> b.partitions().size() - a.partitions().size())
|
||||
.map(TopicDescription::name)
|
||||
.limit(25)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -295,6 +295,11 @@ paths:
|
|||
required: false
|
||||
schema:
|
||||
$ref: '#/components/schemas/TopicColumnsToSort'
|
||||
- name: sortOrder
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
$ref: '#/components/schemas/SortOrder'
|
||||
responses:
|
||||
200:
|
||||
description: OK
|
||||
|
@ -1729,6 +1734,12 @@ components:
|
|||
- TOTAL_PARTITIONS
|
||||
- REPLICATION_FACTOR
|
||||
|
||||
SortOrder:
|
||||
type: string
|
||||
enum:
|
||||
- ASC
|
||||
- DESC
|
||||
|
||||
Topic:
|
||||
type: object
|
||||
properties:
|
||||
|
|
Loading…
Add table
Reference in a new issue