Skip to content

Commit

Permalink
#141: Fix bug on IN operation of WHERE filter with single element value
Browse files Browse the repository at this point in the history
- This change fixes a bug where if a value used for a WHERE filter with an IN operation had only a single element in a list, it would cause a JPQL error. This happened because the list was converted into a tuple (to satisfy JPQL formatting of array based data). With single element tuples, Python adds a trailing comma, something which is invalid in JPQL. The value is now converted into a string, with the square brackets being replaced with normal brackets before being sent off to JPQL.
- Also added type checking on the value if an IN operation is used to ensure the value is a list
  • Loading branch information
MRichards99 committed Aug 27, 2020
1 parent 2d7eeff commit 2aea37c
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 3 deletions.
9 changes: 9 additions & 0 deletions common/filters.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from abc import ABC, abstractmethod
import logging

from common.exceptions import BadRequestError

log = logging.getLogger()


Expand All @@ -27,6 +29,13 @@ def __init__(self, field, value, operation):
self.value = value
self.operation = operation

if self.operation == "in":
if not isinstance(self.value, list):
raise BadRequestError(
"When using the 'in' operation for a WHERE filter, the values must"
" be in a list format e.g. [1, 2, 3]"
)

def _extract_filter_fields(self, field):
fields = field.split(".")
include_depth = len(fields)
Expand Down
11 changes: 8 additions & 3 deletions common/icat/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ def apply_filter(self, query):
elif self.operation == "gte":
where_filter = self.create_condition(self.field, ">=", self.value)
elif self.operation == "in":
where_filter = self.create_condition(self.field, "in", tuple(self.value))
# Convert self.value into a string with brackets equivalent to tuple format.
# Cannot convert straight to tuple as single element tuples contain a
# trailing comma which Python ICAT/JPQL doesn't accept
self.value = str(self.value).replace("[", "(").replace("]", ")")
where_filter = self.create_condition(self.field, "in", self.value)
else:
raise FilterError(f"Bad operation given to where filter: {self.operation}")

Expand Down Expand Up @@ -65,9 +69,10 @@ def create_condition(attribute_name, operator, value):
"""

conditions = {}
# Removing quote marks when doing conditions with IN expressions
# Removing quote marks when doing conditions with IN expressions or when a
# distinct filter is used in a request
jpql_value = (
f"{value}" if isinstance(value, tuple) or operator == "!=" else f"'{value}'"
f"{value}" if operator == "in" or operator == "!=" else f"'{value}'"
)
conditions[attribute_name] = f"{operator} {jpql_value}"
log.debug("Conditions in ICAT where filter, %s", conditions)
Expand Down

0 comments on commit 2aea37c

Please sign in to comment.