Commit 4eca0e26 authored by Matija Obreza's avatar Matija Obreza
Browse files

Fixed #43 Exclude historic records by default

parent c46c7ec5
......@@ -23,6 +23,7 @@ public class BasicFilter implements GenesysFilter {
private FilterType filterType;
private final Integer maxLength;
private boolean analyzed = false;
private boolean allowsNull = false;
@Override
public boolean isCore() {
......@@ -72,6 +73,11 @@ public class BasicFilter implements GenesysFilter {
this.maxLength = i;
}
public BasicFilter allowsNull(boolean allowsNull) {
this.allowsNull = allowsNull;
return this;
}
@Override
public String getKey() {
return name;
......@@ -90,4 +96,12 @@ public class BasicFilter implements GenesysFilter {
public Integer getMaxLength() {
return maxLength;
}
/**
* Specifies whether null is an accepted value
*/
@Override
public boolean isAllowsNull() {
return allowsNull;
}
}
\ No newline at end of file
......@@ -36,4 +36,6 @@ public interface GenesysFilter {
FilterType getFilterType();
public boolean isAnalyzed();
boolean isAllowsNull();
}
\ No newline at end of file
......@@ -38,25 +38,31 @@ public interface AccessionRepository extends JpaRepository<Accession, Long> {
@Query("select a.id from Accession a")
public List<Long> listAccessionsIds(Pageable pageable);
@Query(countQuery = "select count(*) from Accession a where a.institute = ?1")
Page<Accession> findByInstitute(FaoInstitute institute, Pageable pageable);
List<Accession> findByInstitute(FaoInstitute institute);
@Query("select count(a) from Accession a where a.institute = ?1")
/**
* Return the number of active ({@link Accession#historic} == false) accession records held at the institute
*/
@Query("select count(a) from Accession a where a.institute = ?1 and a.historic = false")
long countByInstitute(FaoInstitute institute);
@Query(value = "select t.genus, count(a.id) from Accession a inner join a.taxonomy t where a.institute = ?1 group by t.genus order by count(a) desc", countQuery = "select count(distinct a.taxonomy.taxGenus) from Accession a where a.institute = ?1")
Page<Object[]> statisticsGenusInInstitute(FaoInstitute institute, Pageable pageable);
@Query(value = "select t.taxSpecies, count(a) from Accession a inner join a.taxonomy t where a.institute = ?1 group by t.taxSpecies order by count(a) desc", countQuery = "select count(distinct a.taxonomy.taxSpecies) from Accession a where a.institute = ?1")
Page<Object[]> statisticsSpeciesInInstitute(FaoInstitute institute, Pageable pageable);
@Query("select count(a) from Accession a where a.countryOfOrigin = ?1")
/**
* Return the number of active ({@link Accession#historic} == false) accession records originating from specified country
*/
@Query("select count(a) from Accession a where a.countryOfOrigin = ?1 and a.historic = false")
long countByOrigin(Country country);
@Query("select count(a) from Accession a where a.institute.country = ?1")
/**
* Return the number of active ({@link Accession#historic} == false) accession records where holding institute is in the specified country
*/
@Query("select count(a) from Accession a where a.institute.country = ?1 and a.historic = false")
long countByLocation(Country country);
@Query(value = "select t.genus, count(a.id) from Accession a inner join a.taxonomy t where a.institute = ?1 and a.historic = false group by t.genus order by count(a) desc", countQuery = "select count(distinct a.taxonomy.taxGenus) from Accession a where a.institute = ?1")
Page<Object[]> statisticsGenusInInstitute(FaoInstitute institute, Pageable pageable);
@Query(value = "select t.taxSpecies, count(a) from Accession a inner join a.taxonomy t where a.institute = ?1 and a.historic = false group by t.taxSpecies order by count(a) desc", countQuery = "select count(distinct a.taxonomy.taxSpecies) from Accession a where a.institute = ?1")
Page<Object[]> statisticsSpeciesInInstitute(FaoInstitute institute, Pageable pageable);
@Query("select a from Accession a where a.institute in ( ?1 )")
Page<Accession> findByInstitute(List<FaoInstitute> institutes, Pageable pageable);
......
......@@ -56,10 +56,19 @@ import org.springframework.data.domain.Pageable;
public interface GenesysService {
/**
* Return the number of active ({@link Accession#historic} == false) accession records
*/
long countByInstitute(FaoInstitute institute);
/**
* Return the number of active ({@link Accession#historic} == false) accession records
*/
long countByOrigin(Country country);
/**
* Return the number of active ({@link Accession#historic} == false) accession records
*/
long countByLocation(Country country);
Accession getAccession(long accessionId);
......
......@@ -98,61 +98,57 @@ public class DirectMysqlQuery {
}
protected DirectMysqlQuery join(AppliedFilters filters) {
if (hasFilter(filters, FilterConstants.CROPS) || hasFilter(filters, FilterConstants.TAXONOMY_GENUS)
|| hasFilter(filters, FilterConstants.TAXONOMY_SPECIES) || hasFilter(filters, FilterConstants.TAXONOMY_SUBTAXA) || hasFilter(filters, FilterConstants.TAXONOMY_SCINAME)) {
if (filters.hasFilter(FilterConstants.CROPS) || filters.hasFilter(FilterConstants.TAXONOMY_GENUS)
|| filters.hasFilter(FilterConstants.TAXONOMY_SPECIES) || filters.hasFilter(FilterConstants.TAXONOMY_SUBTAXA)
|| filters.hasFilter(FilterConstants.TAXONOMY_SCINAME)) {
innerJoin("taxonomy2", "t", "t.id=a.taxonomyId2");
if (hasFilter(filters, FilterConstants.CROPS)) {
if (filters.hasFilter(FilterConstants.CROPS)) {
innerJoin("croptaxonomy", "ct", "ct.taxonomyId=t.id");
innerJoin("crop", null, "crop.id=ct.cropId");
}
}
// if (hasFilter(filters, FilterConstants.ORGCTY_ISO3)) {
// if (filters.hasFilter(FilterConstants.ORGCTY_ISO3)) {
// innerJoin("country", "cty", "cty.id=a.orgCtyId");
// }
if (/* hasFilter(filters, FilterConstants.INSTCODE) || */hasFilter(filters, FilterConstants.INSTITUTE_COUNTRY_ISO3)
|| hasFilter(filters, FilterConstants.INSTITUTE_NETWORK)) {
if (/* filters.hasFilter(FilterConstants.INSTCODE) || */filters.hasFilter(FilterConstants.INSTITUTE_COUNTRY_ISO3)
|| filters.hasFilter(FilterConstants.INSTITUTE_NETWORK)) {
innerJoin("faoinstitute", "fao", "fao.id=a.instituteId");
if (hasFilter(filters, FilterConstants.INSTITUTE_COUNTRY_ISO3)) {
if (filters.hasFilter(FilterConstants.INSTITUTE_COUNTRY_ISO3)) {
innerJoin("country", "faocty", "faocty.id=fao.countryId");
}
if (hasFilter(filters, FilterConstants.INSTITUTE_NETWORK)) {
if (filters.hasFilter(FilterConstants.INSTITUTE_NETWORK)) {
innerJoin("organizationinstitute", "oi", "oi.instituteId=fao.id");
innerJoin("organization", "org", "org.id=oi.organizationId");
}
}
if (hasFilter(filters, FilterConstants.GEO_LATITUDE) || hasFilter(filters, FilterConstants.GEO_LONGITUDE)
|| hasFilter(filters, FilterConstants.GEO_ELEVATION)) {
if (filters.hasFilter(FilterConstants.GEO_LATITUDE) || filters.hasFilter(FilterConstants.GEO_LONGITUDE)
|| filters.hasFilter(FilterConstants.GEO_ELEVATION)) {
innerJoin("accessiongeo", "geo", "geo.accessionId=a.id");
}
if (hasFilter(filters, FilterConstants.ALIAS)) {
if (filters.hasFilter(FilterConstants.ALIAS)) {
innerJoin("accessionalias", "accename", "accename.accessionId=a.id");
}
if (hasFilter(filters, FilterConstants.COLLMISSID)) {
if (filters.hasFilter(FilterConstants.COLLMISSID)) {
innerJoin("accessioncollect", "col", "col.accessionId=a.id");
}
if (hasFilter(filters, FilterConstants.STORAGE)) {
if (filters.hasFilter(FilterConstants.STORAGE)) {
outerJoin("accessionstorage", "storage", "storage.accessionId=a.id");
}
return this;
}
static boolean hasFilter(AppliedFilters filters, String filterName) {
final AppliedFilter f = filters.get(filterName);
return f != null && (f.getWithNull() || f.getValues().size() > 0);
}
protected DirectMysqlQuery filter(AppliedFilters filters, MethodResolver methodResolver) {
createQuery(whereBuffer, "a.id", filters.get("id"), params);
{
......@@ -169,7 +165,17 @@ public class DirectMysqlQuery {
createQuery(whereBuffer, "a.inTrust", filters.get(FilterConstants.ART15), params);
createQuery(whereBuffer, "a.sampStat", filters.get(FilterConstants.SAMPSTAT), params);
createQuery(whereBuffer, "a.available", filters.get(FilterConstants.AVAILABLE), params);
createQuery(whereBuffer, "a.historic", filters.get(FilterConstants.HISTORIC), params);
{
if (filters.hasFilter(FilterConstants.HISTORIC)) {
createQuery(whereBuffer, "a.historic", filters.get(FilterConstants.HISTORIC), params);
} else {
// Handle HISTORIC: When filter not provided by user, apply
// historic=false
createQuery(whereBuffer, "a.historic", FilterHandler.NON_HISTORIC_FILTER, params);
}
}
createQuery(whereBuffer, "org.slug", filters.get(FilterConstants.INSTITUTE_NETWORK), params);
createQuery(whereBuffer, "t.genus", filters.get(FilterConstants.TAXONOMY_GENUS), params);
createQuery(whereBuffer, "t.species", filters.get(FilterConstants.TAXONOMY_SPECIES), params);
......
......@@ -176,111 +176,124 @@ public class ElasticsearchSearchServiceImpl implements ElasticService, Initializ
private AndFilterBuilder getFilterBuilder(AppliedFilters appliedFilters) {
AndFilterBuilder filterBuilder = FilterBuilders.andFilter();
for (AppliedFilter appliedFilter : appliedFilters) {
applyFilter(filterBuilder, appliedFilter);
}
String key = appliedFilter.getFilterName();
{
// Handle HISTORIC: When filter not provided by user, apply
// historic=false
if (!appliedFilters.hasFilter(FilterConstants.HISTORIC)) {
applyFilter(filterBuilder, FilterHandler.NON_HISTORIC_FILTER);
}
}
GenesysFilter genesysFilter = filterHandler.getFilter(key);
return filterBuilder;
}
if (genesysFilter == null) {
LOG.warn("No such filter " + key);
continue;
}
private void applyFilter(AndFilterBuilder filterBuilder, AppliedFilter appliedFilter) {
String key = appliedFilter.getFilterName();
// Filter-level OR
OrFilterBuilder orFilter = FilterBuilders.orFilter();
GenesysFilter genesysFilter = filterHandler.getFilter(key);
// null
if (appliedFilter.getWithNull()) {
orFilter.add(FilterBuilders.missingFilter(key));
}
if (genesysFilter == null) {
LOG.warn("No such filter " + key);
return;
}
Set<FilterValue> filterValues = appliedFilter.getValues();
if (filterValues != null && !filterValues.isEmpty()) {
// Filter-level OR
OrFilterBuilder orFilter = FilterBuilders.orFilter();
{
// Handle literals
Set<Object> literals = new HashSet<Object>();
for (FilterValue filterValue : filterValues) {
if (filterValue instanceof FilterHandler.LiteralValueFilter) {
FilterHandler.LiteralValueFilter literal = (LiteralValueFilter) filterValue;
literals.add(literal.getValue());
}
}
// null
if (appliedFilter.getWithNull()) {
orFilter.add(FilterBuilders.missingFilter(key));
}
if (!literals.isEmpty()) {
Set<FilterValue> filterValues = appliedFilter.getValues();
if (filterValues != null && !filterValues.isEmpty()) {
if (genesysFilter.isAnalyzed()) {
// query
StringBuilder sb = new StringBuilder();
for (Object val : literals) {
if (sb.length() > 0)
sb.append(",");
if (val instanceof String)
sb.append("\"" + val + "\"");
else
sb.append(val);
}
{
// Handle literals
Set<Object> literals = new HashSet<Object>();
for (FilterValue filterValue : filterValues) {
if (filterValue instanceof FilterHandler.LiteralValueFilter) {
FilterHandler.LiteralValueFilter literal = (LiteralValueFilter) filterValue;
literals.add(literal.getValue());
}
}
if (FilterConstants.ALIAS.equals(key)) {
// Nested
orFilter.add(FilterBuilders.nestedFilter("aliases", QueryBuilders.queryString("aliases.name" + ":(" + sb.toString() + ")")));
} else {
orFilter.add(FilterBuilders.queryFilter(QueryBuilders.queryString(key + ":(" + sb.toString() + ")")));
}
if (!literals.isEmpty()) {
if (genesysFilter.isAnalyzed()) {
// query
StringBuilder sb = new StringBuilder();
for (Object val : literals) {
if (sb.length() > 0)
sb.append(",");
if (val instanceof String)
sb.append("\"" + val + "\"");
else
sb.append(val);
}
if (FilterConstants.ALIAS.equals(key)) {
// Nested
orFilter.add(FilterBuilders.nestedFilter("aliases", QueryBuilders.queryString("aliases.name" + ":(" + sb.toString() + ")")));
} else {
// terms
orFilter.add(FilterBuilders.queryFilter(QueryBuilders.queryString(key + ":(" + sb.toString() + ")")));
}
} else {
// terms
if (FilterConstants.SGSV.equals(key)) {
orFilter.add(FilterBuilders.termsFilter(FilterConstants.IN_SGSV, literals).execution("or"));
} else {
orFilter.add(FilterBuilders.termsFilter(key, literals).execution("or"));
}
if (FilterConstants.SGSV.equals(key)) {
orFilter.add(FilterBuilders.termsFilter(FilterConstants.IN_SGSV, literals).execution("or"));
} else {
orFilter.add(FilterBuilders.termsFilter(key, literals).execution("or"));
}
}
}
}
{
// Handle operations
for (FilterValue filterValue : filterValues) {
if (filterValue instanceof ValueRangeFilter) {
ValueRangeFilter range = (ValueRangeFilter) filterValue;
LOG.debug("Range " + range.getClass() + " " + range);
orFilter.add(FilterBuilders.rangeFilter(key).from(range.getFrom()).to(range.getTo()));
} else if (filterValue instanceof MaxValueFilter) {
MaxValueFilter max = (MaxValueFilter) filterValue;
LOG.debug("Max " + max);
orFilter.add(FilterBuilders.rangeFilter(key).to(max.getTo()));
} else if (filterValue instanceof MinValueFilter) {
MinValueFilter min = (MinValueFilter) filterValue;
LOG.debug("Min " + min);
orFilter.add(FilterBuilders.rangeFilter(key).from(min.getFrom()));
} else if (filterValue instanceof StartsWithFilter) {
StartsWithFilter startsWith = (StartsWithFilter) filterValue;
LOG.debug("startsWith " + startsWith);
if (genesysFilter.isAnalyzed()) {
if (FilterConstants.ALIAS.equals(key)) {
orFilter.add(FilterBuilders.nestedFilter("aliases",
QueryBuilders.queryString("aliases.name" + ":" + startsWith.getStartsWith() + "*")));
} else {
orFilter.add(FilterBuilders.queryFilter(QueryBuilders.queryString(key + ":" + startsWith.getStartsWith() + "*")));
}
{
// Handle operations
for (FilterValue filterValue : filterValues) {
if (filterValue instanceof ValueRangeFilter) {
ValueRangeFilter range = (ValueRangeFilter) filterValue;
LOG.debug("Range " + range.getClass() + " " + range);
orFilter.add(FilterBuilders.rangeFilter(key).from(range.getFrom()).to(range.getTo()));
} else if (filterValue instanceof MaxValueFilter) {
MaxValueFilter max = (MaxValueFilter) filterValue;
LOG.debug("Max " + max);
orFilter.add(FilterBuilders.rangeFilter(key).to(max.getTo()));
} else if (filterValue instanceof MinValueFilter) {
MinValueFilter min = (MinValueFilter) filterValue;
LOG.debug("Min " + min);
orFilter.add(FilterBuilders.rangeFilter(key).from(min.getFrom()));
} else if (filterValue instanceof StartsWithFilter) {
StartsWithFilter startsWith = (StartsWithFilter) filterValue;
LOG.debug("startsWith " + startsWith);
if (genesysFilter.isAnalyzed()) {
if (FilterConstants.ALIAS.equals(key)) {
orFilter.add(FilterBuilders.nestedFilter("aliases",
QueryBuilders.queryString("aliases.name" + ":" + startsWith.getStartsWith() + "*")));
} else {
orFilter.add(FilterBuilders.prefixFilter(key, startsWith.getStartsWith()));
orFilter.add(FilterBuilders.queryFilter(QueryBuilders.queryString(key + ":" + startsWith.getStartsWith() + "*")));
}
} else {
orFilter.add(FilterBuilders.prefixFilter(key, startsWith.getStartsWith()));
}
}
}
}
}
if (appliedFilter.isInverse()) {
filterBuilder.add(FilterBuilders.notFilter(orFilter));
} else {
filterBuilder.add(orFilter);
}
if (appliedFilter.isInverse()) {
filterBuilder.add(FilterBuilders.notFilter(orFilter));
} else {
filterBuilder.add(orFilter);
}
return filterBuilder;
}
@Override
......
......@@ -76,19 +76,25 @@ public class FilterHandler {
private final ArrayList<GenesysFilter> availableFilters;
/**
* By default we exclude historic records unless the user explicitly
* specifies otherwise.
*/
public static final AppliedFilter NON_HISTORIC_FILTER = new AppliedFilter().setFilterName(FilterConstants.HISTORIC).addFilterValue(new LiteralValueFilter(false));
public FilterHandler() {
this.availableFilters = new ArrayList<GenesysFilter>();
this.availableFilters.add(new BasicFilter(FilterConstants.CROPS, DataType.STRING));
this.availableFilters.add(new I18nListFilter<Integer>(FilterConstants.SAMPSTAT, DataType.NUMERIC).build("accession.sampleStatus", new Integer[] { 100,
110, 120, 130, 200, 300, 400, 410, 411, 412, 413, 414, 415, 416, 420, 421, 422, 423, 500, 600, 999 }));
this.availableFilters.add(new AutocompleteFilter(FilterConstants.TAXONOMY_GENUS, "/explore/ac/"+FilterConstants.TAXONOMY_GENUS));
this.availableFilters.add(new AutocompleteFilter(FilterConstants.TAXONOMY_SPECIES, "/explore/ac/"+FilterConstants.TAXONOMY_SPECIES));
this.availableFilters.add(new AutocompleteFilter(FilterConstants.TAXONOMY_SUBTAXA, "/explore/ac/"+FilterConstants.TAXONOMY_SUBTAXA));
this.availableFilters.add(new AutocompleteFilter(FilterConstants.TAXONOMY_SCINAME, "/explore/ac/"+FilterConstants.TAXONOMY_SCINAME));
this.availableFilters.add(new AutocompleteFilter(FilterConstants.TAXONOMY_GENUS, "/explore/ac/" + FilterConstants.TAXONOMY_GENUS));
this.availableFilters.add(new AutocompleteFilter(FilterConstants.TAXONOMY_SPECIES, "/explore/ac/" + FilterConstants.TAXONOMY_SPECIES));
this.availableFilters.add(new AutocompleteFilter(FilterConstants.TAXONOMY_SUBTAXA, "/explore/ac/" + FilterConstants.TAXONOMY_SUBTAXA));
this.availableFilters.add(new AutocompleteFilter(FilterConstants.TAXONOMY_SCINAME, "/explore/ac/" + FilterConstants.TAXONOMY_SCINAME));
this.availableFilters.add(new AutocompleteFilter(FilterConstants.ORGCTY_ISO3, "/explore/ac/"+FilterConstants.ORGCTY_ISO3));
this.availableFilters.add(new AutocompleteFilter(FilterConstants.INSTITUTE_COUNTRY_ISO3, "/explore/ac/"+FilterConstants.ORGCTY_ISO3));
this.availableFilters.add(new AutocompleteFilter(FilterConstants.ORGCTY_ISO3, "/explore/ac/" + FilterConstants.ORGCTY_ISO3));
this.availableFilters.add(new AutocompleteFilter(FilterConstants.INSTITUTE_COUNTRY_ISO3, "/explore/ac/" + FilterConstants.ORGCTY_ISO3));
this.availableFilters.add(new BasicFilter(FilterConstants.GEO_LATITUDE, DataType.NUMERIC));
this.availableFilters.add(new BasicFilter(FilterConstants.GEO_LONGITUDE, DataType.NUMERIC));
this.availableFilters.add(new BasicFilter(FilterConstants.GEO_ELEVATION, DataType.NUMERIC));
......@@ -101,7 +107,7 @@ public class FilterHandler {
this.availableFilters.add(new BasicFilter(FilterConstants.MLSSTATUS, DataType.BOOLEAN));
this.availableFilters.add(new BasicFilter(FilterConstants.ART15, DataType.BOOLEAN));
this.availableFilters.add(new BasicFilter(FilterConstants.AVAILABLE, DataType.BOOLEAN));
this.availableFilters.add(new BasicFilter(FilterConstants.HISTORIC, DataType.BOOLEAN));
this.availableFilters.add(new BasicFilter(FilterConstants.HISTORIC, DataType.BOOLEAN).allowsNull(false));
this.availableFilters.add(new BasicFilter(FilterConstants.COLLMISSID, DataType.STRING).setAnalyzed(true));
this.availableFilters.add(new I18nListFilter<Integer>(FilterConstants.STORAGE, DataType.NUMERIC).build("accession.storage", new Integer[] { 10, 11, 12,
13, 20, 30, 40, 50, 99 }));
......@@ -358,6 +364,18 @@ public class FilterHandler {
return null;
}
/**
* Returns true if the filter is listed and has at least one value
* specified
*
* @param filterName
* @return
*/
public boolean hasFilter(final String filterName) {
final AppliedFilter f = get(filterName);
return f != null && (f.getWithNull() || f.getValues().size() > 0);
}
public Collection<AppliedFilter> methodFilters() {
return CollectionUtils.select(this, new Predicate<AppliedFilter>() {
@Override
......
......@@ -84,7 +84,9 @@
<div class="">
<div><label><input type="checkbox" ${fn:contains(filters[filter.key], 'true')?'checked':''} class="filter-bool" i-key="<c:out value="${filter.key}" />" id="<c:out value="${normalizedKey}" />" value="true"><spring:message code="boolean.true"/></label></div>
<div><label><input type="checkbox" ${fn:contains(filters[filter.key], 'false')?'checked':''} class="filter-bool" i-key="<c:out value="${filter.key}" />" id="<c:out value="${normalizedKey}" />" value="false"><spring:message code="boolean.false"/></label></div>
<c:if test="${filter.allowsNull}">
<div><label><input type="checkbox" ${fn:contains(filters[filter.key], 'null')?'checked':''} class="filter-bool" i-key="<c:out value="${filter.key}" />" id="<c:out value="${normalizedKey}" />" value="null"><spring:message code="boolean.null"/></label></div>
</c:if>
</div>
</c:when>
<c:otherwise>
......
......@@ -160,7 +160,9 @@
<div class="">
<div><label><input type="checkbox" ${fn:contains(filters[appliedFilter.key], 'true')?'checked':''} class="filter-bool" i-key="<c:out value="${filter.key}" />" id="<c:out value="${normalizedKey}" />" value="true"><spring:message code="boolean.true"/></label></div>
<div><label><input type="checkbox" ${fn:contains(filters[appliedFilter.key], 'false')?'checked':''} class="filter-bool" i-key="<c:out value="${filter.key}" />" id="<c:out value="${normalizedKey}" />" value="false"><spring:message code="boolean.false"/></label></div>
<c:if test="${filter.allowsNull}">
<div><label><input type="checkbox" ${fn:contains(filters[appliedFilter.key], 'null')?'checked':''} class="filter-bool" i-key="<c:out value="${filter.key}" />" id="<c:out value="${normalizedKey}" />" value="null"><spring:message code="boolean.null"/></label></div>
</c:if>
</div>
</c:when>
<c:when test="${filter.key=='crops'}">
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment