diff --git a/gcloud/search/index.py b/gcloud/search/index.py index 31c2950b7105..5f418fa2b188 100644 --- a/gcloud/search/index.py +++ b/gcloud/search/index.py @@ -14,6 +14,8 @@ """Define API Indexes.""" +from gcloud.search.document import Document + class Index(object): """Indexes are containers for documents. @@ -148,3 +150,50 @@ def _set_properties(self, api_response): """ self._properties.clear() self._properties.update(api_response) + + def list_documents(self, max_results=None, page_token=None, + view=None): + """List documents created within this index. + + See: + https://cloud.google.com/search/reference/rest/v1/projects/indexes/documents/list + + :type max_results: int + :param max_results: maximum number of zones to return, If not + passed, defaults to a value set by the API. + + :type page_token: string + :param page_token: opaque marker for the next "page" of zones. If + not passed, the API will return the first page of + zones. + + :type view: string + :param view: One of 'ID_ONLY' (return only the document ID; the + default) or 'FULL' (return the full resource + representation for the document, including field + values) + + :rtype: tuple, (list, str) + :returns: list of :class:`gcloud.dns.document.Document`, plus a + "next page token" string: if the token is not None, + indicates that more zones can be retrieved with another + call (pass that value as ``page_token``). + """ + params = {} + + if max_results is not None: + params['pageSize'] = max_results + + if page_token is not None: + params['pageToken'] = page_token + + if view is not None: + params['view'] = view + + path = '%s/documents' % (self.path,) + connection = self._client.connection + resp = connection.api_request(method='GET', path=path, + query_params=params) + zones = [Document.from_api_repr(resource, self) + for resource in resp['documents']] + return zones, resp.get('nextPageToken') diff --git a/gcloud/search/test_client.py b/gcloud/search/test_client.py index 1692be82b7b3..9ba7c65e4d52 100644 --- a/gcloud/search/test_client.py +++ b/gcloud/search/test_client.py @@ -54,10 +54,10 @@ def test_list_indexes_defaults(self): client = self._makeOne(self.PROJECT, creds) conn = client.connection = _Connection(DATA) - zones, token = client.list_indexes() + indexes, token = client.list_indexes() - self.assertEqual(len(zones), len(DATA['indexes'])) - for found, expected in zip(zones, DATA['indexes']): + self.assertEqual(len(indexes), len(DATA['indexes'])) + for found, expected in zip(indexes, DATA['indexes']): self.assertTrue(isinstance(found, Index)) self.assertEqual(found.name, expected['indexId']) self.assertEqual(found.text_fields, None) @@ -72,6 +72,7 @@ def test_list_indexes_defaults(self): req = conn._requested[0] self.assertEqual(req['method'], 'GET') self.assertEqual(req['path'], '/%s' % PATH) + self.assertEqual(req['query_params'], {}) def test_list_indexes_explicit(self): from gcloud.search.index import Index @@ -93,11 +94,11 @@ def test_list_indexes_explicit(self): client = self._makeOne(self.PROJECT, creds) conn = client.connection = _Connection(DATA) - zones, token = client.list_indexes( + indexes, token = client.list_indexes( max_results=3, page_token=TOKEN, prefix='index', view='FULL') - self.assertEqual(len(zones), len(DATA['indexes'])) - for found, expected in zip(zones, DATA['indexes']): + self.assertEqual(len(indexes), len(DATA['indexes'])) + for found, expected in zip(indexes, DATA['indexes']): self.assertTrue(isinstance(found, Index)) self.assertEqual(found.name, expected['indexId']) field_info = expected['indexedField'] diff --git a/gcloud/search/test_index.py b/gcloud/search/test_index.py index 26f36879d710..54d31ac17646 100644 --- a/gcloud/search/test_index.py +++ b/gcloud/search/test_index.py @@ -50,6 +50,21 @@ def _makeResource(self): } } + def _makeDocumentResource(self, doc_id, rank=None, title=None): + resource = {'docId': doc_id} + if rank is not None: + resource['rank'] = rank + if title is not None: + resource['fields'] = { + 'title': { + 'values': [{ + 'stringValue': title, + 'stringFormat': 'text', + 'lang': 'en'}] + } + } + return resource + def _verifyResourceProperties(self, index, resource): self.assertEqual(index.name, resource.get('indexId')) @@ -61,6 +76,27 @@ def _verifyResourceProperties(self, index, resource): self.assertEqual(index.number_fields, field_info.get('numberFields')) self.assertEqual(index.geo_fields, field_info.get('geoFields')) + def _verifyDocumentResource(self, documents, resource): + from gcloud.search.document import Document + from gcloud.search.document import StringValue + self.assertEqual(len(documents), len(resource['documents'])) + for found, expected in zip(documents, resource['documents']): + self.assertTrue(isinstance(found, Document)) + self.assertEqual(found.name, expected['docId']) + self.assertEqual(found.rank, expected.get('rank')) + e_fields = expected.get('fields', ()) + self.assertEqual(sorted(found.fields), sorted(e_fields)) + for field, f_field in found.fields.items(): + e_field = e_fields[field] + for f_value, e_value in zip(f_field.values, e_field['values']): + self.assertTrue(isinstance(f_value, StringValue)) + self.assertEqual(f_value.string_value, + e_value['stringValue']) + self.assertEqual(f_value.string_format, + e_value['stringFormat']) + self.assertEqual(f_value.language, + e_value['lang']) + def test_ctor(self): client = _Client(self.PROJECT) index = self._makeOne(self.INDEX_ID, client) @@ -105,9 +141,86 @@ def test_from_api_repr_w_properties(self): self.assertTrue(index._client is client) self._verifyResourceProperties(index, RESOURCE) + def test_list_documents_defaults(self): + DOCID_1 = 'docid-one' + DOCID_2 = 'docid-two' + PATH = 'projects/%s/indexes/%s/documents' % ( + self.PROJECT, self.INDEX_ID) + TOKEN = 'TOKEN' + DOC_1 = self._makeDocumentResource(DOCID_1) + DOC_2 = self._makeDocumentResource(DOCID_2) + DATA = { + 'nextPageToken': TOKEN, + 'documents': [DOC_1, DOC_2], + } + client = _Client(self.PROJECT) + conn = client.connection = _Connection(DATA) + index = self._makeOne(self.INDEX_ID, client) + + documents, token = index.list_documents() + + self._verifyDocumentResource(documents, DATA) + self.assertEqual(token, TOKEN) + + self.assertEqual(len(conn._requested), 1) + req = conn._requested[0] + self.assertEqual(req['method'], 'GET') + self.assertEqual(req['path'], '/%s' % PATH) + self.assertEqual(req['query_params'], {}) + + def test_list_documents_explicit(self): + DOCID_1 = 'docid-one' + RANK_1 = 2345 + TITLE_1 = 'Title One' + DOCID_2 = 'docid-two' + RANK_2 = 1234 + TITLE_2 = 'Title Two' + PATH = 'projects/%s/indexes/%s/documents' % ( + self.PROJECT, self.INDEX_ID) + TOKEN = 'TOKEN' + DOC_1 = self._makeDocumentResource(DOCID_1, RANK_1, TITLE_1) + DOC_2 = self._makeDocumentResource(DOCID_2, RANK_2, TITLE_2) + DATA = {'documents': [DOC_1, DOC_2]} + client = _Client(self.PROJECT) + conn = client.connection = _Connection(DATA) + index = self._makeOne(self.INDEX_ID, client) + + documents, token = index.list_documents( + max_results=3, page_token=TOKEN, view='FULL') + + self._verifyDocumentResource(documents, DATA) + self.assertEqual(token, None) + + self.assertEqual(len(conn._requested), 1) + req = conn._requested[0] + self.assertEqual(req['method'], 'GET') + self.assertEqual(req['path'], '/%s' % PATH) + self.assertEqual(req['query_params'], + {'pageSize': 3, + 'pageToken': TOKEN, + 'view': 'FULL'}) + class _Client(object): def __init__(self, project='project', connection=None): self.project = project self.connection = connection + + +class _Connection(object): + + def __init__(self, *responses): + self._responses = responses + self._requested = [] + + def api_request(self, **kw): + from gcloud.exceptions import NotFound + self._requested.append(kw) + + try: + response, self._responses = self._responses[0], self._responses[1:] + except: # pragma: NO COVER + raise NotFound('miss') + else: + return response