Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
657c2a3
Add aggregation and precision values to the V1_PARAMETERS_LIST
mazursasha1990 Jan 23, 2025
873086b
Add add_specific_queries to the builders and move methods related to …
mazursasha1990 Jan 23, 2025
c60f32a
Add aggregation_data list to the opensearch response if it present
mazursasha1990 Jan 23, 2025
66d7c8d
Merge branch 'main' into OSDEV-1581-add-geohex-grid-aggregation-suppo…
mazursasha1990 Jan 23, 2025
779726f
Add cooment line to the add_specific_queries of ModerationEventsQuery…
mazursasha1990 Jan 23, 2025
fa7d987
Add tests for ProductionLocationsQueryBuilder
mazursasha1990 Jan 24, 2025
0dd3ffe
Fix opensearch response object
mazursasha1990 Jan 24, 2025
30fd3db
Add test_prepare_opensearch_response_with_aggregation_data test case
mazursasha1990 Jan 24, 2025
44bd1da
Add additional test cases for ProductionLocationsQueryBuilder
mazursasha1990 Jan 24, 2025
a258184
Remove rudundand import of unittest from test_production_locations_qu…
mazursasha1990 Jan 24, 2025
f4f1f1a
Add additional test cases for TestProductionLocationsQueryBuilder
mazursasha1990 Jan 24, 2025
2fe7276
Fix linter issue
mazursasha1990 Jan 24, 2025
e6ee9fa
Add integration test_production_locations_aggregations test case
mazursasha1990 Jan 24, 2025
442482f
Add default precision value and modify test cases
mazursasha1990 Jan 24, 2025
a0df1a0
Remove test_add_aggregations_without_precision test case
mazursasha1990 Jan 24, 2025
f88903b
Add test_add_specific_queries_with_aggregation_only test case and add…
mazursasha1990 Jan 25, 2025
382d5e4
Add validation for aggregation and precision parameters
mazursasha1990 Jan 25, 2025
96b046a
Change implementation of __add_aggregations method and change tests f…
mazursasha1990 Jan 26, 2025
c5958f8
Add test cases related to the aggregation and precision parameters to…
mazursasha1990 Jan 27, 2025
ee12ffd
Add address and description fields to the ProductionLocationsSerializer
mazursasha1990 Jan 27, 2025
0114f6c
Change title() to capitalize() for error messages and fix tests
mazursasha1990 Jan 27, 2025
3954031
Replace the unused local variable serialized_params with _ in the tes…
mazursasha1990 Jan 27, 2025
784ea15
Fix tests
mazursasha1990 Jan 27, 2025
832e3c4
Fix spelling mistake in the test_invalid_moderation_id
mazursasha1990 Jan 28, 2025
0ed37f8
Add max value for precision
mazursasha1990 Jan 28, 2025
87b6f7c
Add release notes
mazursasha1990 Jan 28, 2025
31dfd1f
Change the structure of response if aggregations are present
mazursasha1990 Jan 28, 2025
875af2f
Rename parameter precision to geohex_grid_precision
mazursasha1990 Jan 28, 2025
93c5248
Rename valid value for parameter aggregation from hexgrid to geohex_grid
mazursasha1990 Jan 28, 2025
bd31809
Update the release notes
mazursasha1990 Jan 28, 2025
80c4645
Fix tests
mazursasha1990 Jan 28, 2025
16e5d1b
Remove add_specific_queries method and use add_multi_match and add_ag…
mazursasha1990 Jan 28, 2025
61b0fb9
Remove commented code
mazursasha1990 Jan 28, 2025
a38dae2
Add empty line in the end of test_production_locations_query_builder.py
mazursasha1990 Jan 28, 2025
675acd9
Refactor the add_aggregations method
mazursasha1990 Jan 28, 2025
68442df
Refactor OpenSearchQueryDirector to avoid cognitive complexity error
mazursasha1990 Jan 29, 2025
5a9790a
Fix __process_multi_match
mazursasha1990 Jan 29, 2025
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
2 changes: 1 addition & 1 deletion doc/release/RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html
* *Describe schema changes here.*

### Code/API changes
* *Describe code/API changes here.*
* [OSDEV-1581](https://opensupplyhub.atlassian.net/browse/OSDEV-1581) - Added support for Geohex grid aggregation to the GET `/api/v1/production-locations/` endpoint. To receive the Geohex grid aggregation list in the response, it is necessary to pass the `aggregation` parameter with a value of `geohex_grid` and optionally specify `geohex_grid_precision` with an integer between 0 and 15. If `geohex_grid_precision` is not defined, the default value of 5 will be used.

### Architecture/Environment changes
* *Describe architecture/environment changes here.*
Expand Down
11 changes: 11 additions & 0 deletions src/django/api/serializers/v1/production_locations_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
class ProductionLocationsSerializer(Serializer):
# These params are checking considering serialize_params output
size = IntegerField(required=False)
address = CharField(required=False)
description = CharField(required=False)
number_of_workers_min = IntegerField(required=False)
number_of_workers_max = IntegerField(required=False)
percent_female_workers_min = FloatField(required=False)
Expand All @@ -45,6 +47,15 @@ class ProductionLocationsSerializer(Serializer):
choices=['asc', 'desc'],
required=False
)
aggregation = ChoiceField(
choices=['geohex_grid'],
required=False,
)
geohex_grid_precision = IntegerField(
min_value=0,
max_value=15,
required=False,
)

