From 4bd314ed8127bed0795021dbd01a5ca9c6dc0b45 Mon Sep 17 00:00:00 2001 From: Jacek Poreda Date: Tue, 11 Jul 2023 13:53:31 +0200 Subject: [PATCH] SONAR-19728 Remove ordering from query, fetch issue keys --- .../java/org/sonar/db/issue/IssueDaoIT.java | 55 +++++++++---------- .../java/org/sonar/db/issue/IssueDao.java | 7 ++- .../java/org/sonar/db/issue/IssueMapper.java | 2 +- .../org/sonar/db/issue/IssueMapper.xml | 11 ++-- .../sonar/server/hotspot/ws/ListAction.java | 9 +-- .../org/sonar/server/issue/ws/ListAction.java | 17 +++--- 6 files changed, 52 insertions(+), 49 deletions(-) diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/issue/IssueDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/issue/IssueDaoIT.java index 567af5f8352..5a3f2a1214c 100644 --- a/server/sonar-db-dao/src/it/java/org/sonar/db/issue/IssueDaoIT.java +++ b/server/sonar-db-dao/src/it/java/org/sonar/db/issue/IssueDaoIT.java @@ -579,21 +579,20 @@ public class IssueDaoIT { } @Test - public void selectByQuery_shouldBePaginated() { + public void selectIssueKeysByQuery_shouldBePaginated() { List issues = generateIssues(10, i -> createIssueWithKey("i-" + i)); issues.forEach(issue -> underTest.insert(db.getSession(), issue)); - List results = underTest.selectByQuery( + List results = underTest.selectIssueKeysByQuery( db.getSession(), newIssueListQueryBuilder().project(PROJECT_KEY).build(), Pagination.forPage(2).andSize(3)); - List expectedKeys = List.of("i-3", "i-4", "i-5"); - assertThat(results.stream().map(IssueDto::getKey).toList()).containsExactlyElementsOf(expectedKeys); + assertThat(results.stream().toList()).hasSize(3); } @Test - public void selectByQuery_whenFilteredByBranch_shouldGetOnlyBranchIssues() { + public void selectIssueKeysByQuery_whenFilteredByBranch_shouldGetOnlyBranchIssues() { BranchDto branchDto = ComponentTesting.newBranchDto(PROJECT_UUID, BRANCH); ComponentDto branch = db.components().insertProjectBranch(projectDto, branchDto); ComponentDto branchFile = db.components().insertComponent(newFileDto(branch)); @@ -602,17 +601,17 @@ public class IssueDaoIT { Stream.concat(mainBranchIssues.stream(), otherBranchIssues.stream()) .forEach(issue -> underTest.insert(db.getSession(), issue)); - List results = underTest.selectByQuery( + List results = underTest.selectIssueKeysByQuery( db.getSession(), newIssueListQueryBuilder().project(PROJECT_KEY).branch(branchDto.getKey()).build(), Pagination.forPage(1).andSize(6)); List expectedKeys = List.of("branch-0", "branch-1", "branch-2"); - assertThat(results.stream().map(IssueDto::getKey).toList()).containsExactlyElementsOf(expectedKeys); + assertThat(results.stream().toList()).containsExactlyInAnyOrderElementsOf(expectedKeys); } @Test - public void selectByQuery_whenFilteredByPullRequest_shouldGetOnlyPRIssues() { + public void selectIssueKeysByQuery_whenFilteredByPullRequest_shouldGetOnlyPRIssues() { BranchDto pullRequestDto = ComponentTesting.newBranchDto(PROJECT_UUID, PULL_REQUEST); ComponentDto branch = db.components().insertProjectBranch(projectDto, pullRequestDto); ComponentDto branchFile = db.components().insertComponent(newFileDto(branch)); @@ -621,34 +620,34 @@ public class IssueDaoIT { Stream.concat(mainBranchIssues.stream(), otherBranchIssues.stream()) .forEach(issue -> underTest.insert(db.getSession(), issue)); - List results = underTest.selectByQuery( + List results = underTest.selectIssueKeysByQuery( db.getSession(), newIssueListQueryBuilder().project(PROJECT_KEY).pullRequest(pullRequestDto.getKey()).build(), Pagination.forPage(1).andSize(6)); List expectedKeys = List.of("pr-0", "pr-1", "pr-2"); - assertThat(results.stream().map(IssueDto::getKey).toList()).containsExactlyElementsOf(expectedKeys); + assertThat(results.stream().toList()).containsExactlyInAnyOrderElementsOf(expectedKeys); } @Test - public void selectByQuery_whenFilteredByTypes_shouldGetIssuesWithSpecifiedTypes() { + public void selectIssueKeysByQuery_whenFilteredByTypes_shouldGetIssuesWithSpecifiedTypes() { List bugs = generateIssues(3, i -> createIssueWithKey("bug-" + i).setType(RuleType.BUG)); List codeSmells = generateIssues(3, i -> createIssueWithKey("codesmell-" + i).setType(RuleType.CODE_SMELL)); Stream.of(bugs, codeSmells) .flatMap(Collection::stream) .forEach(issue -> underTest.insert(db.getSession(), issue)); - List results = underTest.selectByQuery( + List results = underTest.selectIssueKeysByQuery( db.getSession(), newIssueListQueryBuilder().project(PROJECT_KEY).types(List.of(RuleType.BUG.getDbConstant())).build(), Pagination.forPage(1).andSize(10)); List expectedKeys = List.of("bug-0", "bug-1", "bug-2"); - assertThat(results.stream().map(IssueDto::getKey).toList()).containsExactlyElementsOf(expectedKeys); + assertThat(results.stream().toList()).containsExactlyInAnyOrderElementsOf(expectedKeys); } @Test - public void selectByQuery_whenFilteredByFilteredStatuses_shouldGetIssuesWithoutSpecifiedStatuses() { + public void selectIssueKeysByQuery_whenFilteredByFilteredStatuses_shouldGetIssuesWithoutSpecifiedStatuses() { List openIssues = generateIssues(3, i -> createIssueWithKey("open-" + i).setStatus("OPEN")); List closedIssues = generateIssues(3, i -> createIssueWithKey("closed-" + i).setStatus("CLOSED")); List resolvedIssues = generateIssues(3, i -> createIssueWithKey("resolved-" + i).setStatus("RESOLVED")); @@ -656,17 +655,17 @@ public class IssueDaoIT { .flatMap(Collection::stream) .forEach(issue -> underTest.insert(db.getSession(), issue)); - List results = underTest.selectByQuery( + List results = underTest.selectIssueKeysByQuery( db.getSession(), newIssueListQueryBuilder().project(PROJECT_KEY).statuses(List.of("OPEN")).build(), Pagination.forPage(1).andSize(10)); List expectedKeys = List.of("open-0", "open-1", "open-2"); - assertThat(results.stream().map(IssueDto::getKey).toList()).containsExactlyElementsOf(expectedKeys); + assertThat(results.stream().toList()).containsExactlyInAnyOrderElementsOf(expectedKeys); } @Test - public void selectByQuery_whenFilteredByFilteredResolutions_shouldGetIssuesWithoutSpecifiedResolution() { + public void selectIssueKeysByQuery_whenFilteredByFilteredResolutions_shouldGetIssuesWithoutSpecifiedResolution() { List unresolvedIssues = generateIssues(3, i -> createIssueWithKey("open-" + i).setResolution(null)); List wontfixIssues = generateIssues(3, i -> createIssueWithKey("wf-" + i).setResolution("WONTFIX")); List falsePositiveIssues = generateIssues(3, i -> createIssueWithKey("fp-" + i).setResolution("FALSE-POSITIVE")); @@ -674,17 +673,17 @@ public class IssueDaoIT { .flatMap(Collection::stream) .forEach(issue -> underTest.insert(db.getSession(), issue)); - List results = underTest.selectByQuery( + List results = underTest.selectIssueKeysByQuery( db.getSession(), newIssueListQueryBuilder().project(PROJECT_KEY).resolutions(List.of("WONTFIX")).build(), Pagination.forPage(1).andSize(10)); List expectedKeys = List.of("wf-0", "wf-1", "wf-2"); - assertThat(results.stream().map(IssueDto::getKey).toList()).containsExactlyElementsOf(expectedKeys); + assertThat(results.stream().toList()).containsExactlyInAnyOrderElementsOf(expectedKeys); } @Test - public void selectByQuery_whenFilteredByFileComponent_shouldGetIssuesWithinFileOnly() { + public void selectIssueKeysByQuery_whenFilteredByFileComponent_shouldGetIssuesWithinFileOnly() { ComponentDto otherFileDto = db.components().insertComponent(newFileDto(projectDto).setUuid("OTHER_UUID").setKey("OTHER_KEY")); List fromFileIssues = generateIssues(3, i -> createIssueWithKey("file-" + i)); List fromOtherFileIssues = generateIssues(3, i -> createIssueWithKey("otherfile-" + i, PROJECT_UUID, otherFileDto.uuid())); @@ -692,17 +691,17 @@ public class IssueDaoIT { .flatMap(Collection::stream) .forEach(issue -> underTest.insert(db.getSession(), issue)); - List results = underTest.selectByQuery( + List results = underTest.selectIssueKeysByQuery( db.getSession(), newIssueListQueryBuilder().component(otherFileDto.getKey()).build(), Pagination.forPage(1).andSize(10)); List expectedKeys = List.of("otherfile-0", "otherfile-1", "otherfile-2"); - assertThat(results.stream().map(IssueDto::getKey).toList()).containsExactlyElementsOf(expectedKeys); + assertThat(results.stream().toList()).containsExactlyInAnyOrderElementsOf(expectedKeys); } @Test - public void selectByQuery_whenFilteredWithInNewCodeReference_shouldGetNewCodeReferenceIssues() { + public void selectIssueKeysByQuery_whenFilteredWithInNewCodeReference_shouldGetNewCodeReferenceIssues() { List issues = generateIssues(3, i -> createIssueWithKey("i-" + i)); List newCodeRefIssues = generateIssues(3, i -> createIssueWithKey("newCodeRef-" + i)); Stream.of(issues, newCodeRefIssues) @@ -710,30 +709,30 @@ public class IssueDaoIT { .forEach(issue -> underTest.insert(db.getSession(), issue)); newCodeRefIssues.forEach(issue -> db.issues().insertNewCodeReferenceIssue(issue)); - List results = underTest.selectByQuery( + List results = underTest.selectIssueKeysByQuery( db.getSession(), newIssueListQueryBuilder().project(PROJECT_KEY).newCodeOnReference(true).build(), Pagination.forPage(1).andSize(10)); List expectedKeys = List.of("newCodeRef-0", "newCodeRef-1", "newCodeRef-2"); - assertThat(results.stream().map(IssueDto::getKey).toList()).containsExactlyElementsOf(expectedKeys); + assertThat(results.stream().toList()).containsExactlyInAnyOrderElementsOf(expectedKeys); } @Test - public void selectByQuery_whenFilteredWithCreatedAfter_shouldGetIssuesCreatedAfterDate() { + public void selectIssueKeysByQuery_whenFilteredWithCreatedAfter_shouldGetIssuesCreatedAfterDate() { List createdBeforeIssues = generateIssues(3, i -> createIssueWithKey("createdBefore-" + i).setResolution(null).setIssueCreationDate(new Date(1_400_000_000_000L))); List createdAfterIssues = generateIssues(3, i -> createIssueWithKey("createdAfter-" + i).setResolution(null).setIssueCreationDate(new Date(1_420_000_000_000L))); Stream.of(createdBeforeIssues, createdAfterIssues) .flatMap(Collection::stream) .forEach(issue -> underTest.insert(db.getSession(), issue)); - List results = underTest.selectByQuery( + List results = underTest.selectIssueKeysByQuery( db.getSession(), newIssueListQueryBuilder().project(PROJECT_KEY).createdAfter(1_410_000_000_000L).build(), Pagination.forPage(1).andSize(10)); List expectedKeys = List.of("createdAfter-0", "createdAfter-1", "createdAfter-2"); - assertThat(results.stream().map(IssueDto::getKey).toList()).containsExactlyElementsOf(expectedKeys); + assertThat(results.stream().toList()).containsExactlyInAnyOrderElementsOf(expectedKeys); } private static IssueDto createIssueWithKey(String issueKey) { diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDao.java index 679cf8c0e34..4ff0349eef9 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDao.java @@ -127,8 +127,11 @@ public class IssueDao implements Dao { return mapper(dbSession).selectRecentlyClosedIssues(issueQueryParams); } - public List selectByQuery(DbSession dbSession, IssueListQuery issueListQuery, Pagination pagination) { - return mapper(dbSession).selectByQuery(issueListQuery, pagination); + /** + * Returned results are unordered. + */ + public List selectIssueKeysByQuery(DbSession dbSession, IssueListQuery issueListQuery, Pagination pagination) { + return mapper(dbSession).selectIssueKeysByQuery(issueListQuery, pagination); } } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueMapper.java index 3238a8a089f..5191504426a 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueMapper.java @@ -77,5 +77,5 @@ public interface IssueMapper { List selectRecentlyClosedIssues(@Param("queryParams") IssueQueryParams issueQueryParams); - List selectByQuery(@Param("query") IssueListQuery issueListQuery, @Param("pagination") Pagination pagination); + List selectIssueKeysByQuery(@Param("query") IssueListQuery issueListQuery, @Param("pagination") Pagination pagination); } diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/issue/IssueMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/issue/IssueMapper.xml index ac6593db8e2..61b2b81abfb 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/issue/IssueMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/issue/IssueMapper.xml @@ -718,11 +718,10 @@ - select - + i.kee from issues i - inner join rules r on r.uuid=i.rule_uuid inner join components p on p.uuid=i.component_uuid inner join components root on root.uuid=i.project_uuid inner join project_branches pb on pb.uuid=i.project_uuid @@ -768,8 +767,10 @@ AND i.issue_creation_date >= #{query.createdAfter,jdbcType=BIGINT} - order by i.kee asc + + + order by (select null) + offset (#{pagination.startRowNumber,jdbcType=INTEGER}-1) rows fetch next #{pagination.pageSize,jdbcType=INTEGER} rows only - diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/ListAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/ListAction.java index 1f44254a255..ba61692dad3 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/ListAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/ListAction.java @@ -165,13 +165,14 @@ public class ListAction implements HotspotsWsAction { } private SearchResponseData searchHotspots(DbSession dbSession, WsRequest wsRequest, ProjectAndBranch projectAndBranch) { - List hotspots = getHotspotKeys(dbSession, wsRequest, projectAndBranch); + List hotspotKeys = getHotspotKeys(dbSession, wsRequest, projectAndBranch); - Paging paging = forPageIndex(wsRequest.page).withPageSize(wsRequest.pageSize).andTotal(hotspots.size()); + Paging paging = forPageIndex(wsRequest.page).withPageSize(wsRequest.pageSize).andTotal(hotspotKeys.size()); + List hotspots = dbClient.issueDao().selectByKeys(dbSession, hotspotKeys); return new SearchResponseData(paging, hotspots); } - private List getHotspotKeys(DbSession dbSession, WsRequest wsRequest, ProjectAndBranch projectAndBranch) { + private List getHotspotKeys(DbSession dbSession, WsRequest wsRequest, ProjectAndBranch projectAndBranch) { BranchDto branch = projectAndBranch.getBranch(); IssueListQuery.IssueListQueryBuilder queryBuilder = IssueListQuery.IssueListQueryBuilder.newIssueListQueryBuilder() .project(wsRequest.project) @@ -192,7 +193,7 @@ public class ListAction implements HotspotsWsAction { } Pagination pagination = Pagination.forPage(wsRequest.page).andSize(wsRequest.pageSize); - return dbClient.issueDao().selectByQuery(dbSession, queryBuilder.build(), pagination); + return dbClient.issueDao().selectIssueKeysByQuery(dbSession, queryBuilder.build(), pagination); } private void loadComponents(DbSession dbSession, SearchResponseData searchResponseData) { diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/ListAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/ListAction.java index c53e07826d7..229c5b1bf75 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/ListAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/ListAction.java @@ -34,7 +34,6 @@ import org.sonar.db.DbSession; import org.sonar.db.Pagination; import org.sonar.db.component.BranchDto; import org.sonar.db.component.ComponentDto; -import org.sonar.db.issue.IssueDto; import org.sonar.db.issue.IssueListQuery; import org.sonar.db.newcodeperiod.NewCodePeriodType; import org.sonar.db.project.ProjectDto; @@ -47,6 +46,7 @@ import org.sonarqube.ws.Common; import org.sonarqube.ws.Issues; import static com.google.common.base.Strings.isNullOrEmpty; +import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static org.sonar.api.server.ws.WebService.Param.PAGE; import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE; @@ -136,8 +136,8 @@ public class ListAction implements IssuesWsAction { public final void handle(Request request, Response response) { WsRequest wsRequest = toWsRequest(request); ProjectAndBranch projectAndBranch = validateRequest(wsRequest); - List issues = getIssueKeys(wsRequest, projectAndBranch); - Issues.ListWsResponse wsResponse = formatResponse(wsRequest, issues); + List issueKeys = getIssueKeys(wsRequest, projectAndBranch); + Issues.ListWsResponse wsResponse = formatResponse(wsRequest, issueKeys); writeProtobuf(wsResponse, request, response); } @@ -190,7 +190,7 @@ public class ListAction implements IssuesWsAction { return projectAndBranch; } - private List getIssueKeys(WsRequest wsRequest, ProjectAndBranch projectAndBranch) { + private List getIssueKeys(WsRequest wsRequest, ProjectAndBranch projectAndBranch) { try (DbSession dbSession = dbClient.openSession(false)) { BranchDto branch = projectAndBranch.getBranch(); IssueListQuery.IssueListQueryBuilder queryBuilder = IssueListQuery.IssueListQueryBuilder.newIssueListQueryBuilder() @@ -213,21 +213,20 @@ public class ListAction implements IssuesWsAction { } Pagination pagination = Pagination.forPage(wsRequest.page).andSize(wsRequest.pageSize); - return dbClient.issueDao().selectByQuery(dbSession, queryBuilder.build(), pagination); + return dbClient.issueDao().selectIssueKeysByQuery(dbSession, queryBuilder.build(), pagination); } } - private Issues.ListWsResponse formatResponse(WsRequest request, List issues) { + private Issues.ListWsResponse formatResponse(WsRequest request, List issueKeys) { Issues.ListWsResponse.Builder response = Issues.ListWsResponse.newBuilder(); response.setPaging(Common.Paging.newBuilder() .setPageIndex(request.page) - .setPageSize(issues.size()) + .setPageSize(issueKeys.size()) .build()); - List issueKeys = issues.stream().map(IssueDto::getKey).toList(); SearchResponseLoader.Collector collector = new SearchResponseLoader.Collector(issueKeys); collectLoggedInUser(collector); - SearchResponseData preloadedData = new SearchResponseData(issues); + SearchResponseData preloadedData = new SearchResponseData(emptyList()); EnumSet additionalFields = EnumSet.of(SearchAdditionalField.ACTIONS, SearchAdditionalField.COMMENTS, SearchAdditionalField.TRANSITIONS); SearchResponseData data = searchResponseLoader.load(preloadedData, collector, additionalFields, null); -- 2.39.5