Commit 9a847ade authored by Romain Courteaud's avatar Romain Courteaud

[erp5_hal_json_style] Add the group_by argument

Allow to query the catalog with the group_by parameter.
parent 4ce772ee
......@@ -22,6 +22,7 @@ return context.ERP5Document_getHateoas(
default_param_json=default_param_json,
form_relative_url=form_relative_url,
bulk_list=bulk_list,
group_by=group_by,
sort_on=sort_on,
local_roles=local_roles,
selection_domain=selection_domain,
......
......@@ -50,7 +50,7 @@
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>REQUEST=None, response=None, view=None, mode=\'root\', query=None, select_list=None, limit=10, local_roles=None, form=None, form_data=None, relative_url=None, list_method=None, default_param_json=None, form_relative_url=None, bulk_list="[]", sort_on=None, selection_domain=None, extra_param_json=None, portal_status_message=\'\', portal_status_level=None</string> </value>
<value> <string>REQUEST=None, response=None, view=None, mode=\'root\', query=None, select_list=None, limit=10, local_roles=None, form=None, form_data=None, relative_url=None, list_method=None, default_param_json=None, form_relative_url=None, bulk_list="[]", group_by=None, sort_on=None, selection_domain=None, extra_param_json=None, portal_status_message=\'\', portal_status_level=None</string> </value>
</item>
<item>
<key> <string>id</string> </key>
......
......@@ -293,7 +293,7 @@ url_template_dict = {
# Search template will call standard "searchValues" on a document described by `root_url`
"search_template": "%(root_url)s/%(script_id)s?mode=search" + \
"{&query,select_list*,limit*,sort_on*,local_roles*,selection_domain*}",
"{&query,select_list*,limit*,group_by*,sort_on*,local_roles*,selection_domain*}",
"worklist_template": "%(root_url)s/%(script_id)s?mode=worklist",
# Custom search comes with Listboxes where "list_method" is specified. We pass even listbox's
# own URL so the search can resolve template fields for proper rendering/formatting/editability
......@@ -305,7 +305,7 @@ url_template_dict = {
"&list_method=%(list_method)s" \
"&extra_param_json=%(extra_param_json)s" \
"&default_param_json=%(default_param_json)s" \
"{&query,select_list*,limit*,sort_on*,local_roles*,selection_domain*}",
"{&query,select_list*,limit*,group_by*,sort_on*,local_roles*,selection_domain*}",
# Non-editable searches suppose the search results will be rendered as-is and no template
# fields will get involved. Unfortunately, fields need to be resolved because of formatting
# all the time so we abandoned this no_editable version
......@@ -313,7 +313,7 @@ url_template_dict = {
"&relative_url=%(relative_url)s" \
"&list_method=%(list_method)s" \
"&default_param_json=%(default_param_json)s" \
"{&query,select_list*,limit*,sort_on*,local_roles*,selection_domain*}",
"{&query,select_list*,limit*,group_by*,sort_on*,local_roles*,selection_domain*}",
"new_content_action": "%(root_url)s/%(script_id)s?mode=newContent",
"bulk_action": "%(root_url)s/%(script_id)s?mode=bulk",
# XXX View is set by default to empty
......@@ -1591,6 +1591,7 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None,
catalog_kw = {
"local_roles": local_roles,
"group_by_list": None,
"sort_on": () # default is an empty tuple
}
if default_param_json is not None:
......@@ -1636,6 +1637,14 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None,
else:
catalog_kw['sort_on'] = [parseSortOn(sort_on), ]
if group_by is not None:
if isinstance(group_by, list):
catalog_kw['group_by_list'] = group_by
else:
catalog_kw['group_by_list'] = [str(group_by)]
# Include select, as user may want to count
catalog_kw["select_list"] = select_list
if limit:
catalog_kw["limit"] = limit
if is_rendering_listbox and not has_listbox_a_count_method:
......@@ -1724,6 +1733,8 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None,
'_selection_domain': selection_domain,
'_limit': limit,
'_select_list': select_list,
'_group_by': group_by,
'_sort_on': sort_on,
'_embedded': {}
})
......
......@@ -56,7 +56,7 @@
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>REQUEST=None, response=None, view=None, mode=\'root\', query=None, select_list=None, limit=10, local_roles=None, form=None, form_data=None, relative_url=None, restricted=0, list_method=None, default_param_json=None, form_relative_url=None, bulk_list="[]", sort_on=None, selection_domain=None, extra_param_json=None, portal_status_message=\'\', portal_status_level=None</string> </value>
<value> <string>REQUEST=None, response=None, view=None, mode=\'root\', query=None, select_list=None, limit=10, local_roles=None, form=None, form_data=None, relative_url=None, restricted=0, list_method=None, default_param_json=None, form_relative_url=None, bulk_list="[]", group_by=None, sort_on=None, selection_domain=None, extra_param_json=None, portal_status_message=\'\', portal_status_level=None</string> </value>
</item>
<item>
<key> <string>id</string> </key>
......
......@@ -417,7 +417,7 @@ class TestERP5Document_getHateoas_mode_root(ERP5HALJSONStyleSkinsMixin):
self.assertEqual(result_dict['_links']['type']['name'], document.getPortalType())
self.assertEqual(result_dict['_links']['raw_search']['href'],
"%s/web_site_module/hateoas/ERP5Document_getHateoas?mode=search{&query,select_list*,limit*,sort_on*,local_roles*,selection_domain*}" % self.portal.absolute_url())
"%s/web_site_module/hateoas/ERP5Document_getHateoas?mode=search{&query,select_list*,limit*,group_by*,sort_on*,local_roles*,selection_domain*}" % self.portal.absolute_url())
self.assertEqual(result_dict['_links']['raw_search']['templated'], True)
self.assertEqual(result_dict['_links']['raw_search']['name'], "Raw Search")
......@@ -633,7 +633,7 @@ class TestERP5Document_getHateoas_mode_traverse(ERP5HALJSONStyleSkinsMixin):
self.assertEqual(result_dict['_embedded']['_view']['listbox']['editable_column_list'], [['id', 'ID'], ['title', 'Title'], ['quantity', 'quantity'], ['start_date', 'Date']])
self.assertEqual(result_dict['_embedded']['_view']['listbox']['sort_column_list'], [['id', 'ID'], ['title', 'Title'], ['quantity', 'Quantity'], ['start_date', 'Date']])
self.assertEqual(result_dict['_embedded']['_view']['listbox']['list_method_template'],
'%s/web_site_module/hateoas/ERP5Document_getHateoas?mode=search&relative_url=foo_module%%2F%s&form_relative_url=portal_skins/erp5_ui_test/Foo_view/listbox&list_method=objectValues&extra_param_json=eyJmb3JtX2lkIjogIkZvb192aWV3In0=&default_param_json=eyJwb3J0YWxfdHlwZSI6IFsiRm9vIExpbmUiXSwgImlnbm9yZV91bmtub3duX2NvbHVtbnMiOiB0cnVlfQ=={&query,select_list*,limit*,sort_on*,local_roles*,selection_domain*}' % (self.portal.absolute_url(), document.getId()))
'%s/web_site_module/hateoas/ERP5Document_getHateoas?mode=search&relative_url=foo_module%%2F%s&form_relative_url=portal_skins/erp5_ui_test/Foo_view/listbox&list_method=objectValues&extra_param_json=eyJmb3JtX2lkIjogIkZvb192aWV3In0=&default_param_json=eyJwb3J0YWxfdHlwZSI6IFsiRm9vIExpbmUiXSwgImlnbm9yZV91bmtub3duX2NvbHVtbnMiOiB0cnVlfQ=={&query,select_list*,limit*,group_by*,sort_on*,local_roles*,selection_domain*}' % (self.portal.absolute_url(), document.getId()))
self.assertEqual(result_dict['_embedded']['_view']['listbox']['domain_root_list'], [['foo_category', 'FooCat'], ['foo_domain', 'FooDomain'], ['not_existing_domain', 'NotExisting']])
NBSP_prefix = u'\xA0' * 4
self.assertEqual(result_dict['_embedded']['_view']['listbox']['domain_dict'], {'foo_domain': [['a', 'a'], ['%sa1' % NBSP_prefix, 'a/a1'], ['%sa2' % NBSP_prefix, 'a/a2'], ['b', 'b']], 'foo_category': [['a', 'a'], ['a/a1', 'a/a1'], ['a/a2', 'a/a2'], ['b', 'b']]})
......@@ -1059,7 +1059,7 @@ class TestERP5Document_getHateoas_mode_traverse(ERP5HALJSONStyleSkinsMixin):
self.assertEqual(result_dict['_embedded']['_view']['report_section_list'][1]['listbox']['editable_column_list'], [['time', 'Time'], ['comment', 'Comment'], ['error_message', 'Error Message']])
self.assertEqual(result_dict['_embedded']['_view']['report_section_list'][1]['listbox']['sort_column_list'], [])
self.assertEqual(result_dict['_embedded']['_view']['report_section_list'][1]['listbox']['list_method_template'],
'%s/web_site_module/hateoas/ERP5Document_getHateoas?mode=search&relative_url=foo_module%%2F%s&form_relative_url=portal_skins/erp5_core/Base_viewWorkflowHistory/listbox&list_method=Base_getWorkflowHistoryItemList&extra_param_json=eyJmb3JtX2lkIjogIkJhc2Vfdmlld1dvcmtmbG93SGlzdG9yeSJ9&default_param_json=eyJ3b3JrZmxvd19pZCI6ICJmb29fd29ya2Zsb3ciLCAiY2hlY2tlZF9wZXJtaXNzaW9uIjogIlZpZXciLCAid29ya2Zsb3dfdGl0bGUiOiAiRm9vIFdvcmtmbG93IiwgImlnbm9yZV91bmtub3duX2NvbHVtbnMiOiB0cnVlfQ=={&query,select_list*,limit*,sort_on*,local_roles*,selection_domain*}' % (self.portal.absolute_url(), document.getId()))
'%s/web_site_module/hateoas/ERP5Document_getHateoas?mode=search&relative_url=foo_module%%2F%s&form_relative_url=portal_skins/erp5_core/Base_viewWorkflowHistory/listbox&list_method=Base_getWorkflowHistoryItemList&extra_param_json=eyJmb3JtX2lkIjogIkJhc2Vfdmlld1dvcmtmbG93SGlzdG9yeSJ9&default_param_json=eyJ3b3JrZmxvd19pZCI6ICJmb29fd29ya2Zsb3ciLCAiY2hlY2tlZF9wZXJtaXNzaW9uIjogIlZpZXciLCAid29ya2Zsb3dfdGl0bGUiOiAiRm9vIFdvcmtmbG93IiwgImlnbm9yZV91bmtub3duX2NvbHVtbnMiOiB0cnVlfQ=={&query,select_list*,limit*,group_by*,sort_on*,local_roles*,selection_domain*}' % (self.portal.absolute_url(), document.getId()))
@simulate('Base_getRequestUrl', '*args, **kwargs',
......@@ -1148,6 +1148,8 @@ class TestERP5Document_getHateoas_mode_search(ERP5HALJSONStyleSkinsMixin):
self.assertEqual(result_dict['_query'], None)
self.assertEqual(result_dict['_local_roles'], None)
self.assertEqual(result_dict['_select_list'], [])
self.assertEqual(result_dict['_group_by'], None)
self.assertEqual(result_dict['_sort_on'], None)
self.assertEqual(len(result_dict['_embedded']['contents']), 10)
self.assertEqual(result_dict['_embedded']['contents'][0]["_links"]["self"]["href"][:12], "urn:jio:get:")
......@@ -1174,6 +1176,8 @@ class TestERP5Document_getHateoas_mode_search(ERP5HALJSONStyleSkinsMixin):
self.assertEqual(result_dict['_query'], None)
self.assertEqual(result_dict['_local_roles'], None)
self.assertEqual(result_dict['_select_list'], [])
self.assertEqual(result_dict['_group_by'], None)
self.assertEqual(result_dict['_sort_on'], None)
self.assertEqual(len(result_dict['_embedded']['contents']), 1)
self.assertEqual(result_dict['_embedded']['contents'][0]["_links"]["self"]["href"][:12], "urn:jio:get:")
......@@ -1256,11 +1260,44 @@ class TestERP5Document_getHateoas_mode_search(ERP5HALJSONStyleSkinsMixin):
self.assertEqual(result_dict['_query'], None)
self.assertEqual(result_dict['_local_roles'], ["Assignor", "Assignee"])
self.assertEqual(result_dict['_select_list'], [])
self.assertEqual(result_dict['_group_by'], None)
self.assertEqual(result_dict['_sort_on'], None)
self.assertEqual(len(result_dict['_embedded']['contents']), 0)
# No count if not in the listbox context currently
self.assertEqual(result_dict['_embedded'].get('count', None), None)
@simulate('Base_getRequestUrl', '*args, **kwargs',
'return "http://example.org/bar"')
@simulate('Base_getRequestHeader', '*args, **kwargs',
'return "application/hal+json"')
@changeSkin('Hal')
def test_getHateoas_group_by_param(self):
fake_request = do_fake_request("GET")
result = self.portal.web_site_module.hateoas.ERP5Document_getHateoas(REQUEST=fake_request, mode="search",
select_list=['count(*)'],
query='portal_type:"Base Category"',
group_by=["portal_type"])
self.assertEquals(fake_request.RESPONSE.status, 200)
self.assertEquals(fake_request.RESPONSE.getHeader('Content-Type'),
"application/hal+json"
)
result_dict = json.loads(result)
self.assertEqual(result_dict['_links']['self'], {"href": "http://example.org/bar"})
self.assertEqual(result_dict['_debug'], "search")
self.assertEqual(result_dict['_limit'], 10)
self.assertEqual(result_dict['_query'], 'portal_type:"Base Category"')
self.assertEqual(result_dict['_local_roles'], None)
self.assertEqual(result_dict['_select_list'], ['count(*)'])
self.assertEqual(result_dict['_group_by'], ["portal_type"])
self.assertEqual(result_dict['_sort_on'], None)
self.assertEqual(len(result_dict['_embedded']['contents']), 1)
self.assertTrue(10 < result_dict['_embedded']['contents'][0]['count(*)'] < 1000)
# No count if not in the listbox context currently
self.assertEqual(result_dict['_embedded'].get('count', None), None)
@simulate('Base_getRequestUrl', '*args, **kwargs',
'return "http://example.org/bar"')
@simulate('Base_getRequestHeader', '*args, **kwargs',
......@@ -1282,6 +1319,8 @@ class TestERP5Document_getHateoas_mode_search(ERP5HALJSONStyleSkinsMixin):
self.assertEqual(result_dict['_local_roles'], None)
self.assertEqual(result_dict['_selection_domain'], '{"foo_category": "a/a2"}')
self.assertEqual(result_dict['_select_list'], [])
self.assertEqual(result_dict['_group_by'], None)
self.assertEqual(result_dict['_sort_on'], None)
self.assertEqual(len(result_dict['_embedded']['contents']), 1)
self.assertEqual(result_dict['_embedded']['contents'][0]["_links"]["self"]["href"], "urn:jio:get:portal_categories/foo_category/a/a2")
......@@ -1310,6 +1349,8 @@ class TestERP5Document_getHateoas_mode_search(ERP5HALJSONStyleSkinsMixin):
self.assertEqual(result_dict['_local_roles'], None)
self.assertEqual(result_dict['_selection_domain'], '{"foo_domain": "a/a1"}')
self.assertEqual(result_dict['_select_list'], [])
self.assertEqual(result_dict['_group_by'], None)
self.assertEqual(result_dict['_sort_on'], None)
self.assertEqual(len(result_dict['_embedded']['contents']), 1)
self.assertEqual(result_dict['_embedded']['contents'][0]["_links"]["self"]["href"], "urn:jio:get:portal_categories/foo_category/a/a1")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment