Skip to content

Commit

Permalink
Allow to filter changesets by osm tags with OR condition (#627)
Browse files Browse the repository at this point in the history
* Allow to filter changesets by osm tags with OR condition

* Fix tests

* Another test fix
  • Loading branch information
willemarcel authored Nov 25, 2022
1 parent 24f0cf7 commit 85c6647
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 6 deletions.
25 changes: 24 additions & 1 deletion osmchadjango/changeset/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,14 @@ class ChangesetFilter(GeoFilterSet):
values. To query by any value use key=*.
"""
)
all_tag_changes = filters.CharFilter(
field_name='tag_changes',
method='filter_all_tag_changes',
help_text="""Filter changesets by the tag_changes field using the AND logic. It supports a
combination of OSM tags and will query using both the old and new
values. To query by any value use key=*.
"""
)

def get_past_n_days(self, queryset, field_name, value):
start_date = date.today() - timedelta(days=int(value))
Expand All @@ -281,7 +289,7 @@ def split_values(self, value):
if len(t.split('=')) == 2
]

def filter_tag_changes(self, queryset, name, value):
def filter_all_tag_changes(self, queryset, name, value):
for query in self.split_values(value):
if query[1] == '*':
key = 'tag_changes__has_key'
Expand All @@ -292,6 +300,21 @@ def filter_tag_changes(self, queryset, name, value):
queryset = queryset.filter(**{key: query[1]})
return queryset

def filter_tag_changes(self, queryset, name, value):
or_condition = Q()
keys = []
for query in self.split_values(value):
if query[1] == '*':
keys.append(query[0])
else:
key = 'tag_changes__{}__contains'.format(query[0])
or_condition.add(Q(**{key: query[1]}), Q.OR)
if len(keys):
or_condition.add(Q(**{'tag_changes__has_any_keys': keys}), Q.OR)

queryset = queryset.filter(or_condition)
return queryset

def filter_metadata(self, queryset, name, value):
for query in self.split_values(value):
if '__' in query[0]:
Expand Down
27 changes: 22 additions & 5 deletions osmchadjango/changeset/tests/test_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,17 +399,34 @@ def test_metadata_filter(self):
self.assertEqual(ChangesetFilter({'metadata': 'wrongtag__min=abc'}).qs.count(), 0)
self.assertEqual(ChangesetFilter({'metadata': 'closed:improveosm=*'}).qs.count(), 1)

def test_all_tag_changes_filter(self):
self.assertEqual(ChangesetFilter({'all_tag_changes': 'amenity=*'}).qs.count(), 1)
self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=*'}).qs.count(), 2)
self.assertEqual(ChangesetFilter({'all_tag_changes': 'surface=grass'}).qs.count(), 1)
self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=primary'}).qs.count(), 1)
self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=tertiary'}).qs.count(), 2)
self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=tertiary_link'}).qs.count(), 1)
self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=tertiary,name=*'}).qs.count(), 1)
self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=tertiary_link,surface=*'}).qs.count(), 1)
self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=tertiary_link,name=Sky'}).qs.count(), 0)
self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=tertiary_link,highway=primary'}).qs.count(), 0)

def test_tag_changes_filter(self):
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=*'}).qs.count(), 2)
# with one tag, the result is the same as all_tag_changes
self.assertEqual(ChangesetFilter({'tag_changes': 'amenity=*'}).qs.count(), 1)
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=*'}).qs.count(), 2)
self.assertEqual(ChangesetFilter({'tag_changes': 'surface=grass'}).qs.count(), 1)
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=primary'}).qs.count(), 1)
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary'}).qs.count(), 2)
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary_link'}).qs.count(), 1)
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary,name=*'}).qs.count(), 1)
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary_link,surface=*'}).qs.count(), 1)
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary_link,name=Sky'}).qs.count(), 0)
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary_link,highway=primary'}).qs.count(), 0)
# with multiple tags, it filters using the OR condition
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary_link,highway=primary'}).qs.count(), 2)
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary,surface=*'}).qs.count(), 2)
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary_link,name=Sky'}).qs.count(), 1)
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary_link,highway=primary'}).qs.count(), 2)
self.assertEqual(ChangesetFilter({'tag_changes': 'name=Store,surface=paved'}).qs.count(), 3)
self.assertEqual(ChangesetFilter({'tag_changes': 'landuse=residential,waterway=river'}).qs.count(), 0)



class TestChangesetAreaLowerThan(TestCase):
Expand Down

0 comments on commit 85c6647

Please sign in to comment.