Skip to content

Commit

Permalink
Merge a58eda6 into 81e22e5
Browse files Browse the repository at this point in the history
  • Loading branch information
ebrehault committed Jun 7, 2017
2 parents 81e22e5 + a58eda6 commit c2d500f
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 16 deletions.
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ New Features:
- Automatically publish docker images on hub.docker.com.
[timo]

- Add "&fullobject" parameter in @search to retrieve full objects
[ebrehault]

Bugfixes:

- Docs: Fix batching example request/response.
Expand Down
17 changes: 17 additions & 0 deletions docs/source/searching.rst
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,20 @@ The metadata from those columns then will be included in the results.
In order to specify multiple columns, simply repeat the query string parameter once for every column name (the ``requests`` module will do this automatically for you if you pass it a list of values for a query string parameter).

In order to retrieve all metadata columns that the catalog knows about, use ``metadata_fields=_all``.


Retrieving full objects
-----------------------

If the data provided as metadata is not enough, you can retrieve search results as full serialized objects equivalent to what the resource GET request would produce.

You do so by specifying the ``fullobjects`` parameter:

.. code-block:: http
GET /plone/@search?fullobjects&SearchableText=lorem HTTP/1.1
Accept: application/json
.. warning::

Be aware it might induces performance issues when retrieving a lot of resources. Regular search just uses lazy objects, but with full objects retrieving we wake up all the returned objects.
8 changes: 7 additions & 1 deletion src/plone/restapi/search/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ def _constrain_query_by_path(self, query):
def search(self, query=None):
if query is None:
query = {}
if 'fullobjects' in query:
fullobjects = True
del query['fullobjects']
else:
fullobjects = False

metadata_fields = query.pop('metadata_fields', [])
if not isinstance(metadata_fields, list):
Expand All @@ -56,6 +61,7 @@ def search(self, query=None):
lazy_resultset = self.catalog.searchResults(query)
results = getMultiAdapter(
(lazy_resultset, self.request),
ISerializeToJson)(metadata_fields=metadata_fields)
ISerializeToJson)(
metadata_fields=metadata_fields, fullobjects=fullobjects)

return results
20 changes: 12 additions & 8 deletions src/plone/restapi/serializer/catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def __init__(self, lazy_resultset, request):
self.lazy_resultset = lazy_resultset
self.request = request

def __call__(self, metadata_fields=()):
def __call__(self, metadata_fields=(), fullobjects=False):
batch = HypermediaBatch(self.request, self.lazy_resultset)

results = {}
Expand All @@ -82,15 +82,19 @@ def __call__(self, metadata_fields=()):

results['items'] = []
for brain in batch:
result = getMultiAdapter(
(brain, self.request), ISerializeToJsonSummary)()
if fullobjects:
result = getMultiAdapter(
(brain.getObject(), self.request), ISerializeToJson)()
else:
result = getMultiAdapter(
(brain, self.request), ISerializeToJsonSummary)()

if metadata_fields:
# Merge additional metadata into the summary we already have
metadata = getMultiAdapter(
(brain, self.request),
ISerializeToJson)(metadata_fields=metadata_fields)
result.update(metadata)
if metadata_fields:
metadata = getMultiAdapter(
(brain, self.request),
ISerializeToJson)(metadata_fields=metadata_fields)
result.update(metadata)

results['items'].append(result)

Expand Down
32 changes: 25 additions & 7 deletions src/plone/restapi/tests/test_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from DateTime import DateTime
from plone.app.testing import SITE_OWNER_NAME
from plone.app.testing import SITE_OWNER_PASSWORD
from plone.app.textfield.value import RichTextValue
from plone.dexterity.utils import createContentInContainer
from plone.restapi.testing import PLONE_RESTAPI_DX_FUNCTIONAL_TESTING
from plone.restapi.testing import RelativeSession
Expand Down Expand Up @@ -40,12 +41,17 @@ def setUp(self):
self.folder, u'DXTestDocument',
id='doc',
title=u'Lorem Ipsum',
created=DateTime(1950, 1, 1, 0, 0),
start=DateTime(1950, 1, 1, 0, 0),
effective=DateTime(1995, 1, 1, 0, 0),
expires=DateTime(1999, 1, 1, 0, 0),
test_int_field=42,
test_list_field=['Keyword1', 'Keyword2', 'Keyword3'],
test_bool_field=True,
test_richtext_field=RichTextValue(
raw=u'<p>Some Text</p>',
mimeType='text/html',
outputMimeType='text/html'
),
)
IMutableUUID(self.doc).set('77779ffa110e45afb1ba502f75f77777')
self.doc.reindexObject()
Expand All @@ -56,7 +62,7 @@ def setUp(self):
id='other-document',
title=u'Other Document',
description=u'\xdcbersicht',
created=DateTime(1975, 1, 1, 0, 0),
start=DateTime(1975, 1, 1, 0, 0),
effective=DateTime(2015, 1, 1, 0, 0),
expires=DateTime(2020, 1, 1, 0, 0),
test_list_field=['Keyword2', 'Keyword3'],
Expand Down Expand Up @@ -151,12 +157,22 @@ def test_full_metadata_retrieval(self):
u'meta_type': u'Dexterity Item',
u'portal_type': u'DXTestDocument',
u'review_state': u'private',
u'start': None,
u'start': u'1950-01-01T00:00:00+00:00',
u'sync_uid': None,
u'title': u'Lorem Ipsum',
u'total_comments': 0},
response.json()['items'][0])

def test_full_objects_retrieval(self):
query = {'SearchableText': 'lorem',
'metadata_fields': ['portal_type', 'review_state'],
'fullobjects': True}
response = self.api_session.get('/@search', params=query)

self.assertEqual(
u'<p>Some Text</p>',
response.json()['items'][0]['test_richtext_field']['data'])

# ZCTextIndex

def test_fulltext_search(self):
Expand Down Expand Up @@ -312,7 +328,7 @@ def test_extended_path_index_depth_limiting(self):
# DateIndex

def test_date_index_query(self):
query = {'created': date(1950, 1, 1).isoformat()}
query = {'start': date(1950, 1, 1).isoformat()}
response = self.api_session.get('/@search', params=query)

self.assertEqual(
Expand All @@ -322,9 +338,11 @@ def test_date_index_query(self):

def test_date_index_ranged_query(self):
query = {
'created.query': [date(1949, 1, 1).isoformat(),
date(1951, 1, 1).isoformat()],
'created.range': 'min:max',
'start.query': [
date(1949, 1, 1).isoformat(),
date(1951, 1, 1).isoformat(),
],
'start.range': 'min:max',
}
response = self.api_session.get('/@search', params=query)

Expand Down

0 comments on commit c2d500f

Please sign in to comment.