Skip to content

Commit

Permalink
#145: Implement /findone for all entities
Browse files Browse the repository at this point in the history
  • Loading branch information
MRichards99 committed Sep 30, 2020
1 parent 692ac0f commit 0747c5b
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 9 deletions.
4 changes: 3 additions & 1 deletion common/icat/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
delete_entity_by_id,
get_entity_with_filters,
get_count_with_filters,
get_first_result_with_filters,
)

from common.config import config
Expand Down Expand Up @@ -91,7 +92,8 @@ def update(self, session_id, table, data):
@requires_session_id
@queries_records
def get_one_with_filters(self, session_id, table, filters):
pass
self.client.sessionId = session_id
return get_first_result_with_filters(self.client, table.__name__, filters)

@requires_session_id
@queries_records
Expand Down
59 changes: 51 additions & 8 deletions common/icat/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,12 @@ def __init__(
" suggesting an invalid argument"
)

def execute_query(self, client, return_json_formattable=False):
def execute_query(
self, client, return_json_formattable=False, return_first_value_only=False
):
"""
Execute a previously created ICAT Query object and return in the format
specified by the return_json_formattable flag
Execute the ICAT Query object and return in the format specified by the
return_json_formattable flag
:param client: ICAT client containing an authenticated user
:type client: :class:`icat.client.Client`
Expand All @@ -149,6 +151,11 @@ def execute_query(self, client, return_json_formattable=False):
whether to leave the data in a Python ICAT format (i.e. if it's going to be
manipulated at some point)
:type return_json_formattable_data: :class:`bool`
:param return_first_value_only: Flag to determine whether the query should only
return the first result in the result set. This is used for /findone
endpoints so the first result is dealt with before breaking the processing
of results and returning the first result only
:type return_first_value_only: :class:`bool`
:return: Data (of type list) from the executed query
:raises PythonICATError: If an error occurs during query execution
"""
Expand All @@ -161,7 +168,7 @@ def execute_query(self, client, return_json_formattable=False):

flat_query_includes = self.flatten_query_included_fields(self.query.includes)
mapped_distinct_fields = None

# If the query has a COUNT function applied to it, some of these steps can be
# skipped
count_query = False
Expand All @@ -187,15 +194,19 @@ def execute_query(self, client, return_json_formattable=False):
data = []

for result in query_result:
log.debug(f"Aggregate: {self.query.aggregate}")
# TODO - How to deal with distinct and count as aggregate
if not count_query:
dict_result = self.entity_to_dict(
result, flat_query_includes, mapped_distinct_fields
)
data.append(dict_result)
else:
data.append(result)

# For /findone endpoints - only need to process the first result as the
# rest won't be sent in the response
if return_first_value_only:
break

return data
else:
log.info("Query results will be returned as ICAT entities")
Expand Down Expand Up @@ -613,7 +624,7 @@ def update_entity_by_id(client, table_name, id_, new_data):
return get_entity_by_id(client, table_name, id_, True)


def get_entity_with_filters(client, table_name, filters):
def get_entity_with_filters(client, table_name, filters, return_first_value_only=False):
"""
Gets all the records of a given entity, based on the filters provided in the request
Expand All @@ -623,9 +634,15 @@ def get_entity_with_filters(client, table_name, filters):
:type table_name: :class:`str`
:param filters: The list of filters to be applied to the request
:type filters: List of specific implementations :class:`QueryFilter`
:param return_first_value_only: Flag to determine whether the query should only
return the first result in the result set. This is used for /findone
endpoints so the first result is dealt with before breaking the processing
of results and returning the first result only
:type return_first_value_only: :class:`bool`
:return: The list of records of the given entity, using the filters to restrict the
result of the query
"""
log.info("Getting entity using request's filters")

selected_entity_name = get_python_icat_entity_name(client, table_name)
query = icat_query(client, selected_entity_name)
Expand All @@ -636,7 +653,7 @@ def get_entity_with_filters(client, table_name, filters):
clear_order_filters(filter_handler.filters)
filter_handler.apply_filters(query.query)

data = query.execute_query(client, True)
data = query.execute_query(client, True, return_first_value_only)

if not data:
raise MissingRecordError("No results found")
Expand Down Expand Up @@ -723,3 +740,29 @@ def get_count_with_filters(client, table_name, filters):
else:
# Only ever 1 element in a count query result
return data[0]


def get_first_result_with_filters(client, table_name, filters):
"""
Using filters in the request, get results of the given entity, but only show the
first one to the user
:param client: ICAT client containing an authenticated user
:type client: :class:`icat.client.Client`
:param table_name: Table name to extract which entity to use
:type table_name: :class:`str`
:param filters: The list of filters to be applied to the request
:type filters: List of specific implementations :class:`QueryFilter`
:return: The first record of the given entity, using the filters to restrict the
result of the query
"""
log.info("Getting only first result of an entity, making use of filters in request")

entity_data = get_entity_with_filters(
client, table_name, filters, return_first_value_only=True
)

if not entity_data:
raise MissingRecordError("No results found")
else:
return entity_data

0 comments on commit 0747c5b

Please sign in to comment.