def validate(self, data):
validators = [
Expand Down
19 changes: 17 additions & 2 deletions src/django/api/services/opensearch/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,26 @@ def __prepare_opensearch_response(self, response):
else:
logger.warning(f"Missing '_source' in hit: {hit}")

return {
response_data = {
"count": total_hits,
"data": data
"data": data,
}

geohex_buckets = (
response.get("aggregations", {})
.get("grouped", {})
.get("buckets", [])
)

if geohex_buckets:
response_data.update({
"aggregations": {
"geohex_grid": geohex_buckets
}
})

return response_data

@staticmethod
def __remove_null_values(obj):
if isinstance(obj, dict):
Expand Down
20 changes: 15 additions & 5 deletions src/django/api/tests/test_moderation_events_query_builder.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import unittest
from django.test import TestCase
from api.views.v1.opensearch_query_builder. \
moderation_events_query_builder import ModerationEventsQueryBuilder
Expand Down Expand Up @@ -88,6 +87,21 @@ def test_add_sort(self):
expected = {'created_at': {'order': 'asc'}}
self.assertIn(expected, self.builder.query_body['sort'])

def test_add_sort_with_default_order(self):
self.builder.add_sort('created_at')
expected = {'created_at': {'order': 'desc'}}
self.assertIn(expected, self.builder.query_body['sort'])

def test_add_sort_name(self):
self.builder.add_sort('name', 'asc')
expected = {'cleaned_data.name': {'order': 'asc'}}
self.assertIn(expected, self.builder.query_body['sort'])

def test_add_sort_address(self):
self.builder.add_sort('address', 'asc')
expected = {'cleaned_data.address': {'order': 'asc'}}
self.assertIn(expected, self.builder.query_body['sort'])

def test_add_sort_country(self):
self.builder.add_sort('country', 'asc')
expected = {'cleaned_data.country.name': {'order': 'asc'}}
Expand Down Expand Up @@ -121,7 +135,3 @@ def test_get_final_query_body(self):
'sort': []
}
self.assertEqual(final_query, expected)


if __name__ == '__main__':
unittest.main()
41 changes: 41 additions & 0 deletions src/django/api/tests/test_opensearch_response_formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,47 @@ def test_prepare_opensearch_response_rename_lon_field(self, mock_logger):
self.assertEqual(result, expected_result)
mock_logger.warning.assert_not_called()

@patch('api.services.opensearch.search.logger')
def test_prepare_opensearch_response_with_aggregation_data(
self,
mock_logger
):
response = {
"hits": {
"total": {"value": 10},
"hits": [
{"_source": {"field1": "value1"}},
{"_source": {"field2": "value2"}}
]
},
"aggregations": {
"grouped": {
"buckets": [
{"key": "value1"},
{"key": "value2"}
]
}
}
}
expected_result = {
"count": 10,
"data": [
{"field1": "value1"},
{"field2": "value2"}
],
"aggregations": {
"geohex_grid": [
{"key": "value1"},
{"key": "value2"}
]
}
}

result = self.service. \
_OpenSearchService__prepare_opensearch_response(response)
self.assertEqual(result, expected_result)
mock_logger.warning.assert_not_called()


if __name__ == '__main__':
unittest.main()
73 changes: 56 additions & 17 deletions src/django/api/tests/test_production_locations_query_builder.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import unittest
from django.test import TestCase
from api.views.v1.opensearch_query_builder. \
production_locations_query_builder import ProductionLocationsQueryBuilder
Expand Down Expand Up @@ -26,20 +25,6 @@ def test_add_match(self):
self.builder.query_body['query']['bool']['must']
)

def test_add_multi_match(self):
self.builder.add_multi_match('test query')
expected = {
'multi_match': {
'query': 'test query',
'fields': ['name^2', 'address', 'description', 'local_name'],
'fuzziness': 2
}
}
self.assertIn(
expected,
self.builder.query_body['query']['bool']['must']
)

def test_add_terms_for_standard_field(self):
self.builder.add_terms('country', ['US', 'CA'])
expected = {'terms': {'country.alpha_2': ['US', 'CA']}}
Expand Down Expand Up @@ -181,6 +166,11 @@ def test_add_sort(self):
expected = {'name.keyword': {'order': 'desc'}}
self.assertIn(expected, self.builder.query_body['sort'])

def test_add_sort_with_default_order(self):
self.builder.add_sort('name')
expected = {'name.keyword': {'order': 'asc'}}
self.assertIn(expected, self.builder.query_body['sort'])

def test_add_search_after(self):
search_after_value = 'test_value'
search_after_id = 'test_id'
Expand Down Expand Up @@ -214,6 +204,55 @@ def test_get_final_query_body(self):
}
self.assertEqual(final_query, expected)

def test_add_multi_match(self):
self.builder.add_multi_match(
'test query'
)
expected = {
'multi_match': {
'query': 'test query',
'fields': ['name^2', 'address', 'description', 'local_name'],
'fuzziness': 2,
}
}
self.assertIn(
expected, self.builder.query_body['query']['bool']['must']
)

def test_add_aggregations_with_precision(self):
aggregation = 'geohex_grid'
geohex_grid_precision = 5
self.builder.add_aggregations(
aggregation,
geohex_grid_precision
)
expected = {
'grouped': {
'geohex_grid': {
'field': 'coordinates',
'precision': geohex_grid_precision
}
}
}
self.assertIn('aggregations', self.builder.query_body)
self.assertEqual(expected, self.builder.query_body['aggregations'])

def test_add_aggregations_without_precision(self):
aggregation = 'geohex_grid'
self.builder.add_aggregations(
aggregation
)
expected = {
'grouped': {
'geohex_grid': {'field': 'coordinates'}
}
}
self.assertIn('aggregations', self.builder.query_body)
self.assertEqual(expected, self.builder.query_body['aggregations'])

if __name__ == '__main__':
unittest.main()
def test_add_aggregations_where_aggregation_is_not_geohex_grid(self):
aggregation = 'test_aggregation'
self.builder.add_aggregations(
aggregation
)
self.assertNotIn('aggregations', self.builder.query_body)
Loading