Skip to content

Commit

Permalink
Merge pull request #440 from maykinmedia/feature/414-in-operator
Browse files Browse the repository at this point in the history
✨[#414] add in operator to API
  • Loading branch information
Coperh authored Aug 30, 2024
2 parents 49eb405 + 4dc90a2 commit 590495f
Show file tree
Hide file tree
Showing 8 changed files with 70 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", _("in a list of values separated by `|`")
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
2 changes: 2 additions & 0 deletions src/objects/api/v1/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ paths:
* `lt` - lower than
* `lte` - lower than or equal to
* `icontains` - case-insensitive partial match
* `in` - in a list of values separated by `|`
`value` may not contain double underscore or comma characters.
`key` may not contain comma characters and includes double underscore only if it indicates nested attributes.
Expand Down Expand Up @@ -537,6 +538,7 @@ paths:
* `lt` - lower than
* `lte` - lower than or equal to
* `icontains` - case-insensitive partial match
* `in` - in a list of values separated by `|`
`value` may not contain double underscore or comma characters.
`key` may not contain comma characters and includes double underscore only if it indicates nested attributes.
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
2 changes: 2 additions & 0 deletions src/objects/api/v2/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ paths:
* `lt` - lower than
* `lte` - lower than or equal to
* `icontains` - case-insensitive partial match
* `in` - in a list of values separated by `|`
`value` may not contain double underscore or comma characters.
`key` may not contain comma characters and includes double underscore only if it indicates nested attributes.
Expand Down Expand Up @@ -587,6 +588,7 @@ paths:
* `lt` - lower than
* `lte` - lower than or equal to
* `icontains` - case-insensitive partial match
* `in` - in a list of values separated by `|`
`value` may not contain double underscore or comma characters.
`key` may not contain comma characters and includes double underscore only if it indicates nested attributes.
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 590495f

Please sign in to comment.