Browse Source

SONAR-7780 add MeasureQuery.analysisUuid

required by Governance
tags/6.0-RC1
Sébastien Lesaint 8 years ago
parent
commit
65e2080c62

+ 27
- 0
sonar-db/src/main/java/org/sonar/db/measure/MeasureDao.java View File

@@ -27,6 +27,7 @@ import java.util.List;
import java.util.Optional;
import org.sonar.db.Dao;
import org.sonar.db.DbSession;
import org.sonar.db.version.Select;

import static org.sonar.db.DatabaseUtils.executeLargeInputs;

@@ -37,6 +38,19 @@ public class MeasureDao implements Dao {
return Optional.ofNullable(Iterables.getOnlyElement(measures, null));
}

/**
* Selects the measures of either the last analysis (when {@link MeasureQuery#analysisUuid} is {@code null}) or of the
* specified analysis (given by {@link MeasureQuery#analysisUuid}) for the component UUIDs specified in
* {@link MeasureQuery#componentUuids}.
* <p>
* In addition, this method returns measures which are not associated to any developer, unless one is specified in
* {@link MeasureQuery#personId}.
* </p>
* <p>
* Returned measure can optionally be filtered metric (either by specifying {@link MeasureQuery#metricIds}
* or {@link MeasureQuery#metricKeys}).
* </p>
*/
public List<MeasureDto> selectByQuery(DbSession dbSession, MeasureQuery query) {
if (query.returnsEmpty()) {
return Collections.emptyList();
@@ -50,6 +64,19 @@ public class MeasureDao implements Dao {
});
}

public List<MeasureDto> selectByQuery(DbSession dbSession, MeasureQuery query, Select.RowHandler rowHandler) {
if (query.returnsEmpty()) {
return Collections.emptyList();
}
if (query.getComponentUuids() == null) {
return mapper(dbSession).selectByQuery(query, rowHandler);
}
return executeLargeInputs(query.getComponentUuids(), componentUuids -> {
MeasureQuery pageQuery = MeasureQuery.copyWithSubsetOfComponentUuids(query, componentUuids);
return mapper(dbSession).selectByQuery(pageQuery, rowHandler);
});
}

