import org.sonar.server.rule.RuleUpdater;
import org.sonar.server.rule.ws.ActiveRuleCompleter;
import org.sonar.server.rule.ws.RepositoriesAction;
+import org.sonar.server.rule.ws.RuleMapper;
import org.sonar.server.rule.ws.RuleMapping;
import org.sonar.server.rule.ws.RulesWs;
import org.sonar.server.rule.ws.TagsAction;
org.sonar.server.rule.ws.ListAction.class,
TagsAction.class,
RuleMapping.class,
+ RuleMapper.class,
ActiveRuleCompleter.class,
RepositoriesAction.class,
org.sonar.server.rule.ws.AppAction.class,
*/
package org.sonar.server.qualityprofile.db;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+import java.util.List;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import org.sonar.api.utils.System2;
+import org.sonar.db.DatabaseUtils;
import org.sonar.db.DbSession;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.ActiveRuleKey;
import org.sonar.server.rule.db.RuleDao;
import org.sonar.server.search.IndexDefinition;
-import javax.annotation.CheckForNull;
-
-import java.util.List;
+import static java.util.Collections.emptyList;
public class ActiveRuleDao extends BaseDao<ActiveRuleMapper, ActiveRuleDto, ActiveRuleKey> {
this.profileDao = profileDao;
}
- /**
- * @deprecated do not use ids but keys
- */
@CheckForNull
@Deprecated
public ActiveRuleDto selectById(DbSession session, int activeRuleId) {
return mapper(dbSession).selectAllParams();
}
+ public Optional<ActiveRuleDto> selectByActiveRuleKey(DbSession dbSession, ActiveRuleKey key) {
+ return Optional.fromNullable(mapper(dbSession).selectByKey(key.qProfile(), key.ruleKey().repository(), key.ruleKey().rule()));
+ }
+
+ public List<ActiveRuleDto> selectByActiveRuleKeys(final DbSession dbSession, final List<ActiveRuleKey> keys) {
+ if (keys.isEmpty()) {
+ return emptyList();
+ }
+
+ return DatabaseUtils.executeLargeInputs(keys, new Function<List<ActiveRuleKey>, List<ActiveRuleDto>>() {
+ @Override
+ public List<ActiveRuleDto> apply(@Nonnull List<ActiveRuleKey> input) {
+ return mapper(dbSession).selectByKeys(input);
+ }
+ });
+ }
+
/**
* Nested DTO ActiveRuleParams
*/
return mapper(session).selectParamsByActiveRuleId(activeRule.getId());
}
+ public List<ActiveRuleParamDto> selectParamsByActiveRuleId(DbSession dbSession, Integer activeRuleId) {
+ return mapper(dbSession).selectParamsByActiveRuleId(activeRuleId);
+ }
+
+ public List<ActiveRuleParamDto> selectParamsByActiveRuleIds(final DbSession dbSession, List<Integer> activeRuleIds) {
+ if (activeRuleIds.isEmpty()) {
+ return emptyList();
+ }
+
+ return DatabaseUtils.executeLargeInputs(activeRuleIds, new Function<List<Integer>, List<ActiveRuleParamDto>>() {
+ @Override
+ public List<ActiveRuleParamDto> apply(@Nullable List<Integer> input) {
+ return mapper(dbSession).selectParamsByActiveRuleIds(input);
+ }
+ });
+ }
+
@CheckForNull
public ActiveRuleParamDto selectParamByKeyAndName(ActiveRuleKey key, String name, DbSession session) {
Preconditions.checkNotNull(key, ACTIVE_RULE_KEY_CANNOT_BE_NULL);
*/
package org.sonar.server.rule.ws;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ListMultimap;
+import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
-import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
import org.sonar.api.resources.Language;
import org.sonar.api.resources.Languages;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
+import org.sonar.db.DbSession;
+import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.ActiveRuleKey;
+import org.sonar.db.qualityprofile.ActiveRuleParamDto;
import org.sonar.db.qualityprofile.QualityProfileDto;
+import org.sonar.db.rule.RuleDto;
+import org.sonar.server.db.DbClient;
import org.sonar.server.qualityprofile.ActiveRule;
import org.sonar.server.qualityprofile.QProfileLoader;
import org.sonar.server.rule.Rule;
import static com.google.common.base.Strings.nullToEmpty;
import static com.google.common.collect.Sets.newHashSet;
+import static java.util.Collections.singletonList;
+import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;
/**
* Add details about active rules to api/rules/search and api/rules/show
private static final Logger LOG = Loggers.get(ActiveRuleCompleter.class);
+ private final DbClient dbClient;
private final QProfileLoader loader;
private final Languages languages;
- public ActiveRuleCompleter(QProfileLoader loader, Languages languages) {
+ public ActiveRuleCompleter(DbClient dbClient, QProfileLoader loader, Languages languages) {
+ this.dbClient = dbClient;
this.loader = loader;
this.languages = languages;
}
- void completeSearch(RuleQuery query, Collection<Rule> rules, SearchResponse.Builder searchResponse) {
- Collection<String> harvestedProfileKeys = writeActiveRules(searchResponse, query, rules);
+ void completeSearch(DbSession dbSession, RuleQuery query, List<RuleDto> rules, SearchResponse.Builder searchResponse) {
+ Collection<String> harvestedProfileKeys = writeActiveRules(dbSession, searchResponse, query, rules);
searchResponse.setQProfiles(buildQProfiles(harvestedProfileKeys));
}
- private Collection<String> writeActiveRules(SearchResponse.Builder response, RuleQuery query, Collection<Rule> rules) {
+ private Collection<String> writeActiveRules(DbSession dbSession, SearchResponse.Builder response, RuleQuery query, Collection<RuleDto> rules) {
Collection<String> qProfileKeys = newHashSet();
Rules.Actives.Builder activesBuilder = response.getActivesBuilder();
String profileKey = query.getQProfileKey();
if (profileKey != null) {
// Load details of active rules on the selected profile
- for (Rule rule : rules) {
- ActiveRule activeRule = loader.getActiveRule(ActiveRuleKey.of(profileKey, rule.key()));
+ for (RuleDto rule : rules) {
+ ActiveRule activeRule = loader.getActiveRule(ActiveRuleKey.of(profileKey, rule.getKey()));
if (activeRule != null) {
- qProfileKeys = writeActiveRules(rule.key(), Arrays.asList(activeRule), activesBuilder);
+ Optional<ActiveRuleDto> activeRuleDto = dbClient.activeRuleDao().selectByActiveRuleKey(dbSession, activeRule.key());
+ checkFoundWithOptional(activeRuleDto, "Active rule with key '%s' not found", activeRule.key().toString());
+ List<ActiveRuleParamDto> activeRuleParamDtos = dbClient.activeRuleDao().selectParamsByActiveRuleId(dbSession, activeRuleDto.get().getId());
+ ListMultimap<ActiveRuleKey, ActiveRuleParamDto> activeRuleParamByActiveRuleKey = ArrayListMultimap.create(1, activeRuleParamDtos.size());
+ activeRuleParamByActiveRuleKey.putAll(activeRule.key(), activeRuleParamDtos);
+ qProfileKeys = writeActiveRules(rule.getKey(), singletonList(activeRule), activeRuleParamByActiveRuleKey, activesBuilder);
}
}
} else {
// Load details of all active rules
- for (Rule rule : rules) {
- qProfileKeys = writeActiveRules(rule.key(), loader.findActiveRulesByRule(rule.key()), activesBuilder);
+ for (RuleDto rule : rules) {
+ List<ActiveRule> activeRules = loader.findActiveRulesByRule(rule.getKey());
+ List<ActiveRuleDto> activeRuleDtos = dbClient.activeRuleDao().selectByActiveRuleKeys(dbSession, Lists.transform(activeRules, ActiveRuleToKey.INSTANCE));
+ Map<Integer, ActiveRuleKey> activeRuleIdsByKey = new HashMap<>();
+ for (ActiveRuleDto activeRuleDto : activeRuleDtos) {
+ activeRuleIdsByKey.put(activeRuleDto.getId(), activeRuleDto.getKey());
+ }
+
+ List<ActiveRuleParamDto> activeRuleParamDtos = dbClient.activeRuleDao().selectParamsByActiveRuleIds(dbSession, Lists.transform(activeRuleDtos, ActiveRuleDtoToId.INSTANCE));
+ ListMultimap<ActiveRuleKey, ActiveRuleParamDto> activeRuleParamsByActiveRuleKey = ArrayListMultimap.create(activeRules.size(), 10);
+ for (ActiveRuleParamDto activeRuleParamDto : activeRuleParamDtos) {
+ ActiveRuleKey activeRuleKey = activeRuleIdsByKey.get(activeRuleParamDto.getId());
+ activeRuleParamsByActiveRuleKey.put(activeRuleKey, activeRuleParamDto);
+ }
+
+ qProfileKeys = writeActiveRules(rule.getKey(), activeRules, activeRuleParamsByActiveRuleKey, activesBuilder);
}
}
void completeShow(Rule rule, ShowResponse.Builder response) {
for (ActiveRule activeRule : loader.findActiveRulesByRule(rule.key())) {
- response.addActives(buildActiveRuleResponse(activeRule));
+ response.addActives(buildActiveRuleResponse(activeRule, Collections.<ActiveRuleParamDto>emptyList()));
}
}
- private static Collection<String> writeActiveRules(RuleKey ruleKey, Collection<ActiveRule> activeRules, Rules.Actives.Builder activesBuilder) {
+ private static Collection<String> writeActiveRules(RuleKey ruleKey, Collection<ActiveRule> activeRules,
+ ListMultimap<ActiveRuleKey, ActiveRuleParamDto> activeRuleParamsByActiveRuleKey, Rules.Actives.Builder activesBuilder) {
Collection<String> qProfileKeys = newHashSet();
Rules.ActiveList.Builder activeRulesListResponse = Rules.ActiveList.newBuilder();
for (ActiveRule activeRule : activeRules) {
- activeRulesListResponse.addActiveList(buildActiveRuleResponse(activeRule));
+ activeRulesListResponse.addActiveList(buildActiveRuleResponse(activeRule, activeRuleParamsByActiveRuleKey.get(activeRule.key())));
qProfileKeys.add(activeRule.key().qProfile());
}
activesBuilder
return qProfileKeys;
}
- private static Rules.Active buildActiveRuleResponse(ActiveRule activeRule) {
+ private static Rules.Active buildActiveRuleResponse(ActiveRule activeRule, List<ActiveRuleParamDto> parameters) {
Rules.Active.Builder activeRuleResponse = Rules.Active.newBuilder();
activeRuleResponse.setQProfile(activeRule.key().qProfile());
activeRuleResponse.setInherit(activeRule.inheritance().toString());
activeRuleResponse.setParent(parentKey.toString());
}
Rules.Active.Param.Builder paramBuilder = Rules.Active.Param.newBuilder();
- for (Map.Entry<String, String> param : activeRule.params().entrySet()) {
+ for (ActiveRuleParamDto parameter : parameters) {
activeRuleResponse.addParams(paramBuilder.clear()
- .setKey(param.getKey())
- .setValue(nullToEmpty(param.getValue())));
+ .setKey(parameter.getKey())
+ .setValue(nullToEmpty(parameter.getValue())));
}
return activeRuleResponse.build();
profilesResponse.put(profile.getKey(), profileResponse.build());
}
+ private enum ActiveRuleToKey implements Function<ActiveRule, ActiveRuleKey> {
+ INSTANCE;
+
+ @Override
+ public ActiveRuleKey apply(@Nonnull ActiveRule input) {
+ return input.key();
+ }
+ }
+
+ private enum ActiveRuleDtoToId implements Function<ActiveRuleDto, Integer> {
+ INSTANCE;
+
+ @Override
+ public Integer apply(@Nonnull ActiveRuleDto input) {
+ return input.getId();
+ }
+ }
+
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.server.rule.ws;
+
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.sonar.api.resources.Language;
+import org.sonar.api.resources.Languages;
+import org.sonar.api.server.debt.DebtRemediationFunction;
+import org.sonar.db.rule.RuleDto;
+import org.sonar.db.rule.RuleParamDto;
+import org.sonar.markdown.Markdown;
+import org.sonar.server.rule.index.RuleNormalizer;
+import org.sonar.server.rule.ws.SearchAction.SearchResult;
+import org.sonar.server.search.IndexField;
+import org.sonar.server.text.MacroInterpreter;
+import org.sonarqube.ws.Common;
+import org.sonarqube.ws.Rules;
+
+import static java.lang.String.format;
+import static org.sonar.api.utils.DateUtils.formatDateTime;
+
+/**
+ * Conversion of {@link org.sonar.db.rule.RuleDto} to {@link org.sonarqube.ws.Rules.Rule}
+ */
+public class RuleMapper {
+
+ private final Languages languages;
+ private final MacroInterpreter macroInterpreter;
+
+ public RuleMapper(final Languages languages, final MacroInterpreter macroInterpreter) {
+ this.languages = languages;
+ this.macroInterpreter = macroInterpreter;
+ }
+
+ public Rules.Rule toWsRule(RuleDto ruleDto, SearchResult result, Set<String> fieldsToReturn) {
+ Rules.Rule.Builder ruleResponse = Rules.Rule.newBuilder();
+
+ ruleResponse.setKey(ruleDto.getKey().toString());
+ setRepository(ruleResponse, ruleDto, fieldsToReturn);
+ setName(ruleResponse, ruleDto, fieldsToReturn);
+ setStatus(ruleResponse, ruleDto, fieldsToReturn);
+ setTags(ruleResponse, ruleDto, fieldsToReturn);
+ setSysTags(ruleResponse, ruleDto, fieldsToReturn);
+ setParams(ruleResponse, ruleDto, result, fieldsToReturn);
+ setCreatedAt(ruleResponse, ruleDto, fieldsToReturn);
+ setDescriptionFields(ruleResponse, ruleDto, fieldsToReturn);
+ setNotesFields(ruleResponse, ruleDto, fieldsToReturn);
+ setSeverity(ruleResponse, ruleDto, fieldsToReturn);
+ setInternalKey(ruleResponse, ruleDto, fieldsToReturn);
+ setLanguage(ruleResponse, ruleDto, fieldsToReturn);
+ setLanguageName(ruleResponse, ruleDto, fieldsToReturn);
+ setIsTemplate(ruleResponse, ruleDto, fieldsToReturn);
+ setTemplateKey(ruleResponse, ruleDto, result, fieldsToReturn);
+ setDebtRemediationFunctionFields(ruleResponse, ruleDto, fieldsToReturn);
+ setDefaultDebtRemediationFunctionFields(ruleResponse, ruleDto, fieldsToReturn);
+ setIsDebtOverloaded(ruleResponse, ruleDto, fieldsToReturn);
+ setEffortToFixDescription(ruleResponse, ruleDto, fieldsToReturn);
+
+ return ruleResponse.build();
+ }
+
+ private static void setRepository(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set<String> fieldsToReturn) {
+ if (shouldReturnField(fieldsToReturn, RuleNormalizer.RuleField.REPOSITORY)) {
+ ruleResponse.setRepo(ruleDto.getKey().repository());
+ }
+ }
+
+ private static void setEffortToFixDescription(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set<String> fieldsToReturn) {
+ if (shouldReturnField(fieldsToReturn, RuleNormalizer.RuleField.FIX_DESCRIPTION) && ruleDto.getEffortToFixDescription() != null) {
+ ruleResponse.setEffortToFixDescription(ruleDto.getEffortToFixDescription());
+ }
+ }
+
+ private static void setIsDebtOverloaded(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set<String> fieldsToReturn) {
+ if (shouldReturnField(fieldsToReturn, "debtOverloaded")) {
+ ruleResponse.setDebtOverloaded(ruleToOverloaded(ruleDto));
+ }
+ }
+
+ private static void setDefaultDebtRemediationFunctionFields(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set<String> fieldsToReturn) {
+ if (shouldReturnField(fieldsToReturn, "defaultDebtRemFn")) {
+ DebtRemediationFunction defaultDebtRemediationFunction = defaultDebtRemediationFunction(ruleDto);
+ if (defaultDebtRemediationFunction != null) {
+ if (defaultDebtRemediationFunction.coefficient() != null) {
+ ruleResponse.setDefaultDebtRemFnCoeff(defaultDebtRemediationFunction.coefficient());
+ }
+ if (defaultDebtRemediationFunction.offset() != null) {
+ ruleResponse.setDefaultDebtRemFnOffset(defaultDebtRemediationFunction.offset());
+ }
+ if (defaultDebtRemediationFunction.type() != null) {
+ ruleResponse.setDefaultDebtRemFnType(defaultDebtRemediationFunction.type().name());
+ }
+ }
+ }
+ }
+
+ private static void setDebtRemediationFunctionFields(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set<String> fieldsToReturn) {
+ if (shouldReturnField(fieldsToReturn, "debtRemFn")) {
+ DebtRemediationFunction debtRemediationFunction = debtRemediationFunction(ruleDto);
+ if (debtRemediationFunction != null) {
+ if (debtRemediationFunction.type() != null) {
+ ruleResponse.setDebtRemFnType(debtRemediationFunction.type().name());
+ }
+ if (debtRemediationFunction.coefficient() != null) {
+ ruleResponse.setDebtRemFnCoeff(debtRemediationFunction.coefficient());
+ }
+ if (debtRemediationFunction.offset() != null) {
+ ruleResponse.setDebtRemFnOffset(debtRemediationFunction.offset());
+ }
+ }
+ }
+ }
+
+ private static void setName(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set<String> fieldsToReturn) {
+ if (shouldReturnField(fieldsToReturn, RuleNormalizer.RuleField.NAME) && ruleDto.getName() != null) {
+ ruleResponse.setName(ruleDto.getName());
+ }
+ }
+
+ private static void setStatus(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set<String> fieldsToReturn) {
+ if (shouldReturnField(fieldsToReturn, RuleNormalizer.RuleField.STATUS) && ruleDto.getStatus() != null) {
+ ruleResponse.setStatus(Common.RuleStatus.valueOf(ruleDto.getStatus().toString()));
+ }
+ }
+
+ private static void setTags(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set<String> fieldsToReturn) {
+ if (shouldReturnField(fieldsToReturn, RuleNormalizer.RuleField.TAGS)) {
+ ruleResponse.getTagsBuilder().addAllTags(ruleDto.getTags());
+ }
+ }
+
+ private static void setSysTags(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set<String> fieldsToReturn) {
+ if (shouldReturnField(fieldsToReturn, RuleNormalizer.RuleField.SYSTEM_TAGS)) {
+ ruleResponse.getSysTagsBuilder().addAllSysTags(ruleDto.getSystemTags());
+ }
+ }
+
+ private static void setParams(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, SearchResult searchResult, Set<String> fieldsToReturn) {
+ if (shouldReturnField(fieldsToReturn, RuleNormalizer.RuleField.PARAMS)) {
+ List<RuleParamDto> ruleParameters = searchResult.getRuleParamsByRuleId().get(ruleDto.getId());
+ ruleResponse.getParamsBuilder().addAllParams(FluentIterable.from(ruleParameters)
+ .transform(RuleParamDtoToWsRuleParam.INSTANCE)
+ .toList());
+ }
+ }
+
+ private static void setCreatedAt(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set<String> fieldsToReturn) {
+ if (shouldReturnField(fieldsToReturn, RuleNormalizer.RuleField.CREATED_AT) && ruleDto.getCreatedAt() != null) {
+ ruleResponse.setCreatedAt(formatDateTime(ruleDto.getCreatedAt()));
+ }
+ }
+
+ private void setDescriptionFields(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set<String> fieldsToReturn) {
+ if (shouldReturnField(fieldsToReturn, RuleNormalizer.RuleField.HTML_DESCRIPTION)) {
+ String description = ruleDto.getDescription();
+ if (description != null) {
+ switch (ruleDto.getDescriptionFormat()) {
+ case MARKDOWN:
+ ruleResponse.setHtmlDesc(macroInterpreter.interpret(Markdown.convertToHtml(description)));
+ break;
+ case HTML:
+ ruleResponse.setHtmlDesc(macroInterpreter.interpret(description));
+ break;
+ default:
+ throw new IllegalStateException(format("Rule description format '%s' is unknown for key '%s'", ruleDto.getDescriptionFormat(), ruleDto.getKey().toString()));
+ }
+ }
+ }
+
+ if (shouldReturnField(fieldsToReturn, RuleNormalizer.RuleField.MARKDOWN_DESCRIPTION) && ruleDto.getDescription() != null) {
+ ruleResponse.setMdDesc(ruleDto.getDescription());
+ }
+ }
+
+ private void setNotesFields(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set<String> fieldsToReturn) {
+ if (shouldReturnField(fieldsToReturn, "htmlNote") && ruleDto.getNoteData() != null) {
+ ruleResponse.setHtmlNote(macroInterpreter.interpret(Markdown.convertToHtml(ruleDto.getNoteData())));
+ }
+ if (shouldReturnField(fieldsToReturn, "mdNote") && ruleDto.getNoteData() != null) {
+ ruleResponse.setMdNote(ruleDto.getNoteData());
+ }
+ if (shouldReturnField(fieldsToReturn, RuleNormalizer.RuleField.NOTE_LOGIN) && ruleDto.getNoteUserLogin() != null) {
+ ruleResponse.setNoteLogin(ruleDto.getNoteUserLogin());
+ }
+ }
+
+ private static void setSeverity(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set<String> fieldsToReturn) {
+ if (shouldReturnField(fieldsToReturn, RuleNormalizer.RuleField.SEVERITY) && ruleDto.getSeverityString() != null) {
+ ruleResponse.setSeverity(ruleDto.getSeverityString());
+ }
+ }
+
+ private static void setInternalKey(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set<String> fieldsToReturn) {
+ if (shouldReturnField(fieldsToReturn, RuleNormalizer.RuleField.INTERNAL_KEY) && ruleDto.getConfigKey() != null) {
+ ruleResponse.setInternalKey(ruleDto.getConfigKey());
+ }
+ }
+
+ private static void setLanguage(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set<String> fieldsToReturn) {
+ if (shouldReturnField(fieldsToReturn, RuleNormalizer.RuleField.LANGUAGE) && ruleDto.getLanguage() != null) {
+ ruleResponse.setLang(ruleDto.getLanguage());
+ }
+ }
+
+ private void setLanguageName(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set<String> fieldsToReturn) {
+ if (shouldReturnField(fieldsToReturn, "langName") && ruleDto.getLanguage() != null) {
+ String languageKey = ruleDto.getLanguage();
+ Language language = languages.get(languageKey);
+ ruleResponse.setLangName(language == null ? languageKey : language.getName());
+ }
+ }
+
+ private static void setIsTemplate(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set<String> fieldsToReturn) {
+ if (shouldReturnField(fieldsToReturn, RuleNormalizer.RuleField.IS_TEMPLATE)) {
+ ruleResponse.setIsTemplate(ruleDto.isTemplate());
+ }
+ }
+
+ private static void setTemplateKey(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, SearchResult result, Set<String> fieldsToReturn) {
+ if (shouldReturnField(fieldsToReturn, RuleNormalizer.RuleField.TEMPLATE_KEY) && ruleDto.getTemplateId() != null) {
+ RuleDto templateRule = result.getTemplateRulesByRuleId().get(ruleDto.getTemplateId());
+ if (templateRule != null) {
+ ruleResponse.setTemplateKey(templateRule.getKey().toString());
+ }
+ }
+ }
+
+ private static boolean shouldReturnField(Set<String> fieldsToReturn, IndexField field) {
+ return fieldsToReturn.isEmpty() || fieldsToReturn.contains(field.field());
+ }
+
+ private static boolean shouldReturnField(Set<String> fieldsToReturn, String fieldName) {
+ return fieldsToReturn.isEmpty() || fieldsToReturn.contains(fieldName);
+ }
+
+ private static boolean ruleToOverloaded(RuleDto rule) {
+ return rule.getRemediationFunction() != null;
+ }
+
+ private static DebtRemediationFunction defaultDebtRemediationFunction(final RuleDto ruleDto) {
+ final String function = ruleDto.getDefaultRemediationFunction();
+ if (function == null || function.isEmpty()) {
+ return null;
+ } else {
+ return new DebtRemediationFunction() {
+ @Override
+ public Type type() {
+ return Type.valueOf(function.toUpperCase());
+ }
+
+ @Override
+ public String coefficient() {
+ return ruleDto.getDefaultRemediationCoefficient();
+ }
+
+ @Override
+ public String offset() {
+ return ruleDto.getDefaultRemediationOffset();
+ }
+ };
+ }
+ }
+
+ private static DebtRemediationFunction debtRemediationFunction(final RuleDto ruleDto) {
+ final String function = ruleDto.getRemediationFunction();
+ if (function == null || function.isEmpty()) {
+ return null;
+ } else {
+ return new DebtRemediationFunction() {
+ @Override
+ public Type type() {
+ return Type.valueOf(function.toUpperCase());
+ }
+
+ @Override
+ public String coefficient() {
+ return ruleDto.getRemediationCoefficient();
+ }
+
+ @Override
+ public String offset() {
+ return ruleDto.getRemediationOffset();
+ }
+ };
+ }
+ }
+
+ private enum RuleParamDtoToWsRuleParam implements Function<RuleParamDto, Rules.Rule.Param> {
+ INSTANCE;
+
+ @Override
+ public Rules.Rule.Param apply(@Nonnull RuleParamDto param) {
+ Rules.Rule.Param.Builder paramResponse = Rules.Rule.Param.newBuilder();
+ paramResponse.setKey(param.getName());
+ if (param.getDescription() != null) {
+ paramResponse.setHtmlDesc(Markdown.convertToHtml(param.getDescription()));
+ }
+ if (param.getDefaultValue() != null) {
+ paramResponse.setDefaultValue(param.getDefaultValue());
+ }
+ if (param.getType() != null) {
+ paramResponse.setType(param.getType());
+ }
+
+ return paramResponse.build();
+ }
+ }
+}
public Rules.Rule buildRuleResponse(Rule ruleDoc, @Nullable QueryContext queryContext) {
Rules.Rule.Builder ruleResponse = Rules.Rule.newBuilder();
-
- RuleMappingContext context = new RuleMappingContext();
Set<String> fieldsToReturn = fieldsToReturn(queryContext);
ruleResponse.setKey(ruleDoc.key().toString());
*/
package org.sonar.server.rule.ws;
+import com.google.common.base.Function;
+import com.google.common.base.Predicates;
+import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.io.Resources;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+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 javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
-import org.sonar.api.server.debt.DebtCharacteristic;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.WebService.Param;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
import org.sonar.db.qualityprofile.QualityProfileDto;
+import org.sonar.db.rule.RuleDto;
+import org.sonar.db.rule.RuleParamDto;
import org.sonar.server.qualityprofile.ActiveRule;
import org.sonar.server.rule.Rule;
-import org.sonar.server.rule.RuleService;
import org.sonar.server.rule.index.RuleIndex;
import org.sonar.server.rule.index.RuleNormalizer;
import org.sonar.server.rule.index.RuleQuery;
import org.sonar.server.search.FacetValue;
+import org.sonar.server.search.Facets;
import org.sonar.server.search.QueryContext;
import org.sonar.server.search.Result;
import org.sonar.server.search.ws.SearchOptions;
import org.sonarqube.ws.Common;
import org.sonarqube.ws.Rules.SearchResponse;
+import static com.google.common.collect.FluentIterable.from;
import static org.sonar.server.search.QueryContext.MAX_LIMIT;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
private static final Collection<String> DEFAULT_FACETS = ImmutableSet.of(PARAM_LANGUAGES, PARAM_REPOSITORIES, "tags");
- private final RuleService ruleService;
+ private final UserSession userSession;
+ private final DbClient dbClient;
+ private final RuleIndex ruleIndex;
private final ActiveRuleCompleter activeRuleCompleter;
private final RuleMapping mapping;
- private final UserSession userSession;
+ private final RuleMapper mapper;
- public SearchAction(RuleService service, ActiveRuleCompleter activeRuleCompleter, RuleMapping mapping, UserSession userSession) {
+ public SearchAction(RuleIndex ruleIndex, ActiveRuleCompleter activeRuleCompleter, RuleMapping mapping, UserSession userSession, DbClient dbClient, RuleMapper mapper) {
this.userSession = userSession;
- this.ruleService = service;
+ this.ruleIndex = ruleIndex;
this.activeRuleCompleter = activeRuleCompleter;
this.mapping = mapping;
+ this.dbClient = dbClient;
+ this.mapper = mapper;
}
@Override
@Override
public void handle(Request request, Response response) throws Exception {
- QueryContext context = getQueryContext(request);
- RuleQuery query = doQuery(request);
- Result<Rule> result = doSearch(query, context);
-
- SearchResponse responseBuilder = buildResponse(request, context, result);
- writeProtobuf(responseBuilder, request, response);
+ DbSession dbSession = dbClient.openSession(false);
+ try {
+ QueryContext context = getQueryContext(request);
+ RuleQuery query = doQuery(request);
+ SearchResult searchResult = doSearch(dbSession, query, context);
+ SearchResponse responseBuilder = buildResponse(dbSession, request, context, searchResult);
+ writeProtobuf(responseBuilder, request, response);
+ } finally {
+ dbClient.closeSession(dbSession);
+ }
}
- private SearchResponse buildResponse(Request request, QueryContext context, Result<Rule> result) {
+ private SearchResponse buildResponse(DbSession dbSession, Request request, QueryContext context, SearchResult result) {
SearchResponse.Builder responseBuilder = SearchResponse.newBuilder();
writeStatistics(responseBuilder, result, context);
- doContextResponse(request, result, responseBuilder);
+ doContextResponse(dbSession, request, result, responseBuilder);
if (context.isFacet()) {
writeFacets(responseBuilder, request, context, result);
}
return responseBuilder.build();
}
- protected void writeStatistics(SearchResponse.Builder response, Result searchResult, QueryContext context) {
- response.setTotal(searchResult.getTotal());
+ protected void writeStatistics(SearchResponse.Builder response, SearchResult searchResult, QueryContext context) {
+ response.setTotal(searchResult.total);
response.setP(context.getPage());
response.setPs(context.getLimit());
}
RuleIndex.FACET_SEVERITIES,
RuleIndex.FACET_ACTIVE_SEVERITIES,
RuleIndex.FACET_STATUSES,
- RuleIndex.FACET_OLD_DEFAULT
- );
+ RuleIndex.FACET_OLD_DEFAULT);
}
/**
return query;
}
- private void writeRules(SearchResponse.Builder response, Result<Rule> result, QueryContext context) {
- for (Rule rule : result.getHits()) {
- response.addRules(mapping.buildRuleResponse(rule, context));
+ private void writeRules(SearchResponse.Builder response, SearchResult result, QueryContext context) {
+ for (RuleDto rule : result.rules) {
+ response.addRules(mapper.toWsRule(rule, result, context.getFieldsToReturn()));
}
}
return context;
}
- protected Result<Rule> doSearch(RuleQuery query, QueryContext context) {
- return ruleService.search(query, context);
+ protected SearchResult doSearch(DbSession dbSession, RuleQuery query, QueryContext context) {
+ Result<Rule> result = ruleIndex.search(query, context);
+ List<RuleKey> ruleKeys = from(result.getHits()).transform(RuleToRuleKey.INSTANCE).toList();
+ // rule order is managed by ES
+ Map<RuleKey, RuleDto> rulesByRuleKey = Maps.uniqueIndex(
+ dbClient.ruleDao().selectByKeys(dbSession, ruleKeys),
+ new Function<RuleDto, RuleKey>() {
+ @Override
+ public RuleKey apply(@Nonnull RuleDto input) {
+ return input.getKey();
+ }
+ });
+ List<RuleDto> rules = new ArrayList<>();
+ for (RuleKey ruleKey : ruleKeys) {
+ RuleDto rule = rulesByRuleKey.get(ruleKey);
+ if (rule != null) {
+ rules.add(rule);
+ }
+ }
+ List<Integer> ruleIds = from(rules).transform(RuleDtoToId.INSTANCE).toList();
+ List<Integer> templateRuleIds = from(rules)
+ .transform(RuleDtoToTemplateId.INSTANCE)
+ .filter(Predicates.<Integer>notNull())
+ .toList();
+ List<RuleDto> templateRules = dbClient.ruleDao().selectByIds(dbSession, templateRuleIds);
+ List<RuleParamDto> ruleParamDtos = dbClient.ruleDao().selectRuleParamsByRuleIds(dbSession, ruleIds);
+ return new SearchResult(result)
+ .setRules(rules)
+ .setRuleParams(ruleParamDtos)
+ .setTemplateRules(templateRules);
}
protected RuleQuery doQuery(Request request) {
- RuleQuery plainQuery = createRuleQuery(ruleService.newRuleQuery(), request);
+ RuleQuery plainQuery = createRuleQuery(new RuleQuery(), request);
String qProfileKey = request.param(PARAM_QPROFILE);
if (qProfileKey != null) {
return plainQuery;
}
- protected void doContextResponse(Request request, Result<Rule> result, SearchResponse.Builder response) {
+ protected void doContextResponse(DbSession dbSession, Request request, SearchResult result, SearchResponse.Builder response) {
// TODO Get rid of this horrible hack: fields on request are not the same as fields for ES search ! 2/2
QueryContext contextForResponse = loadCommonContext(request);
writeRules(response, result, contextForResponse);
if (contextForResponse.getFieldsToReturn().contains("actives")) {
- activeRuleCompleter.completeSearch(doQuery(request), result.getHits(), response);
+ activeRuleCompleter.completeSearch(dbSession, doQuery(request), result.rules, response);
}
}
return builder.add("actives").build();
}
- protected void writeFacets(SearchResponse.Builder response, Request request, QueryContext context, Result<?> results) {
+ protected void writeFacets(SearchResponse.Builder response, Request request, QueryContext context, SearchResult results) {
addMandatoryFacetValues(results, RuleIndex.FACET_LANGUAGES, request.paramAsStrings(PARAM_LANGUAGES));
addMandatoryFacetValues(results, RuleIndex.FACET_REPOSITORIES, request.paramAsStrings(PARAM_REPOSITORIES));
addMandatoryFacetValues(results, RuleIndex.FACET_STATUSES, RuleIndex.ALL_STATUSES_EXCEPT_REMOVED);
Common.FacetValue.Builder value = Common.FacetValue.newBuilder();
for (String facetName : context.facets()) {
facet.clear().setProperty(facetName);
- if (results.getFacets().containsKey(facetName)) {
+ if (results.facets.getFacets().containsKey(facetName)) {
Set<String> itemsFromFacets = Sets.newHashSet();
- for (FacetValue facetValue : results.getFacets().get(facetName)) {
+ for (FacetValue facetValue : results.facets.getFacets().get(facetName)) {
itemsFromFacets.add(facetValue.getKey());
facet.addValues(value
.clear()
}
}
- protected void addMandatoryFacetValues(Result<?> results, String facetName, @Nullable List<String> mandatoryValues) {
- Collection<FacetValue> facetValues = results.getFacetValues(facetName);
+ protected void addMandatoryFacetValues(SearchResult results, String facetName, @Nullable List<String> mandatoryValues) {
+ Collection<FacetValue> facetValues = results.facets.getFacetValues(facetName);
if (facetValues != null) {
Map<String, Long> valuesByItem = Maps.newHashMap();
for (FacetValue value : facetValues) {
}
}
}
+
+ static class SearchResult {
+ private List<RuleDto> rules;
+ private final ListMultimap<Integer, RuleParamDto> ruleParamsByRuleId;
+ private final Map<Integer, RuleDto> templateRulesByRuleId;
+ private final long total;
+ private final Facets facets;
+
+ public SearchResult(Result<Rule> result) {
+ this.rules = new ArrayList<>();
+ this.ruleParamsByRuleId = ArrayListMultimap.create();
+ this.templateRulesByRuleId = new HashMap<>();
+ this.total = result.getTotal();
+ this.facets = result.getFacetsObject();
+ }
+
+ public List<RuleDto> getRules() {
+ return rules;
+ }
+
+ public SearchResult setRules(List<RuleDto> rules) {
+ this.rules = rules;
+ return this;
+ }
+
+ public ListMultimap<Integer, RuleParamDto> getRuleParamsByRuleId() {
+ return ruleParamsByRuleId;
+ }
+
+ public SearchResult setRuleParams(List<RuleParamDto> ruleParams) {
+ ruleParamsByRuleId.clear();
+ for (RuleParamDto ruleParam : ruleParams) {
+ ruleParamsByRuleId.put(ruleParam.getRuleId(), ruleParam);
+ }
+ return this;
+ }
+
+ public Map<Integer, RuleDto> getTemplateRulesByRuleId() {
+ return templateRulesByRuleId;
+ }
+
+ public SearchResult setTemplateRules(List<RuleDto> templateRules) {
+ templateRulesByRuleId.clear();
+ for (RuleDto templateRule : templateRules) {
+ templateRulesByRuleId.put(templateRule.getId(), templateRule);
+ }
+ return this;
+ }
+
+ public long getTotal() {
+ return total;
+ }
+
+ public Facets getFacets() {
+ return facets;
+ }
+ }
+
+ private enum RuleDtoToId implements Function<RuleDto, Integer> {
+ INSTANCE;
+
+ @Override
+ public Integer apply(@Nonnull RuleDto input) {
+ return input.getId();
+ }
+ }
+
+ private enum RuleDtoToTemplateId implements Function<RuleDto, Integer> {
+ INSTANCE;
+
+ @Override
+ public Integer apply(@Nonnull RuleDto input) {
+ return input.getTemplateId();
+ }
+ }
+
+ private enum RuleToRuleKey implements Function<Rule, RuleKey> {
+ INSTANCE;
+
+ @Override
+ public RuleKey apply(@Nonnull Rule input) {
+ return input.key();
+ }
+ }
}
import java.util.List;
import java.util.Map;
-class Facets {
+public class Facets {
private static final Logger LOGGER = Loggers.get(Facets.class);
return this.facets.getFacets();
}
+ public Facets getFacetsObject() {
+ return this.facets;
+ }
+
@CheckForNull
public Collection<FacetValue> getFacetValues(String facetName) {
return this.facets.getFacetValues(facetName);
package org.sonar.server.rule.ws;
import com.google.common.collect.ImmutableSet;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsTester;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.Date;
-
import static org.assertj.core.api.Assertions.assertThat;
public class SearchActionMediumTest {
@Test
public void return_lang_key_field_when_language_name_is_not_available() throws Exception {
- ruleDao.insert(dbSession, RuleTesting.newDto(RuleKey.of("other", "rule"))).setLanguage("unknown");
+ ruleDao.insert(dbSession, RuleTesting.newDto(RuleKey.of("other", "rule")).setLanguage("unknown"));
dbSession.commit();
WsTester.TestRequest request = tester.wsTester().newGetRequest(API_ENDPOINT, API_SEARCH_METHOD).setParam(WebService.Param.FIELDS, "langName");
.setDefaultRemediationOffset("15min")
.setRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.name())
.setRemediationCoefficient("2h")
- .setRemediationOffset("25min")
- );
+ .setRemediationOffset("25min"));
dbSession.commit();
WsTester.TestRequest request = tester.wsTester().newGetRequest(API_ENDPOINT, API_SEARCH_METHOD);
.setDefaultRemediationOffset("15min")
.setRemediationFunction(DebtRemediationFunction.Type.CONSTANT_ISSUE.name())
.setRemediationCoefficient(null)
- .setRemediationOffset("5min")
- );
+ .setRemediationOffset("5min"));
dbSession.commit();
WsTester.TestRequest request = tester.wsTester().newGetRequest(API_ENDPOINT, API_SEARCH_METHOD);
.setDefaultRemediationOffset("15min")
.setRemediationFunction(DebtRemediationFunction.Type.LINEAR.name())
.setRemediationCoefficient("1h")
- .setRemediationOffset(null)
- );
+ .setRemediationOffset(null));
dbSession.commit();
WsTester.TestRequest request = tester.wsTester().newGetRequest(API_ENDPOINT, API_SEARCH_METHOD);
public void search_custom_rules_from_template_key() throws Exception {
RuleDto templateRule = RuleTesting.newXooX1().setIsTemplate(true);
ruleDao.insert(dbSession, templateRule);
- ruleDao.insert(dbSession, RuleTesting.newXooX2()).setTemplateId(templateRule.getId());
+ ruleDao.insert(dbSession, RuleTesting.newXooX2().setTemplateId(templateRule.getId()));
dbSession.commit();
WsTester.TestRequest request = tester.wsTester().newGetRequest(API_ENDPOINT, API_SEARCH_METHOD);
*
* @since 4.4
*/
-public class ActiveRuleKey implements Serializable {
+public class ActiveRuleKey implements Serializable, Comparable<ActiveRuleKey> {
private final String qualityProfileKey;
private final RuleKey ruleKey;
public String toString() {
return String.format("%s:%s", qualityProfileKey, ruleKey.toString());
}
+
+ @Override
+ public int compareTo(ActiveRuleKey o) {
+ int compareQualityProfileKey = this.qualityProfileKey.compareTo(o.qualityProfileKey);
+ if (compareQualityProfileKey == 0) {
+ return this.ruleKey.compareTo(o.ruleKey);
+ }
+ return compareQualityProfileKey;
+ }
}
@CheckForNull
ActiveRuleDto selectById(Integer id);
+ ActiveRuleDto selectByKey(@Param("profileKey") String profileKey, @Param("repository") String repository, @Param("rule") String rule);
+
+ List<ActiveRuleDto> selectByKeys(@Param("keys") List<ActiveRuleKey> keys);
+
List<ActiveRuleDto> selectByRuleId(int ruleId);
List<ActiveRuleDto> selectByProfileKey(String key);
List<ActiveRuleParamDto> selectParamsByActiveRuleId(int activeRuleId);
- List<ActiveRuleParamDto> selectParamsByProfileKey(String profileKey);
+ List<ActiveRuleParamDto> selectParamsByActiveRuleIds(@Param("ids") List<Integer> ids);
- ActiveRuleDto selectByKey(@Param("profileKey") String profileKey,
- @Param("repository") String repository, @Param("rule") String rule);
+ List<ActiveRuleParamDto> selectParamsByProfileKey(String profileKey);
List<ActiveRuleParamDto> selectAllParams();
List<ActiveRuleDto> selectAfterDate(@Nullable Timestamp date);
-
}
import com.google.common.base.Optional;
import java.util.List;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import org.apache.ibatis.session.ResultHandler;
import org.sonar.api.rule.RuleKey;
import org.sonar.db.Dao;
+import org.sonar.db.DatabaseUtils;
import org.sonar.db.DbSession;
import org.sonar.db.RowNotFoundException;
+import static java.util.Collections.emptyList;
import static org.sonar.db.DatabaseUtils.executeLargeInputs;
public class RuleDao implements Dao {
return Optional.fromNullable(mapper(session).selectById(id));
}
+ public List<RuleDto> selectByIds(final DbSession dbSession, List<Integer> ids) {
+ if (ids.isEmpty()) {
+ return emptyList();
+ }
+ return DatabaseUtils.executeLargeInputs(ids, new Function<List<Integer>, List<RuleDto>>() {
+ @Override
+ public List<RuleDto> apply(@Nullable List<Integer> input) {
+ return mapper(dbSession).selectByIds(input);
+ }
+ });
+ }
+
/**
* Select rules by keys, whatever their status. Returns an empty list
* if the list of {@code keys} is empty, without any db round trip.
return mapper(session).selectAll();
}
+ public List<RuleParamDto> selectRuleParamsByRuleIds(final DbSession dbSession, List<Integer> ruleIds) {
+ if (ruleIds.isEmpty()) {
+ return emptyList();
+ }
+ return DatabaseUtils.executeLargeInputs(ruleIds, new Function<List<Integer>, List<RuleParamDto>>() {
+ @Override
+ public List<RuleParamDto> apply(@Nonnull List<Integer> input) {
+ return mapper(dbSession).selectParamsByRuleIds(input);
+ }
+ });
+ }
+
public void insert(DbSession session, RuleDto dto) {
mapper(session).insert(dto);
}
RuleDto selectById(long id);
+ List<RuleDto> selectByIds(@Param("ruleIds") List<Integer> ids);
+
RuleDto selectByKey(RuleKey ruleKey);
List<RuleDto> selectByKeys(@Param("ruleKeys") List<RuleKey> keys);
AND r.plugin_name = #{repository}
</select>
+ <select id="selectByKeys" parameterType="map" resultType="ActiveRule">
+ SELECT
+ <include refid="activeRuleKeyColumns"/>
+ FROM active_rules a
+ <include refid="activeRuleKeyJoin"/>
+ WHERE
+ <foreach collection="keys" item="key" open="(" separator=" or " close=")">
+ (qp.kee = #{key.qProfile()}
+ AND r.plugin_rule_key = #{key.ruleKey().rule()}
+ AND r.plugin_name = #{key.ruleKey().repository()})
+ </foreach>
+ </select>
+
<select id="selectByProfileKey" parameterType="string" resultType="ActiveRule">
SELECT
<include refid="activeRuleKeyColumns"/>
<include refid="activeRuleParamColumns"/>
from active_rule_parameters p
<where>
- (<foreach collection="list" item="id" open="(" separator=" or " close=")">
- p.active_rule_id=#{id}
- </foreach>)
+ <foreach collection="ids" item="id" open="(" separator=" or " close=")">
+ p.active_rule_id=#{id}
+ </foreach>
</where>
</select>
from rules r WHERE r.id=#{id}
</select>
+ <select id="selectByIds" parameterType="Integer" resultType="Rule">
+ select
+ <include refid="selectColumns"/>
+ from rules r WHERE r.id in
+ <foreach collection="ruleIds" index="index" item="id" open="(" separator="," close=")">
+ #{id}
+ </foreach>
+ </select>
+
<select id="selectByKey" parameterType="map" resultType="Rule">
SELECT
<include refid="selectColumns"/>