Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class EntityInstanceListFilter {
/*
Given a Map of
FieldName,Value
sort_by,+-FieldName
_sortBy,+-FieldName

*/
public EntityInstanceListFilter(QueryFilterParams queryParams) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class EntityInstanceListSorter {
/*
Given a Map of
FieldName,Value
sort_by,+-FieldName
_sortBy,+-FieldName

*/
public EntityInstanceListSorter(final QueryFilterParams queryParams) {
Expand All @@ -21,16 +21,23 @@ public List<EntityInstance> sort(final List<EntityInstance> foundItems) {

List<EntityInstance> sorted = new ArrayList<>(foundItems);

Comparator<EntityInstance> comparator = null;
for (SortByFieldName sortBy : instanceFilter.sortBys()) {
sorted = sortByField(sortBy.fieldName, sortBy.order, sorted);
Comparator<EntityInstance> sortByField = compareByField(sortBy, sorted);
if (sortByField != null) {
comparator =
comparator == null ? sortByField : comparator.thenComparing(sortByField);
}
}

if (comparator != null) {
sorted.sort(comparator);
}

return sorted;
}

/** Sorted list of instances */

// TODO: unit tests for sorting
public List<EntityInstance> sortByField(
String fieldName, int order, final List<EntityInstance> itemsToSort) {

Expand All @@ -41,11 +48,31 @@ public List<EntityInstance> sortByField(
return sortedList;
}

Field fieldDefn = sortedList.get(0).getEntity().getField(fieldName);
Comparator<EntityInstance> compareByFieldValue =
compareByField(fieldName, order, sortedList);
if (compareByFieldValue == null) {
return sortedList;
}

sortedList.sort(compareByFieldValue);

// there is no field of that name
return sortedList;
}

private Comparator<EntityInstance> compareByField(
final SortByFieldName sortBy, final List<EntityInstance> itemsToSort) {
return compareByField(sortBy.getFieldName(), sortBy.getOrder(), itemsToSort);
}

private Comparator<EntityInstance> compareByField(
final String fieldName, final int order, final List<EntityInstance> itemsToSort) {
if (itemsToSort.isEmpty()) {
return null;
}

Field fieldDefn = itemsToSort.get(0).getEntity().getField(fieldName);
if (fieldDefn == null) {
return sortedList;
return null;
}

Comparator<EntityInstance> compareByFieldValue =
Expand All @@ -65,13 +92,9 @@ public int compare(EntityInstance thing1, EntityInstance thing2) {
};

if (order < 0) {
// (desc)
Collections.sort(sortedList, compareByFieldValue);
return compareByFieldValue;
} else {
// low to high sort (asc)
Collections.sort(sortedList, compareByFieldValue.reversed());
return compareByFieldValue.reversed();
}

return sortedList;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,39 +22,50 @@ public EntityListSortParamParser(final List<FilterBy> queryParams) {
}

/*
return all the sortBy values
currently sortBy=-FieldName or sortBy=+FieldName or sortBy=FieldName
or sort_by=etc.

TODO: handle multiple sort fields e.g. sortBy=-FieldName1,+FieldName2
return all the _sortBy values
currently _sortBy=-FieldName or _sortBy=+FieldName or _sortBy=FieldName
or multiple sort fields e.g. _sortBy=-FieldName1,+FieldName2
*/
public List<SortByFieldName> sortBys() {
List<SortByFieldName> sortbys = new ArrayList<>();
for (FilterBy field : params.sortBys()) {
if (isSortByParam(field.fieldName)) {
final SortByFieldName aSortBy = new SortByFieldName();
String sortByValue = field.fieldValue;
switch (sortByValue.charAt(0)) {
case '-':
aSortBy.order = 1;
aSortBy.fieldName = sortByValue.substring(1).trim();
break;
case '+':
aSortBy.order = -1;
aSortBy.fieldName = sortByValue.substring(1).trim();
break;
default:
aSortBy.order = -1;
aSortBy.fieldName = sortByValue.trim();
break;
for (String sortByValue : field.fieldValue.split(",")) {
final SortByFieldName aSortBy = sortByFrom(sortByValue);
if (aSortBy != null) {
sortbys.add(aSortBy);
}
}
sortbys.add(aSortBy);
}
}
return sortbys;
}

private SortByFieldName sortByFrom(final String value) {
String sortByValue = value.trim();
if (sortByValue.isEmpty()) {
return null;
}

final SortByFieldName aSortBy = new SortByFieldName();
switch (sortByValue.charAt(0)) {
case '-':
aSortBy.order = 1;
aSortBy.fieldName = sortByValue.substring(1).trim();
break;
case '+':
aSortBy.order = -1;
aSortBy.fieldName = sortByValue.substring(1).trim();
break;
default:
aSortBy.order = -1;
aSortBy.fieldName = sortByValue;
break;
}
return aSortBy.fieldName.isEmpty() ? null : aSortBy;
}

public static boolean isSortByParam(final String key) {
return (key.equalsIgnoreCase("sortby") || key.equalsIgnoreCase("sort_by"));
return SortByFieldName.isSortByParam(key);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public FilterBy get(int i) {

public boolean hasSortBy() {
for (FilterBy filterBy : filterBys) {
if (filterBy.fieldName.equals("sortBy") || filterBy.fieldName.equals("sort_by")) {
if (SortByFieldName.isSortByParam(filterBy.fieldName)) {
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package uk.co.compendiumdev.thingifier.core.query;

public class SortByFieldName {
public static final String PARAMETER_NAME = "_sortBy";

int order = 1;
String fieldName = "";

Expand All @@ -13,6 +15,6 @@ public String getFieldName() {
}

public static boolean isSortByParam(final String key) {
return (key.equalsIgnoreCase("sortby") || key.equalsIgnoreCase("sort_by"));
return PARAMETER_NAME.equals(key);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package uk.co.compendiumdev.thingifier.core.query;

import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import uk.co.compendiumdev.thingifier.core.domain.definitions.EntityDefinition;
import uk.co.compendiumdev.thingifier.core.domain.definitions.field.definition.Field;
import uk.co.compendiumdev.thingifier.core.domain.definitions.field.definition.FieldType;
import uk.co.compendiumdev.thingifier.core.domain.instances.EntityInstance;
import uk.co.compendiumdev.thingifier.core.repository.MutableEntityInstance;

public class EntityInstanceListSorterTest {

private EntityDefinition thing;

@BeforeEach
public void setupEntityDefinition() {
thing =
new EntityDefinition("thing", "things", -1)
.addFields(
Field.is("category", FieldType.STRING),
Field.is("priority", FieldType.INTEGER));
}

@Test
public void sortsBySingleFieldAscendingAndDescending() {
EntityInstance low = instance("beta", "1");
EntityInstance high = instance("alpha", "3");
List<EntityInstance> unsorted = List.of(low, high);

QueryFilterParams ascending = new QueryFilterParams();
ascending.put("_sortBy", "+priority");
Assertions.assertEquals(
List.of(low, high), new EntityInstanceListSorter(ascending).sort(unsorted));

QueryFilterParams descending = new QueryFilterParams();
descending.put("_sortBy", "-priority");
Assertions.assertEquals(
List.of(high, low), new EntityInstanceListSorter(descending).sort(unsorted));
}

@Test
public void sortsByMultipleFieldsUsingLaterFieldsAsTieBreakers() {
EntityInstance alphaLow = instance("alpha", "1");
EntityInstance alphaHigh = instance("alpha", "3");
EntityInstance betaLow = instance("beta", "2");
EntityInstance betaHigh = instance("beta", "4");
List<EntityInstance> unsorted = List.of(betaLow, alphaLow, betaHigh, alphaHigh);

QueryFilterParams params = new QueryFilterParams();
params.put("_sortBy", "+category,-priority");

List<EntityInstance> sorted = new EntityInstanceListSorter(params).sort(unsorted);

Assertions.assertEquals(List.of(alphaHigh, alphaLow, betaHigh, betaLow), sorted);
}

@Test
public void trimsAndIgnoresBlankMultiFieldSortTokens() {
EntityInstance alphaLow = instance("alpha", "1");
EntityInstance alphaHigh = instance("alpha", "3");
EntityInstance betaLow = instance("beta", "2");
EntityInstance betaHigh = instance("beta", "4");
List<EntityInstance> unsorted = List.of(betaLow, alphaLow, betaHigh, alphaHigh);

QueryFilterParams params = new QueryFilterParams();
params.put("_sortBy", " +category, , -priority ");

List<EntityInstance> sorted = new EntityInstanceListSorter(params).sort(unsorted);

Assertions.assertEquals(List.of(alphaHigh, alphaLow, betaHigh, betaLow), sorted);
}

@Test
public void ignoresUnknownSortFieldsAndDoesNotMutateInputList() {
EntityInstance low = instance("beta", "1");
EntityInstance high = instance("alpha", "3");
List<EntityInstance> unsorted = List.of(low, high);

QueryFilterParams params = new QueryFilterParams();
params.put("_sortBy", "+missing");

List<EntityInstance> sorted = new EntityInstanceListSorter(params).sort(unsorted);

Assertions.assertEquals(List.of(low, high), sorted);
Assertions.assertNotSame(unsorted, sorted);
}

private EntityInstance instance(final String category, final String priority) {
return MutableEntityInstance.forEntity(thing)
.setValue("category", category)
.setValue("priority", priority)
.toEntityInstance();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public void canFilterBooleanMatchesNotTrue() {
@Test
public void canSortBooleanMatchesAsc() {
QueryFilterParams params = new QueryFilterParams();
params.put("sortBy", "+truefalse");
params.put("_sortBy", "+truefalse");

RepositoryQuery queryResults = queryThings(params);

Expand All @@ -127,7 +127,7 @@ public void canSortBooleanMatchesAsc() {
@Test
public void canSortBooleanMatchesDesc() {
QueryFilterParams params = new QueryFilterParams();
params.put("sortBy", "-truefalse");
params.put("_sortBy", "-truefalse");

RepositoryQuery queryResults = queryThings(params);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public void canFilterFloatNotEquals() {

QueryFilterParams params = new QueryFilterParams();
params.put("float", "!1.1");
params.put("sortby", "+float");
params.put("_sortBy", "+float");

RepositoryQuery queryResults = queryThings(params);
Assertions.assertTrue(queryResults.isResultACollection(), "result should be a collection");
Expand All @@ -83,7 +83,7 @@ public void canFilterFloatCombinationOfConditions() {
QueryFilterParams params = new QueryFilterParams();
params.put("float", ">1.1"); // greater than 1
params.put("float", "!3.3"); // and not equal to 3
params.put("sortby", "+float");
params.put("_sortBy", "+float");

RepositoryQuery queryResults = queryThings(params);
Assertions.assertTrue(queryResults.isResultACollection(), "result should be a collection");
Expand All @@ -97,7 +97,7 @@ public void canFilterFloatCombinationOfConditions() {
public void canFilterFloatGreaterThan() {
QueryFilterParams params = new QueryFilterParams();
params.put("float", ">1.1");
params.put("sortby", "+float");
params.put("_sortBy", "+float");

RepositoryQuery queryResults = queryThings(params);

Expand All @@ -113,7 +113,7 @@ public void canFilterFloatGreaterThan() {
public void canFilterFloatLessThan() {
QueryFilterParams params = new QueryFilterParams();
params.put("float", "<2.0");
params.put("sortby", "+float");
params.put("_sortBy", "+float");

RepositoryQuery queryResults = queryThings(params);

Expand All @@ -127,7 +127,7 @@ public void canFilterFloatLessThan() {
public void canFilterFloatLessThanNotMatching() {
QueryFilterParams params = new QueryFilterParams();
params.put("float", "<1.1");
params.put("sortby", "+float");
params.put("_sortBy", "+float");

RepositoryQuery queryResults = queryThings(params);

Expand All @@ -140,7 +140,7 @@ public void canFilterFloatLessThanNotMatching() {
public void canFilterFloatGreaterThanEquals() {
QueryFilterParams params = new QueryFilterParams();
params.put("float", ">=3.3");
params.put("sortby", "+float");
params.put("_sortBy", "+float");

RepositoryQuery queryResults = queryThings(params);

Expand All @@ -155,7 +155,7 @@ public void canFilterFloatGreaterThanEquals() {
public void canFilterFloatLessThanEquals() {
QueryFilterParams params = new QueryFilterParams();
params.put("float", "<=3.3");
params.put("sortby", "+float");
params.put("_sortBy", "+float");

RepositoryQuery queryResults = queryThings(params);

Expand All @@ -171,7 +171,7 @@ public void canFilterFloatLessThanEquals() {
public void canFilterFloatLessThanEqualsSortDesc() {
QueryFilterParams params = new QueryFilterParams();
params.put("float", "<=3.3");
params.put("sortby", "-float");
params.put("_sortBy", "-float");

RepositoryQuery queryResults = queryThings(params);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public void canFilterAndSortIdAsc() {

QueryFilterParams params = new QueryFilterParams();
params.put("id", ">=3");
params.put("sortBy", "+id");
params.put("_sortBy", "+id");

RepositoryQuery queryResults = queryThings(params);

Expand All @@ -70,7 +70,7 @@ public void canFilterAndSortIdDesc() {

QueryFilterParams params = new QueryFilterParams();
params.put("id", "<3");
params.put("sortBy", "-id");
params.put("_sortBy", "-id");

RepositoryQuery queryResults = queryThings(params);

Expand Down
Loading
Loading