aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>2016-03-25 16:08:24 +0100
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>2016-03-31 15:22:07 +0200
commit894305bb873f56d55d4acff8a5657a1cd966ab0c (patch)
treede7cf54c4dccf0073f70f8b705c1947cd5cc11db
parentc156d7e0089c6d54e95fb7d1a85c17d2f7470dff (diff)
downloadsonarqube-894305bb873f56d55d4acff8a5657a1cd966ab0c.tar.gz
sonarqube-894305bb873f56d55d4acff8a5657a1cd966ab0c.zip
SONAR-7480 optimize SQL request in QP Search WS
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java15
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLoader.java6
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchAction.java6
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchDataLoader.java205
-rw-r--r--sonar-db/src/main/java/org/sonar/db/qualityprofile/QualityProfileDao.java41
-rw-r--r--sonar-db/src/main/java/org/sonar/db/qualityprofile/QualityProfileMapper.java6
-rw-r--r--sonar-db/src/main/resources/org/sonar/db/qualityprofile/QualityProfileMapper.xml49
-rw-r--r--sonar-db/src/test/java/org/sonar/db/qualityprofile/QualityProfileDaoTest.java42
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();
+ }
}