Skip to content

Commit

Permalink
get time filter working, re #4771
Browse files Browse the repository at this point in the history
  • Loading branch information
apeters committed May 6, 2019
1 parent 824a72f commit 8703a0b
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 109 deletions.
3 changes: 1 addition & 2 deletions arches/app/media/js/views/components/search/map-filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,7 @@ function(ko, BaseFilter, arches) {
this.updateQuery();
}, this);

options.filters[componentName](this);

this.filters[componentName](this);
this.restoreState();
},

Expand Down
3 changes: 1 addition & 2 deletions arches/app/media/js/views/components/search/term-filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ define([
}, this);
}, this, "arrayChange");

options.filters[componentName](this);

this.filters[componentName](this);
this.restoreState();
},

Expand Down
75 changes: 41 additions & 34 deletions arches/app/media/js/views/components/search/time-filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ define([
'bindings/time-wheel'
],
function(_, ko, moment, BaseFilter, arches) {
return ko.components.register('time-filter', {
var componentName = 'time-filter';
return ko.components.register(componentName, {
viewModel: BaseFilter.extend({
initialize: function(options) {
var self = this;
BaseFilter.prototype.initialize.call(this, options);
this.name = 'Time Filter';
this.filter = {
fromDate: ko.observable(null),
Expand All @@ -21,15 +22,15 @@ function(_, ko, moment, BaseFilter, arches) {
inverted: ko.observable(false)
};
this.filter.fromDate.subscribe(function (fromDate) {
var toDate = self.filter.toDate();
var toDate = this.filter.toDate();
if (fromDate && toDate && !this.isFromLessThanTo(fromDate, toDate)) {
self.filter.toDate(fromDate);
this.filter.toDate(fromDate);
}
}, this);
this.filter.toDate.subscribe(function (toDate) {
var fromDate = self.filter.fromDate();
var fromDate = this.filter.fromDate();
if (fromDate && toDate && !this.isFromLessThanTo(fromDate, toDate)) {
self.filter.fromDate(toDate);
this.filter.fromDate(toDate);
}
}, this);
this.dateRangeType = ko.observable('custom');
Expand All @@ -41,14 +42,14 @@ function(_, ko, moment, BaseFilter, arches) {
this.getTimeWheelConfig();
this.selectedPeriod.subscribe(function (d) {
if (d) {
var start = moment(0, 'YYYY').add(d.start, 'years').format(self.format);
var end = moment(0, 'YYYY').add(d.end, 'years').format(self.format);
self.dateRangeType('custom');
self.filter.fromDate(end);
self.filter.toDate(end);
self.filter.fromDate(start);
var start = moment(0, 'YYYY').add(d.start, 'years').format(this.format);
var end = moment(0, 'YYYY').add(d.end, 'years').format(this.format);
this.dateRangeType('custom');
this.filter.fromDate(end);
this.filter.toDate(end);
this.filter.fromDate(start);
}
})
}, this);

this.dateRangeType.subscribe(function(value) {
var today = moment();
Expand Down Expand Up @@ -89,12 +90,28 @@ function(_, ko, moment, BaseFilter, arches) {

this.filterChanged = ko.computed(function(){
if(!!this.filter.fromDate() || !!this.filter.toDate()){
this.termFilter.addTag(this.name, this.name, this.filter.inverted);
this.getFilter('term-filter').addTag(this.name, this.name, this.filter.inverted);
}
return ko.toJSON(this.filter);
}, this).extend({ deferred: true });

BaseFilter.prototype.initialize.call(this, options);
this.filterChanged.subscribe(function() {
this.updateQuery();
}, this);

this.filters[componentName](this);
this.restoreState();
},

updateQuery: function() {
var queryObj = this.query();
var filters_applied = !!this.filter.fromDate() || !!this.filter.toDate();
if(filters_applied){
queryObj[componentName] = ko.toJSON(this.filter);
} else {
delete queryObj[componentName];
}
this.query(queryObj);
},

getTimeWheelConfig: function(){
Expand All @@ -111,28 +128,18 @@ function(_, ko, moment, BaseFilter, arches) {
});
},

appendFilters: function(filterParams) {
var filters_applied = !!this.filter.fromDate() || !!this.filter.toDate();
if(filters_applied){
filterParams.temporalFilter = ko.toJSON(this.filter);
}
return filters_applied;
},

restoreState: function(query) {
var doQuery = false;
if ('temporalFilter' in query) {
query.temporalFilter = JSON.parse(query.temporalFilter);
this.filter.inverted(!!query.temporalFilter.inverted);
this.termFilter.addTag(this.name, this.name, this.filter.inverted);
restoreState: function() {
var query = this.query();
if (componentName in query) {
query[componentName] = JSON.parse(query[componentName]);
this.filter.inverted(!!query[componentName].inverted);
this.getFilter('term-filter').addTag(this.name, this.name, this.filter.inverted);
['fromDate', 'toDate', 'dateNodeId'].forEach(function(key) {
if (key in query.temporalFilter) {
this.filter[key](query.temporalFilter[key]);
if (key in query[componentName]) {
this.filter[key](query[componentName][key]);
}
}, this);
doQuery = true;
}
return doQuery;
},

isFromLessThanTo: function(fromDate, toDate) {
Expand All @@ -158,7 +165,7 @@ function(_, ko, moment, BaseFilter, arches) {
this.filter.dateNodeId(null);
this.filter.inverted(false);
this.dateRangeType('custom');
this.termFilter.removeTag(this.name);
this.getFilter('term-filter').removeTag(this.name);
this.selectedPeriod(null);
return;
}
Expand Down
14 changes: 10 additions & 4 deletions arches/app/search/components/term_filter.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from arches.app.models.concept import Concept
from arches.app.utils.betterJSONSerializer import JSONDeserializer
from arches.app.search.elasticsearch_dsl_builder import Bool, Match, Query, Nested, Term, Terms, GeoShape, Range, MinAgg, MaxAgg, RangeAgg, Aggregation, GeoHashGridAgg, GeoBoundsAgg, FiltersAgg, NestedAgg
from arches.app.search.elasticsearch_dsl_builder import Bool, Match, Nested, Terms

details = {
"searchcomponentid": "",
Expand All @@ -21,7 +22,6 @@ class TermFilter():
def append_dsl(self, querysting_params, query_dsl, permitted_nodegroups, include_provisional):
search_query = Bool()
for term in JSONDeserializer().deserialize(querysting_params):
provisional_term_filter = Bool()
if term['type'] == 'term' or term['type'] == 'string':
string_filter = Bool()
if term['type'] == 'term':
Expand All @@ -30,7 +30,7 @@ def append_dsl(self, querysting_params, query_dsl, permitted_nodegroups, include
string_filter.should(Match(field='strings.string', query=term['value'], type='phrase_prefix'))
string_filter.should(Match(field='strings.string.folded', query=term['value'], type='phrase_prefix'))

if include_provisional == False:
if include_provisional is False:
string_filter.must_not(Match(field='strings.provisional', query='true', type='phrase'))
elif include_provisional == 'only provisional':
string_filter.must_not(Match(field='strings.provisional', query='false', type='phrase'))
Expand All @@ -49,7 +49,7 @@ def append_dsl(self, querysting_params, query_dsl, permitted_nodegroups, include
conceptid_filter.filter(Terms(field='domains.conceptid', terms=concept_ids))
conceptid_filter.filter(Terms(field='domains.nodegroup_id', terms=permitted_nodegroups))

if include_provisional == False:
if include_provisional is False:
conceptid_filter.must_not(Match(field='domains.provisional', query='true', type='phrase'))
elif include_provisional == 'only provisional':
conceptid_filter.must_not(Match(field='domains.provisional', query='false', type='phrase'))
Expand All @@ -62,3 +62,9 @@ def append_dsl(self, querysting_params, query_dsl, permitted_nodegroups, include

query_dsl.add_query(search_query)


def _get_child_concepts(conceptid):
ret = set([conceptid])
for row in Concept().get_child_concepts(conceptid, ['prefLabel']):
ret.add(row[0])
return list(ret)
84 changes: 83 additions & 1 deletion arches/app/search/components/time_filter.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
from datetime import datetime
from arches.app.utils.date_utils import ExtendedDateFormat
from arches.app.utils.betterJSONSerializer import JSONDeserializer
from arches.app.search.elasticsearch_dsl_builder import Bool, Nested, Term, Terms, Range

details = {
"searchcomponentid": "",
"name": "Time Filter",
Expand All @@ -16,4 +21,81 @@
class TimeFilter():

def append_dsl(self, querysting_params, query_dsl, permitted_nodegroups, include_provisional):
pass
search_query = Bool()
temporal_filter = JSONDeserializer().deserialize(querysting_params)
if 'fromDate' in temporal_filter and 'toDate' in temporal_filter:
#now = str(datetime.utcnow())
start_date = ExtendedDateFormat(temporal_filter['fromDate'])
end_date = ExtendedDateFormat(temporal_filter['toDate'])
date_nodeid = str(temporal_filter['dateNodeId']) if 'dateNodeId' in temporal_filter and temporal_filter['dateNodeId'] != '' else None
query_inverted = False if 'inverted' not in temporal_filter else temporal_filter['inverted']

temporal_query = Bool()

if query_inverted:
# inverted date searches need to use an OR clause and are generally more complicated to structure (can't use ES must_not)
# eg: less than START_DATE OR greater than END_DATE
inverted_date_query = Bool()
inverted_date_ranges_query = Bool()

if start_date.is_valid():
inverted_date_query.should(Range(field='dates.date', lt=start_date.lower))
inverted_date_ranges_query.should(Range(field='date_ranges.date_range', lt=start_date.lower))
if end_date.is_valid():
inverted_date_query.should(Range(field='dates.date', gt=end_date.upper))
inverted_date_ranges_query.should(Range(field='date_ranges.date_range', gt=end_date.upper))

date_query = Bool()
date_query.filter(inverted_date_query)
date_query.filter(Terms(field='dates.nodegroup_id', terms=permitted_nodegroups))

if include_provisional is False:
date_query.filter(Terms(field='dates.provisional', terms=['false']))

elif include_provisional == 'only provisional':
date_query.filter(Terms(field='dates.provisional', terms=['true']))

if date_nodeid:
date_query.filter(Term(field='dates.nodeid', term=date_nodeid))
else:
date_ranges_query = Bool()
date_ranges_query.filter(inverted_date_ranges_query)
date_ranges_query.filter(Terms(field='date_ranges.nodegroup_id', terms=permitted_nodegroups))

if include_provisional is False:
date_ranges_query.filter(Terms(field='date_ranges.provisional', terms=['false']))

elif include_provisional == 'only provisional':
date_ranges_query.filter(Terms(field='date_ranges.provisional', terms=['true']))

temporal_query.should(Nested(path='date_ranges', query=date_ranges_query))
temporal_query.should(Nested(path='dates', query=date_query))

else:
date_query = Bool()
date_query.filter(Range(field='dates.date', gte=start_date.lower, lte=end_date.upper))
date_query.filter(Terms(field='dates.nodegroup_id', terms=permitted_nodegroups))

if include_provisional is False:
date_query.filter(Terms(field='dates.provisional', terms=['false']))
elif include_provisional == 'only provisional':
date_query.filter(Terms(field='dates.provisional', terms=['true']))

if date_nodeid:
date_query.filter(Term(field='dates.nodeid', term=date_nodeid))
else:
date_ranges_query = Bool()
date_ranges_query.filter(Range(field='date_ranges.date_range', gte=start_date.lower, lte=end_date.upper, relation='intersects'))
date_ranges_query.filter(Terms(field='date_ranges.nodegroup_id', terms=permitted_nodegroups))

if include_provisional is False:
date_ranges_query.filter(Terms(field='date_ranges.provisional', terms=['false']))
if include_provisional == 'only provisional':
date_ranges_query.filter(Terms(field='date_ranges.provisional', terms=['true']))

temporal_query.should(Nested(path='date_ranges', query=date_ranges_query))
temporal_query.should(Nested(path='dates', query=date_query))

search_query.filter(temporal_query)

query_dsl.add_query(search_query)
2 changes: 1 addition & 1 deletion arches/app/templates/views/search.htm
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
<div class="" data-bind="foreach: {data: sharedStateObject.filtersList, as: 'filter'}">
<!-- ko if: filter.type === 'filter' && filter.enabled -->
{% if user|can_read_resource_instance %}
<button class="btn search-type-btn relative" data-bind="css: {'active': $parent.sharedStateObject.selectedTab() === filter.componentname}, click: function(){sharedStateObject.selectedTab(filter.componentname)}">
<button class="btn search-type-btn relative" data-bind="css: {'active': $parent.sharedStateObject.selectedTab() === filter.componentname}, click: function(){$parent.sharedStateObject.selectedTab(filter.componentname)}">
<i class="fa fa-code-fork"></i>
<p data-bind="text: filter.name"></p>
</button>
Expand Down
Loading

0 comments on commit 8703a0b

Please sign in to comment.