diff options
author | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2016-03-25 16:08:24 +0100 |
---|---|---|
committer | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2016-03-31 15:22:07 +0200 |
commit | 894305bb873f56d55d4acff8a5657a1cd966ab0c (patch) | |
tree | de7cf54c4dccf0073f70f8b705c1947cd5cc11db | |
parent | c156d7e0089c6d54e95fb7d1a85c17d2f7470dff (diff) | |
download | sonarqube-894305bb873f56d55d4acff8a5657a1cd966ab0c.tar.gz sonarqube-894305bb873f56d55d4acff8a5657a1cd966ab0c.zip |
SONAR-7480 optimize SQL request in QP Search WS
8 files changed, 282 insertions, 88 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java index f5e458a2777..29903ee8dcc 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java @@ -21,8 +21,10 @@ package org.sonar.server.qualityprofile; import com.google.common.collect.Lists; import java.util.ArrayList; +import java.util.Collection; import java.util.Date; import java.util.List; +import java.util.Set; import javax.annotation.CheckForNull; import org.apache.commons.lang.RandomStringUtils; import org.apache.commons.lang.StringUtils; @@ -138,6 +140,11 @@ public class QProfileFactory { return db.qualityProfileDao().selectDefaultProfile(session, language); } + @CheckForNull + public List<QualityProfileDto> getDefaults(DbSession session, Collection<String> languageKeys) { + return db.qualityProfileDao().selectDefaultProfiles(session, languageKeys); + } + public void setDefault(String profileKey) { DbSession dbSession = db.openSession(false); try { @@ -179,6 +186,10 @@ public class QProfileFactory { return db.qualityProfileDao().selectByProjectAndLanguage(session, projectKey, language); } + public List<QualityProfileDto> getByProjectAndLanguages(DbSession session, String projectKey, Set<String> languageKeys) { + return db.qualityProfileDao().selectByProjectAndLanguages(session, projectKey, languageKeys); + } + QualityProfileDto getByNameAndLanguage(String name, String language) { DbSession dbSession = db.openSession(false); try { @@ -193,6 +204,10 @@ public class QProfileFactory { return db.qualityProfileDao().selectByNameAndLanguage(name, language, session); } + public List<QualityProfileDto> getByNameAndLanguages(DbSession session, String name, Collection<String> languages) { + return db.qualityProfileDao().selectByNameAndLanguages(name, languages, session); + } + private void checkNotDefault(QualityProfileDto p) { if (p.isDefault()) { throw new BadRequestException("The profile marked as default can not be deleted: " + p.getKey()); diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLoader.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLoader.java index 1e23d75a0f9..64230d8b40b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLoader.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLoader.java @@ -25,6 +25,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import javax.annotation.CheckForNull; import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.RuleStatus; @@ -100,8 +101,9 @@ public class QProfileLoader { } public Map<String, Long> countAllActiveRules() { - Map<String, Long> counts = new HashMap<>(); - for (Map.Entry<String, Long> entry : activeRuleIndex.countAllByQualityProfileKey().entrySet()) { + Set<Map.Entry<String, Long>> entries = activeRuleIndex.countAllByQualityProfileKey().entrySet(); + Map<String, Long> counts = new HashMap<>(entries.size()); + for (Map.Entry<String, Long> entry : entries) { counts.put(entry.getKey(), entry.getValue()); } return counts; diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchAction.java index 033280ff0e6..d05d1fa7a1b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchAction.java @@ -108,7 +108,7 @@ public class SearchAction implements QProfileWsAction { private SearchWsResponse buildResponse(SearchData data) { List<QProfile> profiles = data.getProfiles(); - Map<String, QProfile> profilesByKey = uniqueIndex(profiles, new QProfileToKey()); + Map<String, QProfile> profilesByKey = uniqueIndex(profiles, QProfileToKey.INSTANCE); QualityProfiles.SearchWsResponse.Builder response = QualityProfiles.SearchWsResponse.newBuilder(); QualityProfile.Builder profileBuilder = QualityProfile.newBuilder(); @@ -169,7 +169,9 @@ public class SearchAction implements QProfileWsAction { return value != null; } - private static class QProfileToKey implements Function<QProfile, String> { + private enum QProfileToKey implements Function<QProfile, String> { + INSTANCE; + @Override public String apply(@Nonnull QProfile input) { return input.key(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchDataLoader.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchDataLoader.java index 0ee94761834..71348447368 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchDataLoader.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchDataLoader.java @@ -19,10 +19,16 @@ */ package org.sonar.server.qualityprofile.ws; +import com.google.common.base.Function; import com.google.common.base.Predicate; -import java.util.ArrayList; +import com.google.common.collect.Sets; +import java.util.Arrays; +import java.util.Collection; import java.util.Comparator; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Set; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.apache.commons.lang.builder.CompareToBuilder; @@ -39,7 +45,6 @@ import org.sonar.server.qualityprofile.QProfileLoader; import org.sonar.server.qualityprofile.QProfileLookup; import org.sonarqube.ws.client.qualityprofile.SearchWsRequest; -import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.FluentIterable.from; import static java.lang.String.format; import static org.sonar.server.ws.WsUtils.checkRequest; @@ -51,6 +56,7 @@ public class SearchDataLoader { private final QProfileFactory profileFactory; private final DbClient dbClient; private final ComponentFinder componentFinder; + private final IsLanguageKnown isLanguageKnown; public SearchDataLoader(Languages languages, QProfileLookup profileLookup, QProfileLoader profileLoader, QProfileFactory profileFactory, DbClient dbClient, ComponentFinder componentFinder) { @@ -60,6 +66,7 @@ public class SearchDataLoader { this.profileFactory = profileFactory; this.dbClient = dbClient; this.componentFinder = componentFinder; + this.isLanguageKnown = new IsLanguageKnown(); } SearchData load(SearchWsRequest request) { @@ -72,7 +79,7 @@ public class SearchDataLoader { } private List<QProfile> findProfiles(SearchWsRequest request) { - List<QProfile> profiles; + Collection<QProfile> profiles; if (askDefaultProfiles(request)) { profiles = findDefaultProfiles(request); } else if (hasComponentKey(request)) { @@ -81,105 +88,125 @@ public class SearchDataLoader { profiles = findAllProfiles(request); } - return orderProfiles(profiles); + return from(profiles).toSortedList(QProfileComparator.INSTANCE); } - private static List<QProfile> orderProfiles(List<QProfile> profiles) { - return from(profiles) - .toSortedList(QProfileComparator.INSTANCE); - } + private Collection<QProfile> findDefaultProfiles(SearchWsRequest request) { + String profileName = request.getProfileName(); - private List<QProfile> findAllProfiles(SearchWsRequest request) { - String language = request.getLanguage(); + Set<String> languageKeys = getLanguageKeys(); + try (DbSession dbSession = dbClient.openSession(false)) { + Map<String, QProfile> qualityProfiles = new HashMap<>(languageKeys.size()); - List<QProfile> profiles = language != null ? profileLookup.profiles(language) - : profileLookup.allProfiles(); + Set<String> missingLanguageKeys = lookupByProfileName(dbSession, qualityProfiles, languageKeys, profileName); + Set<String> noDefaultProfileLanguageKeys = lookupDefaults(dbSession, qualityProfiles, missingLanguageKeys); - return from(profiles) - .filter(new IsLanguageKnown()) - .toList(); + if (!noDefaultProfileLanguageKeys.isEmpty()) { + throw new IllegalStateException(format("No quality profile can been found on language(s) '%s'", noDefaultProfileLanguageKeys)); + } + + return qualityProfiles.values(); + } } - private List<QProfile> findProjectProfiles(SearchWsRequest request) { - String moduleKey = request.getProjectKey(); + private Collection<QProfile> findProjectProfiles(SearchWsRequest request) { + String componentKey = request.getProjectKey(); String profileName = request.getProfileName(); - List<QProfile> profiles = new ArrayList<>(); + Set<String> languageKeys = getLanguageKeys(); + try (DbSession dbSession = dbClient.openSession(false)) { + Map<String, QProfile> qualityProfiles = new HashMap<>(languageKeys.size()); + + // look up profiles by profileName (if any) for each language + Set<String> unresolvedLanguages = lookupByProfileName(dbSession, qualityProfiles, languageKeys, profileName); + // look up profile by componentKey for each language for which we don't have one yet + Set<String> stillUnresolvedLanguages = lookupByModuleKey(dbSession, qualityProfiles, unresolvedLanguages, componentKey); + // look up profile by default for each language for which we don't have one yet + Set<String> noDefaultProfileLanguages = lookupDefaults(dbSession, qualityProfiles, stillUnresolvedLanguages); - DbSession dbSession = dbClient.openSession(false); - try { - for (Language language : languages.all()) { - String languageKey = language.getKey(); - ComponentDto project = getProject(moduleKey, dbSession); - profiles.add(getProfile(dbSession, languageKey, project.key(), profileName)); + if (!noDefaultProfileLanguages.isEmpty()) { + throw new IllegalStateException(format("No quality profile can been found on language(s) '%s' for project '%s'", noDefaultProfileLanguages, componentKey)); } - } finally { - dbClient.closeSession(dbSession); + + return qualityProfiles.values(); } + } + + private List<QProfile> findAllProfiles(SearchWsRequest request) { + String language = request.getLanguage(); - return profiles; + if (language == null) { + return from(profileLookup.allProfiles()).filter(isLanguageKnown).toList(); + } + return profileLookup.profiles(language); + } + + private Set<String> lookupByProfileName(DbSession dbSession, Map<String, QProfile> qualityProfiles, Set<String> languageKeys, @Nullable String profileName) { + if (languageKeys.isEmpty() || profileName == null) { + return languageKeys; + } + + addAllFromDto(qualityProfiles, profileFactory.getByNameAndLanguages(dbSession, profileName, languageKeys)); + return difference(languageKeys, qualityProfiles.keySet()); + } + + private Set<String> lookupByModuleKey(DbSession dbSession, Map<String, QProfile> qualityProfiles, Set<String> languageKeys, @Nullable String moduleKey) { + if (languageKeys.isEmpty() || moduleKey == null) { + return languageKeys; + } + + ComponentDto project = getProject(moduleKey, dbSession); + addAllFromDto(qualityProfiles, profileFactory.getByProjectAndLanguages(dbSession, project.getKey(), languageKeys)); + return difference(languageKeys, qualityProfiles.keySet()); } private ComponentDto getProject(String moduleKey, DbSession session) { ComponentDto module = componentFinder.getByKey(session, moduleKey); - if (!module.isRootProject()) { - return dbClient.componentDao().selectOrFailByUuid(session, module.projectUuid()); - } else { + if (module.isRootProject()) { return module; } + return dbClient.componentDao().selectOrFailByUuid(session, module.projectUuid()); } - private List<QProfile> findDefaultProfiles(SearchWsRequest request) { - String profileName = request.getProfileName(); - List<QProfile> profiles = new ArrayList<>(); + private Set<String> lookupDefaults(DbSession dbSession, Map<String, QProfile> qualityProfiles, Set<String> languageKeys) { + if (languageKeys.isEmpty()) { + return languageKeys; + } - DbSession dbSession = dbClient.openSession(false); - try { - for (Language language : languages.all()) { - profiles.add(getDefaultProfile(dbSession, language.getKey(), profileName)); - } - } finally { - dbClient.closeSession(dbSession); + addAll(qualityProfiles, findDefaultProfiles(dbSession, languageKeys)); + return difference(languageKeys, qualityProfiles.keySet()); + } + + private static <T> Set<T> difference(Set<T> languageKeys, Set<T> set2) { + return Sets.newHashSet(Sets.difference(languageKeys, set2)); + } + + private void addAllFromDto(Map<String, QProfile> qualityProfiles, Collection<QualityProfileDto> list) { + for (QualityProfileDto qualityProfileDto : list) { + qualityProfiles.put(qualityProfileDto.getLanguage(), QualityProfileDtoToQProfile.INSTANCE.apply(qualityProfileDto)); } + } - return profiles; - } - - private static QProfile profileDtoToQProfile(QualityProfileDto dto) { - return new QProfile() - .setKey(dto.getKey()) - .setName(dto.getName()) - .setLanguage(dto.getLanguage()) - .setDefault(dto.isDefault()) - .setRulesUpdatedAt(dto.getRulesUpdatedAt()); - } - - /** - * First try to find a quality profile matching the given name (if provided) and current language - * If no profile found, try to find the quality profile set on the project (if provided) - * If still no profile found, try to find the default profile of the language - * <p/> - * Never return null because a default profile should always be set on each language - */ - private QProfile getProfile(DbSession dbSession, String languageKey, @Nullable String projectKey, @Nullable String profileName) { - QualityProfileDto profileDto = profileName != null ? profileFactory.getByNameAndLanguage(dbSession, profileName, languageKey) : null; - if (profileDto == null && projectKey != null) { - profileDto = profileFactory.getByProjectAndLanguage(dbSession, projectKey, languageKey); + private void addAll(Map<String, QProfile> qualityProfiles, Collection<QProfile> list) { + for (QProfile qProfile : list) { + qualityProfiles.put(qProfile.language(), qProfile); } - profileDto = profileDto != null ? profileDto : profileFactory.getDefault(dbSession, languageKey); - checkState(profileDto != null, format("No quality profile can been found on language '%s' for project '%s'", languageKey, projectKey)); + } - return profileDtoToQProfile(profileDto); + private Set<String> getLanguageKeys() { + return from(Arrays.asList(languages.all())).transform(LanguageToKey.INSTANCE).toSet(); } - private QProfile getDefaultProfile(DbSession dbSession, String languageKey, @Nullable String profileName) { - QualityProfileDto profile = profileName != null ? profileFactory.getByNameAndLanguage(dbSession, profileName, languageKey) : null; - if (profile == null) { - profile = profileFactory.getDefault(dbSession, languageKey); + private List<QProfile> findDefaultProfiles(Set<String> languageKeys) { + try (DbSession dbSession = dbClient.openSession(false)) { + return findDefaultProfiles(dbSession, languageKeys); } - checkState(profile != null, format("No quality profile can been found on language '%s'", languageKey)); + } - return profileDtoToQProfile(profile); + private List<QProfile> findDefaultProfiles(final DbSession dbSession, Set<String> languageKeys) { + return from(profileFactory.getDefaults(dbSession, languageKeys)) + .transform(QualityProfileDtoToQProfile.INSTANCE) + .toList(); } private static void validateRequest(SearchWsRequest request) { @@ -193,6 +220,10 @@ public class SearchDataLoader { checkRequest(!isDefault || !hasComponentKey, "The default parameter cannot be provided at the same time than the component key"); } + private static boolean askDefaultProfiles(SearchWsRequest request) { + return request.getDefaults(); + } + private static boolean hasProfileName(SearchWsRequest request) { return request.getProfileName() != null; } @@ -201,10 +232,6 @@ public class SearchDataLoader { return request.getProjectKey() != null; } - private static Boolean askDefaultProfiles(SearchWsRequest request) { - return request.getDefaults(); - } - private static boolean hasLanguage(SearchWsRequest request) { return request.getLanguage() != null; } @@ -220,6 +247,32 @@ public class SearchDataLoader { } } + private enum LanguageToKey implements Function<Language, String> { + INSTANCE; + + @Override + @Nonnull + public String apply(@Nonnull Language input) { + return input.getKey(); + } + } + + private enum QualityProfileDtoToQProfile implements Function<QualityProfileDto, QProfile> { + INSTANCE; + + @Override + @Nonnull + public QProfile apply(@Nonnull QualityProfileDto input) { + return new QProfile() + .setKey(input.getKey()) + .setName(input.getName()) + .setLanguage(input.getLanguage()) + .setDefault(input.isDefault()) + .setRulesUpdatedAt(input.getRulesUpdatedAt()); + } + + } + private class IsLanguageKnown implements Predicate<QProfile> { @Override public boolean apply(@Nonnull QProfile profile) { diff --git a/sonar-db/src/main/java/org/sonar/db/qualityprofile/QualityProfileDao.java b/sonar-db/src/main/java/org/sonar/db/qualityprofile/QualityProfileDao.java index ca2ec555f1c..fbe2d1913c2 100644 --- a/sonar-db/src/main/java/org/sonar/db/qualityprofile/QualityProfileDao.java +++ b/sonar-db/src/main/java/org/sonar/db/qualityprofile/QualityProfileDao.java @@ -19,16 +19,20 @@ */ package org.sonar.db.qualityprofile; +import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Map; import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.sonar.api.utils.System2; import org.sonar.db.Dao; +import org.sonar.db.DatabaseUtils; import org.sonar.db.DbSession; import org.sonar.db.MyBatis; import org.sonar.db.RowNotFoundException; @@ -155,8 +159,7 @@ public class QualityProfileDao implements Dao { } /** - * @deprecated Replaced by - * {@link #selectAll(DbSession)} + * @deprecated Replaced by {@link #selectAll(DbSession)} */ @Deprecated public List<QualityProfileDto> selectAll() { @@ -169,7 +172,18 @@ public class QualityProfileDao implements Dao { } @CheckForNull - public QualityProfileDto selectDefaultProfile(DbSession session, String language) { + public List<QualityProfileDto> selectDefaultProfiles(final DbSession session, Collection<String> languageKeys) { + return DatabaseUtils.executeLargeInputs(languageKeys, new Function<List<String>, List<QualityProfileDto>>() { + @Override + @Nonnull + public List<QualityProfileDto> apply(@Nonnull List<String> input) { + return mapper(session).selectDefaultProfiles(input); + } + }); + } + + @CheckForNull + public QualityProfileDto selectDefaultProfile(final DbSession session, String language) { return mapper(session).selectDefaultProfile(language); } @@ -198,6 +212,16 @@ public class QualityProfileDao implements Dao { return mapper(session).selectByProjectAndLanguage(projectKey, language); } + public List<QualityProfileDto> selectByProjectAndLanguages(final DbSession session, final String projectKey, Collection<String> languageKeys) { + return DatabaseUtils.executeLargeInputs(languageKeys, new Function<List<String>, List<QualityProfileDto>>() { + @Override + @Nonnull + public List<QualityProfileDto> apply(@Nonnull List<String> input) { + return mapper(session).selectByProjectAndLanguages(projectKey, input); + } + }); + } + public List<QualityProfileDto> selectByLanguage(String language) { DbSession session = mybatis.openSession(false); try { @@ -273,6 +297,16 @@ public class QualityProfileDao implements Dao { return mapper(session).selectByNameAndLanguage(name, language); } + public List<QualityProfileDto> selectByNameAndLanguages(final String name, Collection<String> languageKeys, final DbSession session) { + return DatabaseUtils.executeLargeInputs(languageKeys, new Function<List<String>, List<QualityProfileDto>>() { + @Override + @Nonnull + public List<QualityProfileDto> apply(@Nonnull List<String> input) { + return mapper(session).selectByNameAndLanguages(name, input); + } + }); + } + public List<ComponentDto> selectProjects(String profileName, String language) { DbSession session = mybatis.openSession(false); try { @@ -346,5 +380,4 @@ public class QualityProfileDao implements Dao { private QualityProfileMapper mapper(DbSession session) { return session.getMapper(QualityProfileMapper.class); } - } diff --git a/sonar-db/src/main/java/org/sonar/db/qualityprofile/QualityProfileMapper.java b/sonar-db/src/main/java/org/sonar/db/qualityprofile/QualityProfileMapper.java index d2f9e73a959..b8a6ef79c09 100644 --- a/sonar-db/src/main/java/org/sonar/db/qualityprofile/QualityProfileMapper.java +++ b/sonar-db/src/main/java/org/sonar/db/qualityprofile/QualityProfileMapper.java @@ -37,9 +37,13 @@ public interface QualityProfileMapper { @CheckForNull QualityProfileDto selectDefaultProfile(@Param("language") String language); + List<QualityProfileDto> selectDefaultProfiles(@Param("languages") List<String> languages); + @CheckForNull QualityProfileDto selectByNameAndLanguage(@Param("name") String name, @Param("language") String language); + List<QualityProfileDto> selectByNameAndLanguages(@Param("name") String name, @Param("languages") List<String> languages); + @CheckForNull QualityProfileDto selectById(@Param("id") Integer id); @@ -70,6 +74,8 @@ public interface QualityProfileMapper { QualityProfileDto selectByProjectAndLanguage(@Param("projectKey") String projectKey, @Param("language") String language); + List<QualityProfileDto> selectByProjectAndLanguages(@Param("projectKey") String projectKey, @Param("languages") List<String> input); + void insertProjectProfileAssociation(@Param("projectUuid") String projectUuid, @Param("profileKey") String profileKey); void updateProjectProfileAssociation(@Param("projectUuid") String projectUuid, @Param("profileKey") String profileKey); diff --git a/sonar-db/src/main/resources/org/sonar/db/qualityprofile/QualityProfileMapper.xml b/sonar-db/src/main/resources/org/sonar/db/qualityprofile/QualityProfileMapper.xml index 873a983c4cb..edc2563f8e2 100644 --- a/sonar-db/src/main/resources/org/sonar/db/qualityprofile/QualityProfileMapper.xml +++ b/sonar-db/src/main/resources/org/sonar/db/qualityprofile/QualityProfileMapper.xml @@ -49,6 +49,19 @@ WHERE p.name=#{name} AND p.language=#{language} </select> + <select id="selectByNameAndLanguages" parameterType="map" resultType="QualityProfile"> + SELECT + <include refid="profilesColumns"/> + FROM rules_profiles p + <where> + p.name=#{name} + AND p.language in + <foreach collection="languages" open="(" close=")" item="language" separator=","> + #{language} + </foreach> + </where> + </select> + <select id="selectByKey" parameterType="string" resultType="QualityProfile"> SELECT <include refid="profilesColumns"/> @@ -97,8 +110,23 @@ SELECT <include refid="profilesColumns"/> FROM rules_profiles p - WHERE p.is_default=${_true} - AND p.language=#{language} + <where> + p.is_default=${_true} + AND p.language=#{language} + </where> + </select> + + <select id="selectDefaultProfiles" parameterType="map" resultType="QualityProfile"> + SELECT + <include refid="profilesColumns"/> + FROM rules_profiles p + <where> + p.is_default=${_true} + AND p.language in + <foreach collection="languages" open="(" close=")" item="language" separator=","> + #{language} + </foreach> + </where> </select> <select id="selectProjects" resultType="Component"> @@ -184,11 +212,24 @@ <include refid="profilesColumns"/> FROM rules_profiles p JOIN project_qprofiles pp ON pp.profile_key=p.kee - JOIN projects project ON pp.project_uuid=project.uuid - AND project.kee=#{projectKey} + JOIN projects project ON pp.project_uuid=project.uuid AND project.kee=#{projectKey} WHERE p.language=#{language} </select> + <select id="selectByProjectAndLanguages" parameterType="map" resultType="QualityProfile"> + SELECT + <include refid="profilesColumns"/> + FROM rules_profiles p + JOIN project_qprofiles pp ON pp.profile_key=p.kee + JOIN projects project ON pp.project_uuid=project.uuid AND project.kee=#{projectKey} + <where> + p.language in + <foreach collection="languages" open="(" close=")" item="language" separator=","> + #{language} + </foreach> + </where> + </select> + <insert id="insertProjectProfileAssociation" keyColumn="id" useGeneratedKeys="true"> INSERT INTO project_qprofiles (project_uuid, profile_key) VALUES (#{projectUuid}, #{profileKey}) </insert> diff --git a/sonar-db/src/test/java/org/sonar/db/qualityprofile/QualityProfileDaoTest.java b/sonar-db/src/test/java/org/sonar/db/qualityprofile/QualityProfileDaoTest.java index f53a1edd2b1..d47a6e19467 100644 --- a/sonar-db/src/test/java/org/sonar/db/qualityprofile/QualityProfileDaoTest.java +++ b/sonar-db/src/test/java/org/sonar/db/qualityprofile/QualityProfileDaoTest.java @@ -28,6 +28,8 @@ import org.sonar.api.utils.System2; import org.sonar.core.util.UtcDateUtils; import org.sonar.db.DbTester; +import static com.google.common.collect.ImmutableList.of; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -130,6 +132,18 @@ public class QualityProfileDaoTest { } @Test + public void get_default_profiles() { + dbTester.prepareDbUnit(getClass(), "shared.xml"); + + List<QualityProfileDto> java = dao.selectDefaultProfiles(dbTester.getSession(), singletonList("java")); + assertThat(java).extracting("key").containsOnly("java_sonar_way"); + + assertThat(dao.selectDefaultProfiles(dbTester.getSession(), singletonList("js"))).isEmpty(); + assertThat(dao.selectDefaultProfiles(dbTester.getSession(), of("java", "js"))).extracting("key").containsOnly("java_sonar_way"); + assertThat(dao.selectDefaultProfiles(dbTester.getSession(), of("js", "java"))).extracting("key").containsOnly("java_sonar_way"); + } + + @Test public void get_by_name_and_language() { dbTester.prepareDbUnit(getClass(), "shared.xml"); @@ -144,6 +158,22 @@ public class QualityProfileDaoTest { } @Test + public void get_by_name_and_languages() { + dbTester.prepareDbUnit(getClass(), "shared.xml"); + + List<QualityProfileDto> dtos = dao.selectByNameAndLanguages("Sonar Way", singletonList("java"), dbTester.getSession()); + assertThat(dtos).hasSize(1); + QualityProfileDto dto = dtos.iterator().next(); + assertThat(dto.getId()).isEqualTo(1); + assertThat(dto.getName()).isEqualTo("Sonar Way"); + assertThat(dto.getLanguage()).isEqualTo("java"); + assertThat(dto.getParentKee()).isNull(); + + assertThat(dao.selectByNameAndLanguages("Sonar Way", singletonList("unknown"), dbTester.getSession())).isEmpty(); + assertThat(dao.selectByNameAndLanguages("Sonar Way", of("java", "unknown"), dbTester.getSession())).extracting("id").containsOnly(1); + } + + @Test public void find_by_language() { dbTester.prepareDbUnit(getClass(), "select_by_language.xml"); @@ -236,4 +266,16 @@ public class QualityProfileDaoTest { assertThat(dao.selectByProjectAndLanguage(dbTester.getSession(), "org.codehaus.sonar:sonar", "unkown")).isNull(); assertThat(dao.selectByProjectAndLanguage(dbTester.getSession(), "unknown", "java")).isNull(); } + + @Test + public void select_by_project_key_and_languages() { + dbTester.prepareDbUnit(getClass(), "projects.xml"); + + List<QualityProfileDto> dto = dao.selectByProjectAndLanguages(dbTester.getSession(), "org.codehaus.sonar:sonar", singletonList("java")); + assertThat(dto).extracting("id").containsOnly(1); + + assertThat(dao.selectByProjectAndLanguages(dbTester.getSession(), "org.codehaus.sonar:sonar", singletonList("unkown"))).isEmpty(); + assertThat(dao.selectByProjectAndLanguages(dbTester.getSession(), "org.codehaus.sonar:sonar", of("java", "unkown"))).extracting("id").containsOnly(1); + assertThat(dao.selectByProjectAndLanguages(dbTester.getSession(), "unknown", singletonList("java"))).isEmpty(); + } } |