From 83f6879f59b1beca9eb44b70632e2e482f0dbe87 Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Mon, 13 Mar 2017 14:43:50 +0100 Subject: [PATCH] SONAR-8931 add OrganizationDao#.selectOrganizationsWithoutLoadedTemplate --- .../db/organization/OrganizationDao.java | 12 ++- .../db/organization/OrganizationMapper.java | 9 ++ .../db/organization/OrganizationMapper.xml | 51 +++++++++++ .../db/organization/OrganizationDaoTest.java | 85 +++++++++++++++++++ 4 files changed, 155 insertions(+), 2 deletions(-) diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationDao.java index d1ef05bd7e5..a2a7bc9543b 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationDao.java @@ -27,6 +27,7 @@ import org.sonar.api.utils.System2; import org.sonar.db.Dao; import org.sonar.db.DbSession; +import static com.google.common.base.Preconditions.checkArgument; import static java.util.Objects.requireNonNull; import static org.sonar.db.DatabaseUtils.executeLargeInputs; @@ -46,9 +47,9 @@ public class OrganizationDao implements Dao { getMapper(dbSession).insert(organization); } - public List selectByQuery(DbSession dbSession, OrganizationQuery organizationQuery, int offset, int limit) { + public List selectByQuery(DbSession dbSession, OrganizationQuery organizationQuery, int page, int pageSize) { requireNonNull(organizationQuery, "organizationQuery can't be null"); - return getMapper(dbSession).selectByQuery(organizationQuery, offset, limit); + return getMapper(dbSession).selectByQuery(organizationQuery, page, pageSize); } public Optional selectByUuid(DbSession dbSession, String uuid) { @@ -72,6 +73,13 @@ public class OrganizationDao implements Dao { return getMapper(dbSession).selectByPermission(userId, permission); } + public List selectOrganizationsWithoutLoadedTemplate(DbSession dbSession, String loadedTemplateType, int page, int pageSize) { + checkArgument(page >= 1, "page must be >= 1"); + checkArgument(pageSize >= 1, "page size must be >= 1"); + int offset = (page - 1) * pageSize; + return getMapper(dbSession).selectOrganizationsWithoutLoadedTemplate(loadedTemplateType, page, pageSize, offset); + } + /** * Retrieve the default template of the specified organization if: *
    diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationMapper.java index f26bfb0a954..05755c1d04b 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationMapper.java @@ -39,6 +39,15 @@ public interface OrganizationMapper { List selectByPermission(@Param("userId") Integer userId, @Param("permission") String permission); + /** + * Assuming the key of the loaded template with the specified type is an organization's UUID, select all organizations + * which does not have a row in table LOADED_TEMPLATES with the specified type. + * + * @param offset {@code ((#{page} - 1) * #{pageSize})} + */ + List selectOrganizationsWithoutLoadedTemplate(@Param("loadedTemplateType") String type, + @Param("page") int page, @Param("pageSize") int pageSize, @Param("offset") int offset); + DefaultTemplates selectDefaultTemplatesByUuid(@Param("uuid") String uuid); /** diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/organization/OrganizationMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/organization/OrganizationMapper.xml index bd8039014c3..826a66b434e 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/organization/OrganizationMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/organization/OrganizationMapper.xml @@ -123,6 +123,57 @@ and gu.user_id = #{userId,jdbcType=INTEGER} + + + + + + + + from + organizations org + where + not exists ( + select + 1 + from + loaded_templates lt + where + lt.template_type=#{loadedTemplateType,jdbcType=VARCHAR} + and lt.kee=org.uuid + ) + + insert into organizations ( diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationDaoTest.java index 1c1fe9287cf..0126857dc15 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationDaoTest.java @@ -29,6 +29,7 @@ import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.Random; +import java.util.stream.IntStream; import javax.annotation.Nullable; import org.apache.ibatis.exceptions.PersistenceException; import org.assertj.core.util.Lists; @@ -36,11 +37,13 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.utils.System2; +import org.sonar.api.utils.internal.AlwaysIncreasingSystem2; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.DbTester; import org.sonar.db.dialect.Dialect; import org.sonar.db.dialect.Oracle; +import org.sonar.db.loadedtemplate.LoadedTemplateDto; import org.sonar.db.user.GroupDto; import org.sonar.db.user.UserDto; @@ -841,6 +844,88 @@ public class OrganizationDaoTest { .containsOnlyOnce(organization.getUuid()); } + @Test + public void selectOrganizationsWithoutLoadedTemplate_returns_empty_if_there_is_no_organization() { + List organizationDtos = underTest.selectOrganizationsWithoutLoadedTemplate(dbSession, "type1", 1, Integer.MAX_VALUE); + + assertThat(organizationDtos).isEmpty(); + } + + @Test + public void selectOrganizationsWithoutLoadedTemplate_returns_all_organizations_if_loaded_template_table_is_empty() { + int organizationCount = Math.abs(new Random().nextInt(20)) + 1; + String[] organizationUuids = IntStream.range(0, organizationCount).mapToObj(i -> "uuid_" + i).toArray(String[]::new); + Arrays.stream(organizationUuids).forEach(uuid -> dbTester.organizations().insertForUuid(uuid)); + + List organizationDtos = underTest.selectOrganizationsWithoutLoadedTemplate(dbSession, "type1", 1, Integer.MAX_VALUE); + + assertThat(organizationDtos) + .extracting(OrganizationDto::getUuid) + .containsOnly(organizationUuids); + } + + @Test + public void selectOrganizationsWithoutLoadedTemplate_returns_all_organizations_but_those_with_loaded_template_with_specified_type_and_org_uuid_as_key() { + int organizationCount = Math.abs(new Random().nextInt(20)) + 5; + String[] organizationUuids = IntStream.range(0, organizationCount).mapToObj(i -> "uuid_" + i).toArray(String[]::new); + Arrays.stream(organizationUuids).forEach(uuid -> dbTester.organizations().insertForUuid(uuid)); + String loadedTemplateType = "type1"; + dbTester.getDbClient().loadedTemplateDao().insert(new LoadedTemplateDto(organizationUuids[0], loadedTemplateType), dbSession); + dbTester.getDbClient().loadedTemplateDao().insert(new LoadedTemplateDto(organizationUuids[1], "foo"), dbSession); + // matching is case sensitive + dbTester.getDbClient().loadedTemplateDao().insert(new LoadedTemplateDto(organizationUuids[2], loadedTemplateType.toUpperCase()), dbSession); + dbTester.getDbClient().loadedTemplateDao().insert(new LoadedTemplateDto(organizationUuids[3], loadedTemplateType), dbSession); + dbTester.getDbClient().loadedTemplateDao().insert(new LoadedTemplateDto(organizationUuids[4] + " not exactly the uuid", loadedTemplateType), dbSession); + dbTester.getDbClient().loadedTemplateDao().insert(new LoadedTemplateDto("foo", loadedTemplateType), dbSession); + dbTester.getDbClient().loadedTemplateDao().insert(new LoadedTemplateDto("", loadedTemplateType), dbSession); + dbTester.commit(); + + List organizationDtos = underTest.selectOrganizationsWithoutLoadedTemplate(dbSession, loadedTemplateType, 1, Integer.MAX_VALUE); + + assertThat(organizationDtos) + .extracting(OrganizationDto::getUuid) + .containsOnly( + Arrays.stream(organizationUuids) + .filter(s -> !s.equals(organizationUuids[0]) && !s.equals(organizationUuids[3])) + .toArray(String[]::new)); + } + + @Test + public void selectOrganizationsWithoutLoadedTemplate_is_paginated() { + AlwaysIncreasingSystem2 alwaysIncreasingSystem2 = new AlwaysIncreasingSystem2(500); + when(system2.now()).thenAnswer(t -> alwaysIncreasingSystem2.now()); + IntStream.range(1, 31).forEach(i -> dbTester.organizations().insertForUuid("" + i)); + + assertThat(underTest.selectOrganizationsWithoutLoadedTemplate(dbSession, "foo", 1, Integer.MAX_VALUE)) + .extracting(dto -> Integer.valueOf(dto.getUuid())) + .hasSize(30) + .allMatch(i -> i > 0 && i <= 30); + assertThat(underTest.selectOrganizationsWithoutLoadedTemplate(dbSession, "foo", 1, 30)) + .extracting(dto -> Integer.valueOf(dto.getUuid())) + .hasSize(30) + .allMatch(i -> i > 0 && i <= 30); + assertThat(underTest.selectOrganizationsWithoutLoadedTemplate(dbSession, "foo", 1, 10)) + .extracting(dto -> Integer.valueOf(dto.getUuid())) + .hasSize(10) + .allMatch(i -> i > 0 && i <= 10); + assertThat(underTest.selectOrganizationsWithoutLoadedTemplate(dbSession, "foo", 2, 10)) + .extracting(dto -> Integer.valueOf(dto.getUuid())) + .hasSize(10) + .allMatch(i -> i > 10 && i <= 20); + assertThat(underTest.selectOrganizationsWithoutLoadedTemplate(dbSession, "foo", 5, 5)) + .extracting(dto -> Integer.valueOf(dto.getUuid())) + .hasSize(5) + .allMatch(i -> i > 20 && i <= 25); + assertThat(underTest.selectOrganizationsWithoutLoadedTemplate(dbSession, "foo", 6, 5)) + .extracting(dto -> Integer.valueOf(dto.getUuid())) + .hasSize(5) + .allMatch(i -> i > 25 && i <= 30); + assertThat(underTest.selectOrganizationsWithoutLoadedTemplate(dbSession, "foo", 7, 5)) + .isEmpty(); + assertThat(underTest.selectOrganizationsWithoutLoadedTemplate(dbSession, "foo", 2, 50)) + .isEmpty(); + } + private void expectDtoCanNotBeNull() { expectedException.expect(NullPointerException.class); expectedException.expectMessage("OrganizationDto can't be null"); -- 2.39.5