@Override
public Map<String, Boolean> getUserUuidToManaged(DbSession dbSession, Set<String> userUuids) {
+ Set<String> gitHubUserUuids = findManagedUserUuids(dbSession, userUuids);
+
+ return userUuids.stream()
+ .collect(toMap(Function.identity(), gitHubUserUuids::contains));
+ }
+
+ private Set<String> findManagedUserUuids(DbSession dbSession, Set<String> userUuids) {
+ List<UserDto> userDtos = findManagedUsers(dbSession, userUuids);
+
+ return userDtos.stream()
+ .map(UserDto::getUuid)
+ .collect(toSet());
+ }
+
+ private List<UserDto> findManagedUsers(DbSession dbSession, Set<String> userUuids) {
UserQuery managedUsersQuery = UserQuery.builder()
.userUuids(userUuids)
.isManagedClause(getManagedUsersSqlFilter(true))
.build();
- List<UserDto> userDtos = userDao.selectUsers(dbSession, managedUsersQuery);
- Set<String> gitHubUserUuids = userDtos.stream()
- .map(UserDto::getUuid)
- .collect(toSet());
-
- return userUuids.stream()
- .collect(toMap(Function.identity(), gitHubUserUuids::contains));
+ return userDao.selectUsers(dbSession, managedUsersQuery);
}
@Override
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
-import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.junit.Rule;
import org.junit.Test;
import static java.util.Collections.emptySet;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toMap;
+import static java.util.stream.Collectors.toSet;
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.groups.Tuple.tuple;
assertThat(users).isEmpty();
}
+ @Test
+ public void selectUsersByQuery_whenSearchingByUuids_findsTheRightResults() {
+ db.users().insertUser();
+ UserDto userToFind1 = db.users().insertUser();
+ UserDto userToFind2 = db.users().insertUser();
+
+ UserQuery query = UserQuery.builder().userUuids(Set.of(userToFind1.getUuid(), userToFind2.getUuid())).build();
+ List<UserDto> users = underTest.selectUsers(session, query);
+
+ assertThat(users).usingRecursiveFieldByFieldElementComparator().containsOnly(userToFind1, userToFind2);
+ assertThat(underTest.countUsers(session, query)).isEqualTo(2);
+ }
+
+ @Test
+ public void selectUsersByQuery_whenSearchingByUuidsWithLongRange_shouldReturnTheExpectedUsers() {
+ db.users().insertUser();
+ List<UserDto> users = generateAndInsertUsers(3200);
+ Set<String> userUuids = users.stream()
+ .map(UserDto::getUuid)
+ .collect(toSet());
+
+ UserQuery query = UserQuery.builder().userUuids(userUuids).build();
+ List<UserDto> actualUsers = underTest.selectUsers(session, query);
+
+ assertThat(actualUsers.stream().map(UserDto::getUuid).collect(toSet()))
+ .containsExactlyInAnyOrderElementsOf(userUuids);
+ }
+
+ private List<UserDto> generateAndInsertUsers(int totalUsers) {
+ return IntStream.range(0, totalUsers)
+ .mapToObj(i -> db.users().insertUser())
+ .toList();
+ }
+
@DataProvider
public static Object[][] paginationTestCases() {
return new Object[][] {
}
return IntStream.range(1000 + (offset - 1) * limit, 1000 + offset * limit)
.mapToObj(i -> allUsers.get(i + "_name"))
- .collect(Collectors.toSet());
+ .collect(toSet());
}
@Test
.toList();
}
- public List<UserDto> selectUsers(DbSession dbSession, UserQuery query) {
- return mapper(dbSession).selectUsers(query, Pagination.all());
+ public List<UserDto> selectUsers(DbSession dbSession, UserQuery userQuery) {
+ return selectUsers(dbSession, userQuery, Pagination.all());
}
- public List<UserDto> selectUsers(DbSession dbSession, UserQuery query, int offset, int limit) {
- return mapper(dbSession).selectUsers(query, Pagination.forPage(offset).andSize(limit));
+ public List<UserDto> selectUsers(DbSession dbSession, UserQuery userQuery, int offset, int limit) {
+ Pagination pagination = Pagination.forPage(offset).andSize(limit);
+ return selectUsers(dbSession, userQuery, pagination);
+ }
+
+ private List<UserDto> selectUsers(DbSession dbSession, UserQuery userQuery, Pagination pagination) {
+ if (userQuery.getUserUuids() != null) {
+ return executeLargeInputs(
+ userQuery.getUserUuids(),
+ partialSetOfUsers -> mapper(dbSession).selectUsers(
+ UserQuery.copyWithNewRangeOfUserUuids(userQuery, partialSetOfUsers),
+ pagination)
+ );
+ }
+ return mapper(dbSession).selectUsers(userQuery, pagination);
}
public int countUsers(DbSession dbSession, UserQuery userQuery) {
import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;
+import java.util.Collection;
+import java.util.HashSet;
import java.util.Set;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
private final Long sonarLintLastConnectionDateTo;
private final Set<String> userUuids;
+ public static UserQuery copyWithNewRangeOfUserUuids(UserQuery userQuery, Collection<String> userUuids) {
+ return new UserQuery(userQuery, userUuids);
+ }
+
+ private UserQuery(UserQuery userQuery, Collection<String> userUuids) {
+ this.searchText = userQuery.getSearchText();
+ this.isActive = userQuery.isActive();
+ this.isManagedSqlClause = userQuery.getIsManagedSqlClause();
+ this.lastConnectionDateFrom = userQuery.getLastConnectionDateFrom();
+ this.lastConnectionDateTo = userQuery.getLastConnectionDateTo();
+ this.sonarLintLastConnectionDateTo = userQuery.getSonarLintLastConnectionDateTo();
+ this.sonarLintLastConnectionDateFrom = userQuery.getSonarLintLastConnectionDateFrom();
+ this.userUuids = new HashSet<>(userUuids);
+ }
+
private UserQuery(@Nullable String searchText, @Nullable Boolean isActive, @Nullable String isManagedSqlClause,
@Nullable OffsetDateTime lastConnectionDateFrom, @Nullable OffsetDateTime lastConnectionDateTo,
@Nullable OffsetDateTime sonarLintLastConnectionDateFrom, @Nullable OffsetDateTime sonarLintLastConnectionDateTo, @Nullable Set<String> userUuids) {
<if test="query.isActive != null">
AND u.active=#{query.isActive, jdbcType=BOOLEAN}
</if>
+ <if test="query.userUuids != null">
+ AND u.uuid in
+ <foreach collection="query.userUuids" open="(" close=")" item="userUuid" separator=",">
+ #{userUuid, jdbcType=VARCHAR}
+ </foreach>
+ </if>
<if test="query.searchText != null">
AND (
(lower(u.login) LIKE lower(#{query.searchText, jdbcType=VARCHAR}) ESCAPE '/')
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.db.user;
+
+import java.time.OffsetDateTime;
+import java.time.temporal.ChronoUnit;
+import java.util.Set;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class UserQueryTest {
+
+ @Test
+ public void copyWithNewRangeOfUserUuids_copyAllFieldsCorrectly() {
+ UserQuery original = createUserQueryWithAllFieldsSet();
+
+ Set<String> newRangeOfUsers = Set.of("user1");
+ UserQuery copy = UserQuery.copyWithNewRangeOfUserUuids(original, newRangeOfUsers);
+
+ assertThat(copy)
+ .usingRecursiveComparison()
+ .ignoringFields("userUuids")
+ .isEqualTo(original);
+
+ assertThat(copy.getUserUuids()).isEqualTo(newRangeOfUsers);
+ }
+
+ private static UserQuery createUserQueryWithAllFieldsSet() {
+ return UserQuery.builder()
+ .userUuids(Set.of("user1", "user2"))
+ .searchText("search text")
+ .isActive(true)
+ .isManagedClause("is managed clause")
+ .lastConnectionDateFrom(OffsetDateTime.now().minus(1, ChronoUnit.DAYS))
+ .lastConnectionDateTo(OffsetDateTime.now().plus(1, ChronoUnit.DECADES))
+ .sonarLintLastConnectionDateFrom(OffsetDateTime.now().plus(2, ChronoUnit.DAYS))
+ .sonarLintLastConnectionDateTo(OffsetDateTime.now().minus(2, ChronoUnit.DECADES))
+ .build();
+ }
+}