From 95e8c378778cd43c480b78d4315e0888f3fe9784 Mon Sep 17 00:00:00 2001 From: Matthew Richards Date: Tue, 11 Aug 2020 12:38:01 +0000 Subject: [PATCH] #142: Implement like and in expressions for WHERE filter --- common/database/helpers.py | 4 ++-- common/icat/filters.py | 21 +++++++-------------- common/icat/helpers.py | 12 ++++++------ test/test_database_helpers.py | 2 +- 4 files changed, 16 insertions(+), 23 deletions(-) diff --git a/common/database/helpers.py b/common/database/helpers.py index cf907f06..803348c3 100644 --- a/common/database/helpers.py +++ b/common/database/helpers.py @@ -6,7 +6,8 @@ from sqlalchemy import asc, desc from sqlalchemy.orm import aliased -from common.exceptions import AuthenticationError, MissingRecordError, BadFilterError, BadRequestError, MultipleIncludeError +from common.exceptions import ApiError, AuthenticationError, MissingRecordError, BadFilterError, \ + BadRequestError, MultipleIncludeError from common.models import db_models from common.models.db_models import INVESTIGATIONUSER, INVESTIGATION, INSTRUMENT, FACILITYCYCLE, \ INVESTIGATIONINSTRUMENT, FACILITY, SESSION @@ -24,7 +25,6 @@ PythonICATOrderFilter as OrderFilter, PythonICATSkipFilter as SkipFilter, PythonICATLimitFilter as LimitFilter, \ PythonICATIncludeFilter as IncludeFilter else: - # TODO - Check this works raise ApiError("Cannot select which implementation of filters to import, check the config file has a valid backend type") log = logging.getLogger() diff --git a/common/icat/filters.py b/common/icat/filters.py index cf9525bf..eb6750e0 100644 --- a/common/icat/filters.py +++ b/common/icat/filters.py @@ -13,26 +13,19 @@ def __init__(self, field, value, operation): super().__init__(field, value, operation) def apply_filter(self, query): - # Convert the properties into stuff that ICAT will accept - # Check self.field actually exists within the entity - # - - + if self.operation == "eq": - where_filter = create_condition(self.field, '=', [self.value]) + where_filter = create_condition(self.field, '=', self.value) elif self.operation == "like": - pass + where_filter = create_condition(self.field, 'like', self.value) elif self.operation == "lte": - where_filter = create_condition(self.field, '<=', [self.value]) + where_filter = create_condition(self.field, '<=', self.value) elif self.operation == "gte": - where_filter = create_condition(self.field, '>=', [self.value]) + where_filter = create_condition(self.field, '>=', self.value) elif self.operation == "in": - log.debug(f"Field: {self.field}, Type: {type(self.field)}, Value: {self.value}, Type: {type(self.value)}") - where_filter = create_condition(self.field, '=', [self.value]) - log.debug(f"IN Filter: {where_filter}") + where_filter = create_condition(self.field, 'in', tuple(self.value)) else: - raise BadFilterError( - f" Bad operation given to where filter. operation: {self.operation}") + raise BadFilterError(f"Bad operation given to where filter: {self.operation}") try: query.addConditions(where_filter) diff --git a/common/icat/helpers.py b/common/icat/helpers.py index 2187e374..bac7ab09 100644 --- a/common/icat/helpers.py +++ b/common/icat/helpers.py @@ -173,7 +173,7 @@ def get_python_icat_entity_name(client, database_table_name): return python_icat_entity_name -def create_condition(attribute_name, operator, values): +def create_condition(attribute_name, operator, value): """ Construct and return a Python dictionary containing conditions to be used in a Query object @@ -181,15 +181,15 @@ def create_condition(attribute_name, operator, values): :type attribute_name: :class:`str` :param operator: Operator to use when filtering the data :type operator: :class:`str` - :param values: What ICAT will use to filter the data - :type values: List of :class:`str` + :param value: What ICAT will use to filter the data + :type value: :class:`str` or :class:`tuple` (when using an IN expression) :return: Condition (of type :class:`dict`) ready to be added to a Python ICAT Query object """ conditions = {} - for value in values: - log.debug(f"Value: {value}") - conditions[attribute_name] = f"{operator} '{value}'" + # Removing quote marks when doing conditions with IN expressions + jpql_value = f"{value}" if isinstance(value, tuple) else f"'{value}'" + conditions[attribute_name] = f"{operator} {jpql_value}" return conditions diff --git a/test/test_database_helpers.py b/test/test_database_helpers.py index 7ceedc55..a91ea4d3 100644 --- a/test/test_database_helpers.py +++ b/test/test_database_helpers.py @@ -2,6 +2,7 @@ from common.database.helpers import QueryFilterFactory from common.config import config +from common.exceptions import ApiError backend_type = config.get_backend_type() if backend_type == "db": @@ -14,7 +15,6 @@ PythonICATOrderFilter as OrderFilter, PythonICATSkipFilter as SkipFilter, PythonICATLimitFilter as LimitFilter, \ PythonICATIncludeFilter as IncludeFilter else: - # TODO - Check this works raise ApiError("Cannot select which implementation of filters to import, check the config file has a valid backend type")