Skip to content
This repository has been archived by the owner on Apr 16, 2022. It is now read-only.

Commit

Permalink
Merge pull request #690 from ggalmazor/issue_689_split_select_multipl…
Browse files Browse the repository at this point in the history
…es_in_groups

Issue 689 split select multiples in groups
  • Loading branch information
ggalmazor authored Dec 12, 2018
2 parents 5af9562 + 431d823 commit cb89a71
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 41 deletions.
23 changes: 4 additions & 19 deletions src/org/opendatakit/briefcase/export/CsvSubmissionMappers.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
import static java.util.stream.Stream.concat;
import static java.util.stream.Stream.of;
import static org.javarosa.core.model.DataType.DATE;
import static org.javarosa.core.model.DataType.DATE_TIME;
Expand All @@ -30,7 +29,6 @@

import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Set;
Expand Down Expand Up @@ -106,7 +104,7 @@ static CsvSubmissionMapper repeat(FormDefinition formDefinition, Model groupMode
static String getMainHeader(Model model, boolean isEncrypted, boolean splitSelectMultiples, boolean removeGroupNames) {
List<String> headers = new ArrayList<>();
headers.add("SubmissionDate");
headers.addAll(getModelNames(0, model, splitSelectMultiples, removeGroupNames));
headers.addAll(model.getNames(0, splitSelectMultiples, removeGroupNames));
headers.add("KEY");
if (isEncrypted)
headers.add("isValidated");
Expand All @@ -119,28 +117,15 @@ static String getMainHeader(Model model, boolean isEncrypted, boolean splitSelec
static String getRepeatHeader(Model groupModel, boolean splitSelectMultiples, boolean removeGroupNames) {
int shift = groupModel.countAncestors();
List<String> headers = new ArrayList<>();
headers.addAll(getModelNames(shift, groupModel, splitSelectMultiples, removeGroupNames));
headers.addAll(groupModel.children().stream()
.flatMap(field -> field.getNames(shift, splitSelectMultiples, removeGroupNames).stream())
.collect(toList()));
headers.add("PARENT_KEY");
headers.add("KEY");
headers.add("SET-OF-" + groupModel.getName());
return String.join(",", headers);
}

private static List<String> getModelNames(int shift, Model groupModel, boolean splitSelectMultiples, boolean removeGroupNames) {
return groupModel.children().stream().flatMap(field -> concat(
field.getNames(shift, removeGroupNames).stream(),
getSplitSelectMultipleNames(field, splitSelectMultiples).stream()
)).collect(toList());
}

private static List<String> getSplitSelectMultipleNames(Model field, boolean splitSelectMultiples) {
if (!field.isChoiceList() || !splitSelectMultiples)
return Collections.emptyList();
return field.getChoices().stream()
.map(choice -> field.getName() + "/" + choice.getValue())
.collect(toList());
}

static String encode(String string, boolean allowNulls) {
if (string == null || string.isEmpty())
return allowNulls ? "" : "\"\"";
Expand Down
25 changes: 9 additions & 16 deletions src/org/opendatakit/briefcase/export/Model.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Stream.concat;
import static org.javarosa.core.model.Constants.DATATYPE_NULL;
import static org.javarosa.core.model.DataType.GEOPOINT;
import static org.javarosa.core.model.DataType.GEOSHAPE;
Expand Down Expand Up @@ -135,31 +136,18 @@ DataType getDataType() {
return DataType.from(model.getDataType());
}

/**
* Returns the {@link List} of {@link String} names that this {@link Model} instance can be
* associated with.
* <p>
* For example, {@link DataType#GEOPOINT} fields have 4 associated values.
*
* @return a {@link List} of {@link String} names of this {@link Model} instance
*/
List<String> getNames(boolean removeGroupNames) {
return getNames(0, removeGroupNames);
}

/**
* Returns the {@link List} of {@link String} names that this {@link Model} instance can be
* associated with, shifted a given number of names.
*
* @param shift an int with the number of names to shift from the FQN
* @return a {@link List} of shifted {@link String} names of this {@link Model} instance
* @see Model#getNames(boolean)
*/
List<String> getNames(int shift, boolean removeGroupNames) {
List<String> getNames(int shift, boolean splitSelectMultiples, boolean removeGroupNames) {
if (getDataType() == NULL && model.isRepeatable())
return singletonList("SET-OF-" + fqn(shift));
if (getDataType() == NULL && !model.isRepeatable() && size() > 0)
return children().stream().flatMap(e -> e.getNames(shift, removeGroupNames).stream()).collect(toList());
return children().stream().flatMap(e -> e.getNames(shift, splitSelectMultiples, removeGroupNames).stream()).collect(toList());
String fieldName = removeGroupNames ? getName() : fqn(shift);
if (getDataType() == GEOPOINT)
return Arrays.asList(
Expand All @@ -168,6 +156,11 @@ List<String> getNames(int shift, boolean removeGroupNames) {
fieldName + "-Altitude",
fieldName + "-Accuracy"
);
if (isChoiceList() && splitSelectMultiples)
return concat(
Stream.of(fieldName),
getChoices().stream().map(choice -> fieldName + "/" + choice.getValue())
).collect(toList());
return singletonList(fieldName);
}

Expand Down Expand Up @@ -241,7 +234,7 @@ boolean hasParent() {

private Stream<Model> flatten() {
return children().stream()
.flatMap(e -> e.size() == 0 ? Stream.of(e) : Stream.concat(Stream.of(e), e.flatten()));
.flatMap(e -> e.size() == 0 ? Stream.of(e) : concat(Stream.of(e), e.flatten()));
}

private long size() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@
import static org.opendatakit.briefcase.export.ModelBuilder.group;
import static org.opendatakit.briefcase.export.ModelBuilder.instance;
import static org.opendatakit.briefcase.export.ModelBuilder.repeat;
import static org.opendatakit.briefcase.export.ModelBuilder.selectMultiple;
import static org.opendatakit.briefcase.export.ModelBuilder.text;

import org.javarosa.core.model.SelectChoice;
import org.junit.Test;

public class CsvSubmissionMappersHeadersTest {
Expand Down Expand Up @@ -59,7 +61,7 @@ public void supports_dupe_field_names() {
}

@Test
public void supports_fields_that_generate_more_than_one_column() {
public void supports_geopoint_fields() {
Model model = instance(
group("some-group", geopoint("some-point"))
).build();
Expand All @@ -68,4 +70,46 @@ public void supports_fields_that_generate_more_than_one_column() {
assertThat(getMainHeader(model, false, false, true), is("SubmissionDate,some-point-Latitude,some-point-Longitude,some-point-Altitude,some-point-Accuracy,KEY"));
assertThat(getMainHeader(model, true, false, true), is("SubmissionDate,some-point-Latitude,some-point-Longitude,some-point-Altitude,some-point-Accuracy,KEY,isValidated"));
}

@Test
public void supports_splitting_select_multiple_fields() {
SelectChoice choice1 = new SelectChoice("some label 1", "some value 1", false);
SelectChoice choice2 = new SelectChoice("some label 2", "some value 2", false);

Model model = instance(selectMultiple("select", choice1, choice2)).build();
assertThat(getMainHeader(model, false, false, false), is("SubmissionDate,select,KEY"));
assertThat(getMainHeader(model, true, false, false), is("SubmissionDate,select,KEY,isValidated"));
assertThat(getMainHeader(model, false, false, true), is("SubmissionDate,select,KEY"));
assertThat(getMainHeader(model, true, false, true), is("SubmissionDate,select,KEY,isValidated"));
assertThat(getMainHeader(model, false, true, false), is("SubmissionDate,select,select/some value 1,select/some value 2,KEY"));
assertThat(getMainHeader(model, true, true, false), is("SubmissionDate,select,select/some value 1,select/some value 2,KEY,isValidated"));
assertThat(getMainHeader(model, false, true, true), is("SubmissionDate,select,select/some value 1,select/some value 2,KEY"));
assertThat(getMainHeader(model, true, true, true), is("SubmissionDate,select,select/some value 1,select/some value 2,KEY,isValidated"));
Model repeat = instance(repeat("some-repeat", selectMultiple("select", choice1, choice2))).build().getChildByName("some-repeat");
assertThat(getRepeatHeader(repeat, false, false), is("select,PARENT_KEY,KEY,SET-OF-some-repeat"));
assertThat(getRepeatHeader(repeat, false, true), is("select,PARENT_KEY,KEY,SET-OF-some-repeat"));
assertThat(getRepeatHeader(repeat, true, false), is("select,select/some value 1,select/some value 2,PARENT_KEY,KEY,SET-OF-some-repeat"));
assertThat(getRepeatHeader(repeat, true, true), is("select,select/some value 1,select/some value 2,PARENT_KEY,KEY,SET-OF-some-repeat"));
}

@Test
public void supports_splitting_select_multiple_fields_in_groups() {
SelectChoice choice1 = new SelectChoice("some label 1", "some value 1", false);
SelectChoice choice2 = new SelectChoice("some label 2", "some value 2", false);

Model model = instance(group("some-group", selectMultiple("select", choice1, choice2))).build();
assertThat(getMainHeader(model, false, false, false), is("SubmissionDate,some-group-select,KEY"));
assertThat(getMainHeader(model, true, false, false), is("SubmissionDate,some-group-select,KEY,isValidated"));
assertThat(getMainHeader(model, false, false, true), is("SubmissionDate,select,KEY"));
assertThat(getMainHeader(model, true, false, true), is("SubmissionDate,select,KEY,isValidated"));
assertThat(getMainHeader(model, false, true, false), is("SubmissionDate,some-group-select,some-group-select/some value 1,some-group-select/some value 2,KEY"));
assertThat(getMainHeader(model, true, true, false), is("SubmissionDate,some-group-select,some-group-select/some value 1,some-group-select/some value 2,KEY,isValidated"));
assertThat(getMainHeader(model, false, true, true), is("SubmissionDate,select,select/some value 1,select/some value 2,KEY"));
assertThat(getMainHeader(model, true, true, true), is("SubmissionDate,select,select/some value 1,select/some value 2,KEY,isValidated"));
Model repeat = instance(repeat("some-repeat", group("some-group", selectMultiple("select", choice1, choice2)))).build().getChildByName("some-repeat");
assertThat(getRepeatHeader(repeat, false, false), is("some-group-select,PARENT_KEY,KEY,SET-OF-some-repeat"));
assertThat(getRepeatHeader(repeat, false, true), is("select,PARENT_KEY,KEY,SET-OF-some-repeat"));
assertThat(getRepeatHeader(repeat, true, false), is("some-group-select,some-group-select/some value 1,some-group-select/some value 2,PARENT_KEY,KEY,SET-OF-some-repeat"));
assertThat(getRepeatHeader(repeat, true, true), is("select,select/some value 1,select/some value 2,PARENT_KEY,KEY,SET-OF-some-repeat"));
}
}
6 changes: 5 additions & 1 deletion test/java/org/opendatakit/briefcase/export/ModelBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,11 @@ public ModelBuilder add(List<ModelBuilder> children) {
TreeElement newChild = copy(child.current);
newCurrent.addChild(child.current);
newChild.setParent(newCurrent);
child.controls.forEach(newControls::put);

child.controls.forEach((key, value) -> newControls.put(
getName() != null && !getName().equals("data") ? getName() + "-" + key : key,
value
));
}
return new ModelBuilder(newCurrent, newControls);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
<data id="choice-lists" instanceID="uuid:39f3dd36-161e-45cb-a1a4-395831d253a7" submissionDate="2018-04-26T08:58:20.525Z" isComplete="true" markedAsCompleteDate="2018-04-26T08:58:20.525Z" xmlns="http://opendatakit.org/submissions">
<some_string>CHOICE_1</some_string>
<another_string>CHOICE_2</another_string>
<some_group>
<yet_another_string>CHOICE_1</yet_another_string>
</some_group>
<n0:meta xmlns:n0="http://openrosa.org/xforms">
<n0:instanceID>uuid:39f3dd36-161e-45cb-a1a4-395831d253a7</n0:instanceID>
</n0:meta>
</data>
</data>
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
SubmissionDate,some_string,some_string/CHOICE_1,some_string/CHOICE_2,another_string,meta-instanceID,KEY
"Apr 26, 2018 8:58:20 AM",CHOICE_1,1,0,CHOICE_2,uuid:39f3dd36-161e-45cb-a1a4-395831d253a7,uuid:39f3dd36-161e-45cb-a1a4-395831d253a7
SubmissionDate,some_string,some_string/CHOICE_1,some_string/CHOICE_2,another_string,some_group-yet_another_string,some_group-yet_another_string/CHOICE_1,some_group-yet_another_string/CHOICE_2,meta-instanceID,KEY
"Apr 26, 2018 8:58:20 AM",CHOICE_1,1,0,CHOICE_2,CHOICE_1,1,0,uuid:39f3dd36-161e-45cb-a1a4-395831d253a7,uuid:39f3dd36-161e-45cb-a1a4-395831d253a7
20 changes: 19 additions & 1 deletion test/resources/org/opendatakit/briefcase/export/choice-lists.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@
<data id="choice-lists">
<some_string/>
<another_string/>
<some_group>
<yet_another_string/>
</some_group>
<meta>
<instanceID/>
</meta>
</data>
</instance>
<bind nodeset="/data/some_string" type="string"/>
<bind nodeset="/data/another_string" type="string"/>
<bind nodeset="/data/some_group/yet_another_string" type="string"/>
<bind calculate="concat('uuid:', uuid())" nodeset="/data/meta/instanceID" readonly="true()" type="string"/>
</model>
</h:head>
Expand All @@ -37,5 +42,18 @@
<label>CHOICE 2</label>
</item>
</select1>
<group>
<label>Some group</label>
<select ref="/data/some_group/yet_another_string">
<item>
<value>CHOICE_1</value>
<label>CHOICE 1</label>
</item>
<item>
<value>CHOICE_2</value>
<label>CHOICE 2</label>
</item>
</select>
</group>
</h:body>
</h:html>
</h:html>

0 comments on commit cb89a71

Please sign in to comment.