Skip to content

Commit

Permalink
✨[#414] add in operator to API
Browse files Browse the repository at this point in the history
  • Loading branch information
Coperh committed Aug 27, 2024
1 parent 79591dc commit 1522017
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/objects/api/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ class Operators(models.TextChoices):
lt = "lt", _("lower than")
lte = "lte", _("lower than or equal to")
icontains = "icontains", _("case-insensitive partial match")
in_list = "in", _("contains")
4 changes: 4 additions & 0 deletions src/objects/api/v1/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ def filter_data_attrs(self, queryset, name, value: str):
queryset = queryset.filter(
**{f"data__{variable}__icontains": str_value}
)
elif operator == "in":
# in must be a list
values = str_value.split("|")
queryset = queryset.filter(**{f"data__{variable}__in": values})

else:
# gt, gte, lt, lte operators
Expand Down
4 changes: 4 additions & 0 deletions src/objects/api/v2/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ def filter_data_attrs(self, queryset, name, value: str):
queryset = queryset.filter(
**{f"data__{variable}__icontains": str_value}
)
elif operator == "in":
# in must be a list
values = str_value.split("|")
queryset = queryset.filter(**{f"data__{variable}__in": values})

else:
# gt, gte, lt, lte operators
Expand Down
8 changes: 5 additions & 3 deletions src/objects/api/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,11 @@ def validate_data_attrs(value: str):
}
raise serializers.ValidationError(message, code=code)

if operator not in (Operators.exact, Operators.icontains) and isinstance(
string_to_value(val), str
):
if operator not in (
Operators.exact,
Operators.icontains,
Operators.in_list,
) and isinstance(string_to_value(val), str):
message = _(
"Operator `%(operator)s` supports only dates and/or numeric values"
) % {"operator": operator}
Expand Down
25 changes: 25 additions & 0 deletions src/objects/tests/v1/test_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,31 @@ def test_filter_exclude_old_records(self):
data = response.json()
self.assertEqual(len(data), 0)

def test_filter_in_string(self):
record = ObjectRecordFactory.create(
data={"name": "demo1"}, object__object_type=self.object_type
)
record2 = ObjectRecordFactory.create(
data={"name": "demo2"}, object__object_type=self.object_type
)
ObjectRecordFactory.create(
data={"name": "demo3"}, object__object_type=self.object_type
)

response = self.client.get(self.url, {"data_attrs": "name__in__demo1|demo2"})
self.assertEqual(response.status_code, status.HTTP_200_OK)

data = response.json()
self.assertEqual(len(data), 2)
self.assertEqual(
data[0]["url"],
f"http://testserver{reverse('object-detail', args=[record2.object.uuid])}",
)
self.assertEqual(
data[1]["url"],
f"http://testserver{reverse('object-detail', args=[record.object.uuid])}",
)


class FilterDateTests(TokenAuthMixin, APITestCase):
@classmethod
Expand Down
27 changes: 27 additions & 0 deletions src/objects/tests/v2/test_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,33 @@ def test_filter_date_field_gte(self):

self.assertEqual(len(data), 0)

def test_filter_in_string(self):
record = ObjectRecordFactory.create(
data={"name": "demo1"}, object__object_type=self.object_type
)
record2 = ObjectRecordFactory.create(
data={"name": "demo2"}, object__object_type=self.object_type
)
ObjectRecordFactory.create(
data={"name": "demo3"}, object__object_type=self.object_type
)

response = self.client.get(self.url, {"data_attrs": "name__in__demo1|demo2"})

self.assertEqual(response.status_code, status.HTTP_200_OK)

data = response.json()["results"]

self.assertEqual(len(data), 2)
self.assertEqual(
data[0]["url"],
f"http://testserver{reverse('object-detail', args=[record2.object.uuid])}",
)
self.assertEqual(
data[1]["url"],
f"http://testserver{reverse('object-detail', args=[record.object.uuid])}",
)


class FilterDateTests(TokenAuthMixin, APITestCase):
@classmethod
Expand Down

0 comments on commit 1522017

Please sign in to comment.