From 8215bbca9ec1359dc1fedbf4ab24f9820689044c Mon Sep 17 00:00:00 2001 From: Scott Orr Date: Fri, 15 Mar 2019 17:56:16 -0400 Subject: [PATCH 1/3] Fixed a bug that caused a 'search' to crash if no filter was supplied. --- src/pyCoalesce/pyCoalesce/coalesce_request.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/pyCoalesce/pyCoalesce/coalesce_request.py b/src/pyCoalesce/pyCoalesce/coalesce_request.py index 0053643ce..1492145de 100644 --- a/src/pyCoalesce/pyCoalesce/coalesce_request.py +++ b/src/pyCoalesce/pyCoalesce/coalesce_request.py @@ -477,7 +477,7 @@ def _case_operators(query_fragment, fragment_is_criteria = False): # If "query" is a full query object, assign it directly as the # query ("data"). Otherwise, construct the query object. - if "group" in query: + if query and "group" in query: data = query else: @@ -488,10 +488,11 @@ def _case_operators(query_fragment, fragment_is_criteria = False): # If there's a query (filter object), add it. Otherwise, if a # "template" name was supplied (necessary if there's no query and # no recordset in "return_property_names"), add it. - if query: - data["group"] = query - elif template: - data["type"] = template + if not query: + query = {} + if template: + data["type"] = template + data["group"] = query # Add any sorting parameters. We checkfor the (deprecated) earlier # form of the sort-by input, as a dict/JSON object identical to the From da63d19a1cdafb8376f120ac12c38d9eb29b94f6 Mon Sep 17 00:00:00 2001 From: Scott Orr Date: Fri, 15 Mar 2019 18:07:31 -0400 Subject: [PATCH 2/3] Fixed the bug fix. --- src/pyCoalesce/pyCoalesce/coalesce_request.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/pyCoalesce/pyCoalesce/coalesce_request.py b/src/pyCoalesce/pyCoalesce/coalesce_request.py index 1492145de..938474eca 100644 --- a/src/pyCoalesce/pyCoalesce/coalesce_request.py +++ b/src/pyCoalesce/pyCoalesce/coalesce_request.py @@ -485,15 +485,18 @@ def _case_operators(query_fragment, fragment_is_criteria = False): data = {"pageSize": page_size, "pageNumber": page_number, "propertyNames": return_property_names} - # If there's a query (filter object), add it. Otherwise, if a - # "template" name was supplied (necessary if there's no query and - # no recordset in "return_property_names"), add it. + # If there's a query (filter object), add it. If there's no + # query, create an empty object to use as the value of "group". if not query: query = {} - if template: - data["type"] = template data["group"] = query + # If a "template" name was supplied (necessary if there's no + ## query--or a query with only coalesceEntity metadata fields-- + # and no recordset in "return_property_names"), add it. + if template: + data["type"] = template + # Add any sorting parameters. We checkfor the (deprecated) earlier # form of the sort-by input, as a dict/JSON object identical to the # form accepted by the Coalesce RESTful API. From ed36bdc772647b8fb398d1cbdd67108aec2af99b Mon Sep 17 00:00:00 2001 From: Scott Orr Date: Mon, 18 Mar 2019 22:26:53 -0400 Subject: [PATCH 3/3] Added a test for the bug fix. --- src/pyCoalesce/pyCoalesce/coalesce_request.py | 14 ++++++++++---- .../unit_tests/tests_coalesce_request.py | 7 ++++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/pyCoalesce/pyCoalesce/coalesce_request.py b/src/pyCoalesce/pyCoalesce/coalesce_request.py index 938474eca..92b0a5fdc 100644 --- a/src/pyCoalesce/pyCoalesce/coalesce_request.py +++ b/src/pyCoalesce/pyCoalesce/coalesce_request.py @@ -349,9 +349,10 @@ def search(server = None, query = None, of dict-like or JSON objects in the form `{"propertyName": ., "sortOrder": }`. A single dict-like/JSON object in the latter format will also be - accepted. For basic entity fields, such as "name" and - "dateCreated", the field name should be supplied by itself, with no - recordset. + accepted. In some circumstances (in particular, if Derby is the + default persistor), the in the case of basic entity fields, such + as "name" and "dateCreated", a field name should be supplied by + itself, with no recordset. :param sort_order: "ASC" for ascending, or "DESC" for descending. This argument is used only if "sort_by" is the name of a single field (rather than a full Coalesce "sortBy" object). @@ -506,12 +507,17 @@ def _case_operators(query_fragment, fragment_is_criteria = False): # Check for a JSON object that needs to be decoded. if isinstance(sort_by, basestring): + try: sort_by = json.loads(sort_by) # If it's a string but not decodeable, treat it as a field # name, and construct the sort-by object. This is the only - # case in which the "sort_order" argument is used. + # case in which the "sort_order" argument is used--in the + # case of multiple sort-by fields, each entry in the + # "sort_by" argument must include a "sortOrder" value (the + # API equivalent of "sort_order") as well as a + # "propertyName" value (the sort-by field name). except JSONDecodeError: sort_order = sort_order.upper() if not sort_order in SEARCH_SORT_ORDERS: diff --git a/src/pyCoalesce/unit_tests/tests_coalesce_request.py b/src/pyCoalesce/unit_tests/tests_coalesce_request.py index f07ba0c3e..57b383aab 100644 --- a/src/pyCoalesce/unit_tests/tests_coalesce_request.py +++ b/src/pyCoalesce/unit_tests/tests_coalesce_request.py @@ -34,9 +34,10 @@ SEARCH_PERSISTOR = config.get("Coalesce RESTful API server", "search_persistor") # Set other constants. +TEMPLATE1_NAME = 'TestEntity1' TEMPLATE1_XML = ' ' + \ ' ' + \ @@ -895,6 +896,10 @@ def test_search(self): results6_first_field = json.loads(results6_JSON)["hits"][0]["values"][0] self.assertEqual(results6_first_field, orig3_first_field) + results7 = search(server = self.server, query = {}, + template = TEMPLATE1_NAME) + self.assertEqual(len(results7), 1) + def test_search_simple(self):