Show More
@@ -27,6 +27,16 b' from rhodecode.api.tests.utils import (' | |||
|
27 | 27 | @pytest.mark.usefixtures("testuser_api", "app") |
|
28 | 28 | class TestApiSearch(object): |
|
29 | 29 | |
|
30 | @pytest.mark.parametrize("sort_dir", [ | |
|
31 | "asc", | |
|
32 | "desc", | |
|
33 | ]) | |
|
34 | @pytest.mark.parametrize("sort", [ | |
|
35 | "xxx", | |
|
36 | "author_email", | |
|
37 | "date", | |
|
38 | "message", | |
|
39 | ]) | |
|
30 | 40 | @pytest.mark.parametrize("query, expected_hits, expected_paths", [ |
|
31 | 41 | ('todo', 23, [ |
|
32 | 42 | 'vcs/backends/hg/inmemory.py', |
@@ -55,10 +65,11 b' class TestApiSearch(object):' | |||
|
55 | 65 | 'vcs/tests/test_cli.py']), |
|
56 | 66 | ('owner:michał test', 0, []), |
|
57 | 67 | ]) |
|
58 | def test_search_content_results(self, query, expected_hits, expected_paths): | |
|
68 | def test_search_content_results(self, sort_dir, sort, query, expected_hits, expected_paths): | |
|
59 | 69 | id_, params = build_data( |
|
60 | 70 | self.apikey_regular, 'search', |
|
61 | 71 | search_query=query, |
|
72 | search_sort='{}:{}'.format(sort_dir, sort), | |
|
62 | 73 | search_type='content') |
|
63 | 74 | |
|
64 | 75 | response = api_call(self.app, params) |
@@ -70,6 +81,16 b' class TestApiSearch(object):' | |||
|
70 | 81 | for expected_path in expected_paths: |
|
71 | 82 | assert expected_path in paths |
|
72 | 83 | |
|
84 | @pytest.mark.parametrize("sort_dir", [ | |
|
85 | "asc", | |
|
86 | "desc", | |
|
87 | ]) | |
|
88 | @pytest.mark.parametrize("sort", [ | |
|
89 | "xxx", | |
|
90 | "date", | |
|
91 | "file", | |
|
92 | "size", | |
|
93 | ]) | |
|
73 | 94 | @pytest.mark.parametrize("query, expected_hits, expected_paths", [ |
|
74 | 95 | ('readme.rst', 3, []), |
|
75 | 96 | ('test*', 75, []), |
@@ -77,10 +98,11 b' class TestApiSearch(object):' | |||
|
77 | 98 | ('extension:rst', 48, []), |
|
78 | 99 | ('extension:rst api', 24, []), |
|
79 | 100 | ]) |
|
80 | def test_search_file_paths(self, query, expected_hits, expected_paths): | |
|
101 | def test_search_file_paths(self, sort_dir, sort, query, expected_hits, expected_paths): | |
|
81 | 102 | id_, params = build_data( |
|
82 | 103 | self.apikey_regular, 'search', |
|
83 | 104 | search_query=query, |
|
105 | search_sort='{}:{}'.format(sort_dir, sort), | |
|
84 | 106 | search_type='path') |
|
85 | 107 | |
|
86 | 108 | response = api_call(self.app, params) |
@@ -110,9 +110,13 b' def perform_search(request, tmpl_context' | |||
|
110 | 110 | c.search_tags = search_tags |
|
111 | 111 | |
|
112 | 112 | direction, sort_field = searcher.get_sort(search_type, search_sort) |
|
113 | c.sort = '{}:{}'.format(direction, sort_field) | |
|
114 |
c.sort |
|
|
113 | sort_definition = searcher.sort_def(search_type, direction, sort_field) | |
|
114 | c.sort = '' | |
|
115 | c.sort_tag = None | |
|
115 | 116 | c.sort_tag_dir = direction |
|
117 | if sort_definition: | |
|
118 | c.sort = '{}:{}'.format(direction, sort_field) | |
|
119 | c.sort_tag = sort_field | |
|
116 | 120 | |
|
117 | 121 | |
|
118 | 122 | class SearchView(BaseAppView): |
@@ -89,6 +89,15 b' class BaseSearcher(object):' | |||
|
89 | 89 | """ |
|
90 | 90 | return val |
|
91 | 91 | |
|
92 | def sort_def(self, search_type, direction, sort_field): | |
|
93 | """ | |
|
94 | Defines sorting for search. This function should decide if for given | |
|
95 | search_type, sorting can be done with sort_field. | |
|
96 | ||
|
97 | It also should translate common sort fields into backend specific. e.g elasticsearch | |
|
98 | """ | |
|
99 | raise NotImplementedError() | |
|
100 | ||
|
92 | 101 | @staticmethod |
|
93 | 102 | def get_sort(search_type, search_val): |
|
94 | 103 | """ |
@@ -99,6 +99,29 b' class WhooshSearcher(BaseSearcher):' | |||
|
99 | 99 | query = u'(%s) OR %s' % (query, hashes_or_query) |
|
100 | 100 | return query |
|
101 | 101 | |
|
102 | def sort_def(self, search_type, direction, sort_field): | |
|
103 | ||
|
104 | if search_type == 'commit': | |
|
105 | field_defs = { | |
|
106 | 'message': 'message', | |
|
107 | 'date': 'date', | |
|
108 | 'author_email': 'author', | |
|
109 | } | |
|
110 | elif search_type == 'path': | |
|
111 | field_defs = { | |
|
112 | 'file': 'path', | |
|
113 | 'size': 'size', | |
|
114 | 'lines': 'lines', | |
|
115 | } | |
|
116 | elif search_type == 'content': | |
|
117 | # NOTE(dan): content doesn't support any sorting | |
|
118 | field_defs = {} | |
|
119 | else: | |
|
120 | return '' | |
|
121 | ||
|
122 | if sort_field in field_defs: | |
|
123 | return field_defs[sort_field] | |
|
124 | ||
|
102 | 125 | def search(self, query, document_type, search_user, |
|
103 | 126 | repo_name=None, repo_group_name=None, |
|
104 | 127 | requested_page=1, page_limit=10, sort=None, raise_on_exc=True): |
@@ -124,21 +147,16 b' class WhooshSearcher(BaseSearcher):' | |||
|
124 | 147 | query = qp.parse(safe_unicode(query)) |
|
125 | 148 | log.debug('query: %s (%s)', query, repr(query)) |
|
126 | 149 | |
|
127 | def sort_def(_direction, _sort_field): | |
|
128 | field2whoosh = { | |
|
129 | 'message.raw': 'message', | |
|
130 | 'author.email.raw': 'author', | |
|
131 | } | |
|
132 | return field2whoosh.get(_sort_field) or _sort_field | |
|
133 | ||
|
134 | 150 | reverse, sorted_by = False, None |
|
135 | 151 | direction, sort_field = self.get_sort(search_type, sort) |
|
136 | 152 | if sort_field: |
|
137 | if direction == Searcher.DIRECTION_DESC: | |
|
138 | reverse = True | |
|
139 | if direction == Searcher.DIRECTION_ASC: | |
|
140 | reverse = False | |
|
141 | sorted_by = sort_def(direction, sort_field) | |
|
153 | sort_definition = self.sort_def(search_type, direction, sort_field) | |
|
154 | if sort_definition: | |
|
155 | sorted_by = sort_definition | |
|
156 | if direction == Searcher.DIRECTION_DESC: | |
|
157 | reverse = True | |
|
158 | if direction == Searcher.DIRECTION_ASC: | |
|
159 | reverse = False | |
|
142 | 160 | |
|
143 | 161 | whoosh_results = self.searcher.search( |
|
144 | 162 | query, filter=allowed_repos_filter, limit=None, |
@@ -69,7 +69,7 b'' | |||
|
69 | 69 | elif c.sort.startswith('desc:'): |
|
70 | 70 | return c.url_generator(sort='asc:{}'.format(field_name)) |
|
71 | 71 | |
|
72 | return 'asc:{}'.format(field_name) | |
|
72 | return c.url_generator(sort='asc:{}'.format(field_name)) | |
|
73 | 73 | %> |
|
74 | 74 | </%def> |
|
75 | 75 |
@@ -9,13 +9,13 b'' | |||
|
9 | 9 | <th>${_('Commit')}</th> |
|
10 | 10 | <th></th> |
|
11 | 11 | <th> |
|
12 |
<a href="${search.field_sort('message |
|
|
12 | <a href="${search.field_sort('message')}">${_('Commit message')}</a> | |
|
13 | 13 | </th> |
|
14 | 14 | <th> |
|
15 |
<a href="${search.field_sort('date')}">${_(' |
|
|
15 | <a href="${search.field_sort('date')}">${_('Commit date')}</a> | |
|
16 | 16 | </th> |
|
17 | 17 | <th> |
|
18 |
<a href="${search.field_sort('author |
|
|
18 | <a href="${search.field_sort('author_email')}">${_('Author')}</a> | |
|
19 | 19 | </th> |
|
20 | 20 | </tr> |
|
21 | 21 | %for entry in c.formatted_results: |
General Comments 0
You need to be logged in to leave comments.
Login now