-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add support for customizing query generation and thereby support multiple query parsers. * Adds query factory for Elasticsearch Lucene syntax. Signed-off-by: Lars Holm Nielsen <lars.holm.nielsen@cern.ch>
- Loading branch information
Showing
3 changed files
with
174 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
# -*- coding: utf-8 -*- | ||
# | ||
# This file is part of Invenio. | ||
# Copyright (C) 2016 CERN. | ||
# | ||
# Invenio is free software; you can redistribute it | ||
# and/or modify it under the terms of the GNU General Public License as | ||
# published by the Free Software Foundation; either version 2 of the | ||
# License, or (at your option) any later version. | ||
# | ||
# Invenio is distributed in the hope that it will be | ||
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
# General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU General Public License | ||
# along with Invenio; if not, write to the | ||
# Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
# MA 02111-1307, USA. | ||
# | ||
# In applying this license, CERN does not | ||
# waive the privileges and immunities granted to it by virtue of its status | ||
# as an Intergovernmental Organization or submit itself to any jurisdiction. | ||
|
||
"""Query factories for REST API.""" | ||
|
||
from __future__ import absolute_import, print_function | ||
|
||
from flask import current_app, request | ||
from invenio_search import Query | ||
|
||
from .errors import InvalidQueryRESTError | ||
|
||
|
||
def default_query_factory(index, page, size): | ||
"""Parse and slice query using Invenio-Query-Parser. | ||
:param index: Index to search in. | ||
:param page: Requested page. | ||
:param size: Request results size. | ||
:returns: Tuple of (query, URL arguments). | ||
""" | ||
query_string = request.values.get('q', '') | ||
|
||
try: | ||
query = Query(query_string)[(page-1)*size:page*size] | ||
except SyntaxError: | ||
current_app.logger.debug( | ||
"Failed parsing query: {0}".format( | ||
request.values.get('q', '')), | ||
exc_info=True) | ||
raise InvalidQueryRESTError() | ||
|
||
return (query, {'q': query_string}) | ||
|
||
|
||
def es_query_factory(index, page, size): | ||
"""Send query directly as query string query to Elasticsearch. | ||
.. warning: | ||
All fields in a record that a user can access are searchable! This means | ||
that if a user can access a record, you cannot include confidential | ||
information into the record (or you must remove it when indexing). | ||
Otherwise a user is able to search for the information. | ||
The reason is that the query string is passed directly to Elasticsearch, | ||
which takes care of parsing the string. | ||
:param index: Index to search in. | ||
:param page: Requested page. | ||
:param size: Request results size. | ||
:returns: Tuple of (query, URL arguments). | ||
""" | ||
query_string = request.values.get('q', '') | ||
|
||
query = Query() | ||
if query_string.strip(): | ||
query.body['query'] = dict( | ||
query_string=dict( | ||
query=query_string, | ||
allow_leading_wildcard=False, | ||
) | ||
) | ||
query = query[(page-1)*size:page*size] | ||
return (query, {'q': query_string}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
# -*- coding: utf-8 -*- | ||
# | ||
# This file is part of Invenio. | ||
# Copyright (C) 2016 CERN. | ||
# | ||
# Invenio is free software; you can redistribute it | ||
# and/or modify it under the terms of the GNU General Public License as | ||
# published by the Free Software Foundation; either version 2 of the | ||
# License, or (at your option) any later version. | ||
# | ||
# Invenio is distributed in the hope that it will be | ||
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
# General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU General Public License | ||
# along with Invenio; if not, write to the | ||
# Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
# MA 02111-1307, USA. | ||
# | ||
# In applying this license, CERN does not | ||
# waive the privileges and immunities granted to it by virtue of its status | ||
# as an Intergovernmental Organization or submit itself to any jurisdiction. | ||
|
||
"""Test query factories.""" | ||
|
||
from __future__ import absolute_import, print_function | ||
|
||
import pytest | ||
|
||
from invenio_records_rest.errors import InvalidQueryRESTError | ||
from invenio_records_rest.query import default_query_factory, es_query_factory | ||
|
||
|
||
def test_default_query_factory(app, user_factory): | ||
"""Test default query factory.""" | ||
app.config.update(dict(SEARCH_QUERY_ENHANCERS=[])) | ||
with app.test_request_context("?q=test"): | ||
query, urlargs = default_query_factory('myindex', 1, 10) | ||
assert query.body['query'] == dict( | ||
multi_match=dict( | ||
fields=['_all'], | ||
query='test', | ||
)) | ||
assert query.body['from'] == 0 | ||
assert query.body['size'] == 10 | ||
assert urlargs['q'] == 'test' | ||
|
||
with app.test_request_context("?q=:"): | ||
pytest.raises( | ||
InvalidQueryRESTError, | ||
default_query_factory, 'myindex', 1, 10) | ||
|
||
|
||
def test_es_query_factory(app, user_factory): | ||
"""Test es query factory.""" | ||
app.config.update(dict(SEARCH_QUERY_ENHANCERS=[])) | ||
with app.test_request_context("?q=test"): | ||
query, urlargs = es_query_factory('myindex', 2, 20) | ||
assert query.body['query'] == dict( | ||
query_string=dict( | ||
query="test", | ||
allow_leading_wildcard=False, | ||
) | ||
) | ||
assert query.body['from'] == 20 | ||
assert query.body['size'] == 20 | ||
assert urlargs['q'] == 'test' | ||
|
||
with app.test_request_context("?q="): | ||
query, urlargs = es_query_factory('myindex', 2, 20) | ||
assert query.body['query'] == dict(match_all={}) | ||
assert query.body['from'] == 20 | ||
assert query.body['size'] == 20 | ||
assert urlargs['q'] == '' |