def get_related_case_results(domain, cases, paths): """ Given a set of cases and a set of case property paths, fetches ES documents for all cases referenced by those paths. """ if not cases: return [] results_cache = {} for path in paths: current_cases = cases parts = path.split("/") for index, identifier in enumerate(parts): fragment = "/".join(parts[:index + 1]) if fragment in results_cache: current_cases = results_cache[fragment] else: indices = [ case.get_index(identifier) for case in current_cases ] related_case_ids = {i.referenced_id for i in indices if i} results = CaseSearchES().domain(domain).case_ids( related_case_ids).run().hits current_cases = [ CommCareCase.wrap(flatten_result(result)) for result in results ] results_cache[fragment] = current_cases
def get_rows(self, paged=True): location_ids = self._get_voucher_location_ids() if location_ids: vouchers = [] for location_id_chunk in chunked(location_ids, ES_MAX_CLAUSE_COUNT): vouchers += [ CommCareCase.wrap(flatten_result(result)) for result in self._search_results(paged, location_id_chunk).raw_hits ] else: vouchers = [ CommCareCase.wrap(flatten_result(result)) for result in self._search_results(paged).raw_hits ] return [row for voucher in vouchers for row in self._make_rows(voucher)]
def app_aware_search(request, domain, app_id): """ Accepts search criteria as GET params, e.g. "https://www.commcarehq.org/a/domain/phone/search/?a=b&c=d" Returns results as a fixture with the same structure as a casedb instance. """ criteria = request.GET.dict() try: case_type = criteria.pop('case_type') except KeyError: return HttpResponse('Search request must specify case type', status=400) try: case_search_criteria = CaseSearchCriteria(domain, case_type, criteria) except TooManyRelatedCasesError: return HttpResponse(_('Search has too many results. Please try a more specific search.'), status=400) search_es = case_search_criteria.search_es try: hits = search_es.run().raw_hits except Exception as e: notify_exception(request, str(e), details=dict( exception_type=type(e), )) return HttpResponse(status=500) # Even if it's a SQL domain, we just need to render the hits as cases, so CommCareCase.wrap will be fine cases = [CommCareCase.wrap(flatten_result(result, include_score=True)) for result in hits] if app_id: cases.extend(get_related_cases(domain, app_id, case_type, cases)) fixtures = CaseDBFixture(cases).fixture return HttpResponse(fixtures, content_type="text/xml; charset=utf-8")
def search(request, domain): """ Accepts search criteria as GET params, e.g. "https://www.commcarehq.org/a/domain/phone/search/?a=b&c=d" Returns results as a fixture with the same structure as a casedb instance. """ criteria = request.GET.dict() try: case_type = criteria.pop('case_type') except KeyError: return HttpResponse('Search request must specify case type', status=400) try: case_search_criteria = CaseSearchCriteria(domain, case_type, criteria) search_es = case_search_criteria.search_es except QueryMergeException as e: return _handle_query_merge_exception(request, e) try: hits = search_es.run().raw_hits except Exception as e: return _handle_es_exception( request, e, case_search_criteria.query_addition_debug_details) # Even if it's a SQL domain, we just need to render the hits as cases, so CommCareCase.wrap will be fine cases = [ CommCareCase.wrap(flatten_result(result, include_score=True)) for result in hits ] fixtures = CaseDBFixture(cases).fixture return HttpResponse(fixtures, content_type="text/xml; charset=utf-8")
def search(request, domain): """ Accepts search criteria as GET params, e.g. "https://www.commcarehq.org/a/domain/phone/search/?a=b&c=d" Returns results as a fixture with the same structure as a casedb instance. """ criteria = request.GET.dict() try: case_type = criteria.pop('case_type') except KeyError: return HttpResponse('Search request must specify case type', status=400) try: include_closed = criteria.pop('include_closed') except KeyError: include_closed = False search_es = (CaseSearchES().domain(domain).case_type(case_type).size( CASE_SEARCH_MAX_RESULTS)) if include_closed != 'True': search_es = search_es.is_closed(False) try: config = CaseSearchConfig.objects.get(domain=domain) except CaseSearchConfig.DoesNotExist as e: from corehq.util.soft_assert import soft_assert _soft_assert = soft_assert(to="{}@{}.com".format('frener', 'dimagi'), notify_admins=False, send_to_ops=False) _soft_assert( False, u"Someone in domain: {} tried accessing case search without a config" .format(domain), e) config = CaseSearchConfig(domain=domain) query_addition_id = criteria.pop(SEARCH_QUERY_ADDITION_KEY, None) fuzzies = config.config.get_fuzzy_properties_for_case_type(case_type) for key, value in criteria.items(): search_es = search_es.case_property_query(key, value, fuzzy=(key in fuzzies)) query_addition_debug_details = {} try: search_es = _add_case_search_addition(request, domain, search_es, query_addition_id, query_addition_debug_details) except QueryMergeException as e: return _handle_query_merge_exception(request, e) try: results = search_es.values() except Exception as e: return _handle_es_exception(request, e, query_addition_debug_details) # Even if it's a SQL domain, we just need to render the results as cases, so CommCareCase.wrap will be fine cases = [CommCareCase.wrap(flatten_result(result)) for result in results] fixtures = CaseDBFixture(cases).fixture return HttpResponse(fixtures, content_type="text/xml")
def test_get_related_case_results(self): # Note that cases must be defined before other cases can reference them cases = [ { '_id': 'c1', 'case_type': 'monster', 'description': 'grandparent of first person' }, { '_id': 'c2', 'case_type': 'monster', 'description': 'parent of first person', 'index': { 'parent': ('monster', 'c1') } }, { '_id': 'c3', 'case_type': 'monster', 'description': 'parent of host' }, { '_id': 'c4', 'case_type': 'monster', 'description': 'host of second person', 'index': { 'parent': ('monster', 'c3') } }, { '_id': 'c5', 'description': 'first person', 'index': { 'parent': ('monster', 'c2') } }, { '_id': 'c6', 'description': 'second person', 'index': { 'host': ('monster', 'c4') } }, ] self._bootstrap_cases_in_es_for_domain(self.domain, cases) hits = CaseSearchES().domain(self.domain).case_type( self.case_type).run().hits cases = [CommCareCase.wrap(flatten_result(result)) for result in hits] self.assertEqual({case.case_id for case in cases}, {'c5', 'c6'}) self._assert_related_case_ids(cases, set(), set()) self._assert_related_case_ids(cases, {"parent"}, {"c2"}) self._assert_related_case_ids(cases, {"host"}, {"c4"}) self._assert_related_case_ids(cases, {"parent/parent"}, {"c1"}) self._assert_related_case_ids(cases, {"host/parent"}, {"c3"}) self._assert_related_case_ids(cases, {"host", "parent"}, {"c2", "c4"}) self._assert_related_case_ids(cases, {"host", "parent/parent"}, {"c4", "c1"})
def _get_assigned_cases(checkin_case): query = (CaseSearchES().domain(checkin_case.domain).filter( filters.OR(case_type("patient"), case_type("contact"))).case_property_query( "assigned_to_primary_checkin_case_id", checkin_case.case_id)) return [CommCareCase.wrap(flatten_result(hit)) for hit in query.run().hits]
def get_rows(self, paged=True): vouchers = [ CommCareCase.wrap(flatten_result(result)) for result in self._search_results(paged).raw_hits ] return [ row for voucher in vouchers for row in self._make_rows(voucher) ]
def rows(self): track_workflow(self.request.couch_user.username, "Case List Explorer: Search Performed") send_email_to_dev_more( self.domain, self.request.couch_user.username, XpathCaseSearchFilter.get_value(self.request, self.domain), self.es_results['hits'].get('total', 0)) data = (flatten_result(row) for row in self.es_results['hits'].get('hits', [])) return self._get_rows(data)
def rows(self): track_workflow(self.request.couch_user.username, "Case List Explorer: Search Performed") send_email_to_dev_more( self.domain, self.request.couch_user.username, XpathCaseSearchFilter.get_value(self.request, self.domain), self.es_results['hits'].get('total', 0) ) data = (flatten_result(row) for row in self.es_results['hits'].get('hits', [])) return self._get_rows(data)
def get_usercase_from_checkin(checkin_case): username = checkin_case.get_case_property("username") query = (CaseSearchES().domain( checkin_case.domain).case_type(USERCASE_TYPE).case_property_query( "username", username)) results = query.run().hits if not results: return None return CommCareCase.wrap(flatten_result(results[0]))
def test_flatten_result(self): expected = {'name': 'blah', 'foo': 'bar', 'baz': 'buzz'} self.assertEqual( flatten_result( { 'name': 'blah', 'case_properties': [ {'key': 'foo', 'value': 'bar'}, {'key': 'baz', 'value': 'buzz'}] } ), expected )
def test_flatten_result(self): expected = {'name': 'blah', 'foo': 'bar', 'baz': 'buzz'} self.assertEqual( flatten_result({ 'name': 'blah', 'case_properties': [{ 'key': 'foo', 'value': 'bar' }, { 'key': 'baz', 'value': 'buzz' }] }), expected)
def _get_assigned_cases(checkin_case): """ An assigned case is a case for which all of the following are true Case type patient or contact Exists in the same domain as the user case The case property assigned_to_primary_checkin_case_id equals an associated checkin case's case_id """ query = (CaseSearchES().domain(checkin_case.domain).filter( filters.OR(case_type("patient"), case_type("contact"))).case_property_query( "assigned_to_primary_checkin_case_id", checkin_case.case_id)) return [CommCareCase.wrap(flatten_result(hit)) for hit in query.run().hits]
def test_flatten_result(self): expected = {'name': 'blah', 'foo': 'bar', 'baz': 'buzz', RELEVANCE_SCORE: "1.095"} self.assertEqual( flatten_result( { "_score": "1.095", "_source": { 'name': 'blah', 'case_properties': [ {'key': '@case_id', 'value': '123'}, {'key': 'foo', 'value': 'bar'}, {'key': 'baz', 'value': 'buzz'}] } } ), expected )
def search(request, domain): """ Accepts search criteria as GET params, e.g. "https://www.commcarehq.org/a/domain/phone/search/?a=b&c=d" Returns results as a fixture with the same structure as a casedb instance. """ criteria = request.GET.dict() try: case_type = criteria.pop('case_type') except KeyError: return HttpResponse('Search request must specify case type', status=400) try: include_closed = criteria.pop('include_closed') except KeyError: include_closed = False search_es = (CaseSearchES() .domain(domain) .case_type(case_type) .size(CASE_SEARCH_MAX_RESULTS)) if include_closed != 'True': search_es = search_es.is_closed(False) try: config = CaseSearchConfig.objects.get(domain=domain) except CaseSearchConfig.DoesNotExist as e: from corehq.util.soft_assert import soft_assert _soft_assert = soft_assert( to="{}@{}.com".format('frener', 'dimagi'), notify_admins=False, send_to_ops=False ) _soft_assert(False, "Someone in domain: {} tried accessing case search without a config".format(domain), e) config = CaseSearchConfig(domain=domain) fuzzies = config.config.get_fuzzy_properties_for_case_type(case_type) for key, value in criteria.items(): search_es = search_es.case_property_query(key, value, fuzzy=(key in fuzzies)) results = search_es.values() # Even if it's a SQL domain, we just need to render the results as cases, so CommCareCase.wrap will be fine cases = [CommCareCase.wrap(flatten_result(result)) for result in results] fixtures = CaseDBFixture(cases).fixture return HttpResponse(fixtures, content_type="text/xml")
def test_flatten_result(self): expected = {'name': 'blah', 'foo': 'bar', 'baz': 'buzz', RELEVANCE_SCORE: "1.095"} self.assertEqual( flatten_result( { "_score": "1.095", "_source": { 'name': 'blah', 'case_properties': [ {'key': '@case_id', 'value': 'should be removed'}, {'key': 'name', 'value': 'should be removed'}, {'key': 'case_name', 'value': 'should be removed'}, {'key': 'last_modified', 'value': 'should be removed'}, {'key': 'foo', 'value': 'bar'}, {'key': 'baz', 'value': 'buzz'}] } }, include_score=True ), expected )
def search(request, domain): """ Accepts search criteria as GET params, e.g. "https://www.commcarehq.org/a/domain/phone/search/?a=b&c=d" Returns results as a fixture with the same structure as a casedb instance. """ criteria = request.GET.dict() try: case_type = criteria.pop('case_type') except KeyError: return HttpResponse('Search request must specify case type', status=400) try: case_search_criteria = CaseSearchCriteria(domain, case_type, criteria) search_es = case_search_criteria.search_es except QueryMergeException as e: return _handle_query_merge_exception(request, e) try: hits = search_es.run().raw_hits except Exception as e: return _handle_es_exception(request, e, case_search_criteria.query_addition_debug_details) # Even if it's a SQL domain, we just need to render the hits as cases, so CommCareCase.wrap will be fine cases = [CommCareCase.wrap(flatten_result(result, include_score=True)) for result in hits] fixtures = CaseDBFixture(cases).fixture return HttpResponse(fixtures, content_type="text/xml; charset=utf-8")
def get_data(self): for row in self.es_results['hits'].get('hits', []): yield flatten_result(row)
def __init__(self, request, domain, raw_data): super(CaseDataFormatter, self).__init__(request, domain, raw_data) self.raw_data = flatten_result(raw_data)
def get_all_rows(self): data = (flatten_result(r) for r in iter_es_docs_from_query(self._build_query( sort=False))) return self._get_rows(data)
def rows(self): track_workflow(self.request.couch_user.username, "Case List Explorer: Search Performed") data = (flatten_result(row) for row in self.es_results['hits'].get('hits', [])) return self._get_rows(data)
def get_all_rows(self): data = (flatten_result(r) for r in iter_es_docs_from_query(self._build_query(sort=False))) return self._get_rows(data)