public List<PastMeasureDto> selectPastMeasures(DbSession dbSession,
String componentUuid,
String analysisUuid,

+ 3
- 0
sonar-db/src/main/java/org/sonar/db/measure/MeasureMapper.java View File

@@ -21,11 +21,14 @@ package org.sonar.db.measure;

import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.sonar.db.version.Select;

public interface MeasureMapper {

List<MeasureDto> selectByQuery(@Param("query") MeasureQuery query);

List<MeasureDto> selectByQuery(@Param("query") MeasureQuery query, Select.RowHandler rowHandler);

List<PastMeasureDto> selectPastMeasures(@Param("componentUuid") String componentUuid, @Param("analysisUuid") String analysisUuid, @Param("metricIds") List<Integer> metricIds);

void insert(MeasureDto measureDto);

+ 39
- 23
sonar-db/src/main/java/org/sonar/db/measure/MeasureQuery.java View File

@@ -21,56 +21,51 @@ package org.sonar.db.measure;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

import static com.google.common.base.Preconditions.checkState;
import static java.util.Collections.singleton;
import static java.util.Collections.singletonList;
import static java.util.Objects.requireNonNull;

public class MeasureQuery {

@CheckForNull
private final String analysisUuid;

private final List<String> componentUuids;

@CheckForNull
private final Collection<Integer> metricIds;

@CheckForNull
private final Collection<String> metricKeys;

@CheckForNull
private final Long personId;

private MeasureQuery(Builder builder) {
this(builder.componentUuids, builder.analysisUuid, builder.metricIds, builder.metricKeys, builder.personId);
this(builder.analysisUuid, builder.componentUuids, builder.metricIds, builder.metricKeys, builder.personId);
}

private MeasureQuery(List<String> componentUuids,
@Nullable String analysisUuid,
private MeasureQuery(@Nullable String analysisUuid,
List<String> componentUuids,
@Nullable Collection<Integer> metricIds,
@Nullable Collection<String> metricKeys,
@Nullable Long personId) {
checkState(componentUuids != null, "Component UUIDs must be set");
requireNonNull(componentUuids, "Component UUIDs must be set");
checkState(metricIds == null || metricKeys == null, "Metric IDs and keys must not be set both");
this.componentUuids = componentUuids;
this.analysisUuid = analysisUuid;
this.componentUuids = componentUuids;
this.metricIds = metricIds;
this.metricKeys = metricKeys;
this.personId = personId;
}

public List<String> getComponentUuids() {
return componentUuids;
}

@CheckForNull
public String getAnalysisUuid() {
return analysisUuid;
}

public List<String> getComponentUuids() {
return componentUuids;
}

@CheckForNull
public Collection<Integer> getMetricIds() {
return metricIds;
@@ -92,17 +87,38 @@ public class MeasureQuery {
|| (metricKeys != null && metricKeys.isEmpty());
}

@Override
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
MeasureQuery that = (MeasureQuery) o;
return Objects.equals(analysisUuid, that.analysisUuid) &&
Objects.equals(componentUuids, that.componentUuids) &&
Objects.equals(metricIds, that.metricIds) &&
Objects.equals(metricKeys, that.metricKeys) &&
Objects.equals(personId, that.personId);
}

@Override
public int hashCode() {
return Objects.hash(analysisUuid, componentUuids, metricIds, metricKeys, personId);
}

public static Builder builder() {
return new Builder();
}

static MeasureQuery copyWithSubsetOfComponentUuids(MeasureQuery query, List<String> componentUuids) {
return new MeasureQuery(componentUuids, query.analysisUuid, query.metricIds, query.metricKeys, query.personId);
return new MeasureQuery(query.analysisUuid, componentUuids, query.metricIds, query.metricKeys, query.personId);
}

public static final class Builder {
private List<String> componentUuids;
private String analysisUuid;
private List<String> componentUuids;
private Collection<Integer> metricIds;
private Collection<String> metricKeys;
private Long personId;
@@ -111,6 +127,11 @@ public class MeasureQuery {
// see MeasureQuery#builder()
}

public Builder setAnalysisUuid(String analysisUuid) {
this.analysisUuid = analysisUuid;
return this;
}

public Builder setComponentUuids(List<String> componentUuids) {
this.componentUuids = componentUuids;
return this;
@@ -121,11 +142,6 @@ public class MeasureQuery {
return this;
}

public Builder setAnalysisUuid(String s) {
this.analysisUuid = s;
return this;
}

/**
* All the measures are returned if parameter is {@code null}.
*/

+ 36
- 30
sonar-db/src/main/resources/org/sonar/db/measure/MeasureMapper.xml View File

@@ -26,37 +26,43 @@
</sql>

<select id="selectByQuery" parameterType="map" resultType="Measure">
select <include refid="measureColumns"/>
from project_measures pm
inner join snapshots analysis on analysis.uuid = pm.analysis_uuid
select
<include refid="measureColumns"/>
from
project_measures pm
inner join snapshots analysis on analysis.uuid = pm.analysis_uuid
<if test="query.getMetricKeys() != null">
inner join metrics m on m.id = pm.metric_id
</if>
where
pm.component_uuid in
<foreach item="componentUuid" collection="query.getComponentUuids()" open="(" separator="," close=")">
#{componentUuid}
</foreach>
<choose>
<when test="query.getAnalysisUuid() != null">
and analysis.uuid in <foreach item="analysisUuid" collection="query.getAnalysisUuid()" open="(" separator="," close=")">#{analysisUuid}</foreach>
</when>
<otherwise>
and analysis.islast=${_true}
</otherwise>
</choose>
<if test="query.getMetricIds() != null">
and pm.metric_id in
<foreach item="metricId" collection="query.getMetricIds()" open="(" separator="," close=")">#{metricId}</foreach>
</if>
<if test="query.getMetricKeys() != null">
and pm.metric_id in (select id from metrics where name in <foreach item="metricKey" collection="query.getMetricKeys()" open="(" separator="," close=")">#{metricKey}</foreach>)
</if>
<choose>
<when test="query.getPersonId() != null">
and person_id = #{query.personId}
</when>
<otherwise>
and person_id is null
</otherwise>
</choose>
<if test="query.getAnalysisUuid() == null">
analysis.islast=${_true}
</if>
<if test="query.getAnalysisUuid() != null">
analysis.uuid = #{query.analysisUuid}
</if>
and pm.component_uuid in
<foreach item="componentUuid" collection="query.getComponentUuids()" open="(" separator="," close=")">
#{componentUuid}
</foreach>
<if test="query.getMetricIds() != null">
and pm.metric_id in
<foreach item="metricId" collection="query.getMetricIds()" open="(" separator="," close=")">#{metricId}</foreach>
</if>
<if test="query.getMetricKeys() != null">
and m.name in
<foreach item="metricKey" collection="query.getMetricKeys()" open="(" separator="," close=")">
#{metricKey}
</foreach>
</if>
<choose>
<when test="query.getPersonId() != null">
and person_id = #{query.personId}
</when>
<otherwise>
and person_id is null
</otherwise>
</choose>
</select>

<select id="selectPastMeasures" parameterType="map" resultType="org.sonar.db.measure.PastMeasureDto">

+ 53
- 22
sonar-db/src/test/java/org/sonar/db/measure/MeasureDaoTest.java View File

@@ -38,6 +38,8 @@ public class MeasureDaoTest {
private static final int COMPLEXITY_METRIC_ID = 11;
private static final int NCLOC_METRIC_ID = 12;
private static final long A_PERSON_ID = 444L;
public static final String LAST_ANALYSIS_UUID = "A1";
public static final String OTHER_ANALYSIS_UUID = "A2";

@Rule
public ExpectedException expectedException = ExpectedException.none();
@@ -49,10 +51,10 @@ public class MeasureDaoTest {

@Test
public void test_inserted_and_selected_columns() {
insertAnalysis("A1", true);
insertAnalysis(LAST_ANALYSIS_UUID, true);

MeasureDto inserted = new MeasureDto()
.setAnalysisUuid("A1")
.setAnalysisUuid(LAST_ANALYSIS_UUID)
.setMetricId(2)
.setDeveloperId(3L)
.setComponentUuid("C4")
@@ -90,47 +92,76 @@ public class MeasureDaoTest {

@Test
public void selectByQuery() {
insertAnalysis("A1", false);
insertAnalysis("A2", true);
insertAnalysis(LAST_ANALYSIS_UUID, true);
insertAnalysis(OTHER_ANALYSIS_UUID, false);
// component C1
insertMeasure("M1", "A1", "C1", NCLOC_METRIC_ID);
insertMeasure("M2", "A2", "C1", NCLOC_METRIC_ID);
insertMeasure("M3", "A2", "C1", COVERAGE_METRIC_ID);
insertMeasureOnPerson("M4", "A2", "C1", NCLOC_METRIC_ID, A_PERSON_ID);
insertMeasure("M1", OTHER_ANALYSIS_UUID, "C1", NCLOC_METRIC_ID);
insertMeasure("M2", LAST_ANALYSIS_UUID, "C1", NCLOC_METRIC_ID);
insertMeasure("M3", LAST_ANALYSIS_UUID, "C1", COVERAGE_METRIC_ID);
insertMeasureOnPerson("M4", LAST_ANALYSIS_UUID, "C1", NCLOC_METRIC_ID, A_PERSON_ID);
insertMeasureOnPerson("M5", OTHER_ANALYSIS_UUID, "C1", NCLOC_METRIC_ID, 123L);
// component C2
insertMeasure("M5", "A2", "C2", NCLOC_METRIC_ID);
insertMeasure("M6", LAST_ANALYSIS_UUID, "C2", NCLOC_METRIC_ID);
db.commit();

verifyZeroMeasures(MeasureQuery.builder().setComponentUuids(emptyList()));
verifyZeroMeasures(MeasureQuery.builder().setComponentUuid("MISSING_COMPONENT"));

// all measures of component C1
// all measures of component C1 of last analysis
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1"), "M2", "M3");
// all measures of component C1 of non last analysis
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(OTHER_ANALYSIS_UUID), "M1");
// all measures of component C1 of last analysis by UUID
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(LAST_ANALYSIS_UUID), "M2", "M3");

// ncloc measure of component C1
// ncloc measure of component C1 of last analysis
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setMetricId(NCLOC_METRIC_ID), "M2");
// ncloc measure of component C1 of non last analysis
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(OTHER_ANALYSIS_UUID).setMetricId(NCLOC_METRIC_ID), "M1");
// ncloc measure of component C1 of last analysis by UUID
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(LAST_ANALYSIS_UUID).setMetricId(NCLOC_METRIC_ID), "M2");

// multiple measures of component C1
// multiple measures of component C1 of last analysis
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setMetricIds(asList(NCLOC_METRIC_ID, COVERAGE_METRIC_ID)), "M2", "M3");
// multiple measures of component C1 of non last analysis
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(OTHER_ANALYSIS_UUID).setMetricIds(asList(NCLOC_METRIC_ID, COVERAGE_METRIC_ID)), "M1");
// multiple measures of component C1 of last analysis by UUID
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(LAST_ANALYSIS_UUID).setMetricIds(asList(NCLOC_METRIC_ID, COVERAGE_METRIC_ID)), "M2", "M3");

// missing measure of component C1
// missing measure of component C1 of last analysis
verifyZeroMeasures(MeasureQuery.builder().setComponentUuid("C1").setMetricId(COMPLEXITY_METRIC_ID));

// ncloc measures of components C1, C2 and C3 (which does not exist)
verifyMeasures(MeasureQuery.builder().setComponentUuids(asList("C1", "C2", "C3")), "M2", "M3", "M5");

// measures of missing developer of component C1
// missing measure of component C1 of non last analysis
verifyZeroMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(OTHER_ANALYSIS_UUID).setMetricId(COMPLEXITY_METRIC_ID));
// missing measure of component C1 of last analysis by UUID
verifyZeroMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(LAST_ANALYSIS_UUID).setMetricId(COMPLEXITY_METRIC_ID));

// ncloc measures of components C1, C2 and C3 (which does not exist) of last analysis
verifyMeasures(MeasureQuery.builder().setComponentUuids(asList("C1", "C2", "C3")), "M2", "M3", "M6");
// ncloc measures of components C1, C2 and C3 (which does not exist) of non last analysis
verifyMeasures(MeasureQuery.builder().setComponentUuids(asList("C1", "C2", "C3")).setAnalysisUuid(OTHER_ANALYSIS_UUID), "M1");
// ncloc measures of components C1, C2 and C3 (which does not exist) of last analysis by UUID
verifyMeasures(MeasureQuery.builder().setComponentUuids(asList("C1", "C2", "C3")).setAnalysisUuid(LAST_ANALYSIS_UUID), "M2", "M3", "M6");

// measures of missing developer of component C1 of last analysis
verifyZeroMeasures(MeasureQuery.builder().setComponentUuid("C1").setPersonId(123L));
// measures of missing developer of component C1 of non last analysis
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(OTHER_ANALYSIS_UUID).setPersonId(123L), "M5");
// measures of missing developer of component C1 of last analysis by UUID
verifyZeroMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(LAST_ANALYSIS_UUID).setPersonId(123L));

// developer measures of component C1
// developer measures of component C1 of last analysis
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setPersonId(A_PERSON_ID), "M4");
// developer measures of component C1 of non last analysis
verifyZeroMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(OTHER_ANALYSIS_UUID).setPersonId(A_PERSON_ID));
// developer measures of component C1 of last analysis by UUID
verifyMeasures(MeasureQuery.builder().setComponentUuid("C1").setAnalysisUuid(LAST_ANALYSIS_UUID).setPersonId(A_PERSON_ID), "M4");
}

@Test
public void selectSingle() {
insertAnalysis("A1", true);
insertMeasure("M1", "A1", "C1", NCLOC_METRIC_ID);
insertMeasure("M2", "A1", "C1", COMPLEXITY_METRIC_ID);
insertAnalysis(LAST_ANALYSIS_UUID, true);
insertMeasure("M1", LAST_ANALYSIS_UUID, "C1", NCLOC_METRIC_ID);
insertMeasure("M2", LAST_ANALYSIS_UUID, "C1", COMPLEXITY_METRIC_ID);
db.commit();

assertThat(selectSingle(MeasureQuery.builder().setComponentUuids(emptyList()))).isNotPresent();

Loading…
Cancel
Save