Skip to content

Commit 81af09d

Browse files
tammoippendjc
authored andcommitted
Make the index endpoint a separate class
1 parent 026992f commit 81af09d

File tree

2 files changed

+142
-99
lines changed

2 files changed

+142
-99
lines changed

couchdb/client.py

Lines changed: 112 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -834,92 +834,14 @@ def explain(self, mango_query):
834834
return data
835835

836836
def index(self):
837-
"""Get all available indexes.
837+
"""Get an object to manage the database indexes.
838838
839-
Note: Only available for CouchDB version >= 2.0.0 .
840-
841-
More information here:
842-
http://docs.couchdb.org/en/master/api/database/find.html#get--db-_index
843-
844-
>>> server = Server()
845-
>>> db = server.create('python-tests')
846-
>>> db.index() #doctest: +SKIP
847-
{'indexes': [{'ddoc': None,
848-
'def': {'fields': [{'_id': 'asc'}]},
849-
'name': '_all_docs',
850-
'type': 'special'}],
851-
'total_rows': 1}
852-
>>> del server['python-tests']
853-
854-
:return: `dict` containing the number of indexes (`total_rows`) and
855-
a description of each index (`indexes`)
856-
"""
857-
_, _, data = self.resource.get_json('_index')
858-
return data
859-
860-
def add_index(self, index, ddoc=None, name=None):
861-
"""Add an index to the database.
862-
863-
Note: Only available for CouchDB version >= 2.0.0 .
864-
865-
More information here:
866-
http://docs.couchdb.org/en/master/api/database/find.html#post--db-_index
867-
868-
>>> server = Server()
869-
>>> db = server.create('python-tests')
870-
>>> db['johndoe'] = dict(type='Person', name='John Doe')
871-
>>> db['maryjane'] = dict(type='Person', name='Mary Jane')
872-
>>> db['gotham'] = dict(type='City', name='Gotham City')
873-
>>> db.add_index({'fields': [{'type': 'asc'}]}, #doctest: +SKIP
874-
... ddoc='foo',
875-
... name='bar')
876-
{'id': '_design/foo', 'name': 'bar', 'result': 'created'}
877-
>>> del server['python-tests']
878-
879-
:param index: `dict` describing the index to create
880-
:param ddoc: (optional) name of the design document in which the index
881-
will be created
882-
:param name: (optional) name of the index
883-
:return: `dict` containing the `id`, the `name` and the `result` of
884-
creating the index
839+
:return: an `Indexes` object to manage the databes indexes
840+
:rtype: `Indexes`
885841
"""
886-
assert isinstance(index, dict)
887-
query = {'index': index}
888-
if ddoc:
889-
query['ddoc'] = ddoc
890-
if name:
891-
query['name'] = name
892-
_, _, data = self.resource.post_json('_index', query)
893-
return data
894-
895-
def remove_index(self, ddoc, name):
896-
"""Remove an index from the database.
897-
898-
Note: Only available for CouchDB version >= 2.0.0 .
899-
900-
More information here:
901-
http://docs.couchdb.org/en/master/api/database/find.html#delete--db-_index-designdoc-json-name
842+
return Indexes(self.resource('_index'))
902843

903-
>>> server = Server()
904-
>>> db = server.create('python-tests')
905-
>>> db['johndoe'] = dict(type='Person', name='John Doe')
906-
>>> db['maryjane'] = dict(type='Person', name='Mary Jane')
907-
>>> db['gotham'] = dict(type='City', name='Gotham City')
908-
>>> db.add_index({'fields': [{'type': 'asc'}]}, #doctest: +SKIP
909-
... ddoc='foo',
910-
... name='bar')
911-
{'id': '_design/foo', 'name': 'bar', 'result': 'created'}
912-
>>> db.remove_index('foo', 'bar') #doctest: +SKIP
913-
{'ok': True}
914-
>>> del server['python-tests']
915844

916-
:param ddoc: name of the design document containing the index
917-
:param name: name of the index that is to be removed
918-
:return: `dict` containing the `id`, the `name` and the `result` of
919-
creating the index
920-
"""
921-
_, _, data = self.resource.delete_json(['_index', ddoc, 'json', name])
922-
return data
923845

924846
def query(self, map_fun, reduce_fun=None, language='javascript',
925847
wrapper=None, **options):
@@ -1526,3 +1448,111 @@ def doc(self):
15261448
doc = self.get('doc')
15271449
if doc:
15281450
return Document(doc)
1451+
1452+
1453+
class Indexes(object):
1454+
"""Manage indexes in CouchDB 2.0.0 and later.
1455+
1456+
More information here:
1457+
http://docs.couchdb.org/en/2.0.0/api/database/find.html#db-index
1458+
"""
1459+
1460+
def __init__(self, url, session=None):
1461+
if isinstance(url, util.strbase):
1462+
self.resource = http.Resource(url, session)
1463+
else:
1464+
self.resource = url
1465+
1466+
def __setitem__(self, ddoc_name, index):
1467+
"""Add an index to the database.
1468+
1469+
>>> server = Server()
1470+
>>> db = server.create('python-tests')
1471+
>>> db['johndoe'] = dict(type='Person', name='John Doe')
1472+
>>> db['maryjane'] = dict(type='Person', name='Mary Jane')
1473+
>>> db['gotham'] = dict(type='City', name='Gotham City')
1474+
>>> idx = db.index()
1475+
>>> idx['foo', 'bar'] = [{'type': 'asc'}] #doctest: +SKIP
1476+
>>> list(idx) #doctest: +SKIP
1477+
[{'ddoc': None,
1478+
'def': {'fields': [{'_id': 'asc'}]},
1479+
'name': '_all_docs',
1480+
'type': 'special'},
1481+
{'ddoc': '_design/foo',
1482+
'def': {'fields': [{'type': 'asc'}]},
1483+
'name': 'bar',
1484+
'type': 'json'}]
1485+
>>> idx[None, None] = [{'type': 'desc'}] #doctest: +SKIP
1486+
>>> list(idx) #doctest: +SKIP, +ELLIPSIS
1487+
[{'ddoc': None,
1488+
'def': {'fields': [{'_id': 'asc'}]},
1489+
'name': '_all_docs',
1490+
'type': 'special'},
1491+
{'ddoc': '_design/...',
1492+
'def': {'fields': [{'type': 'desc'}]},
1493+
'name': '...',
1494+
'type': 'json'},
1495+
{'ddoc': '_design/foo',
1496+
'def': {'fields': [{'type': 'asc'}]},
1497+
'name': 'bar',
1498+
'type': 'json'}]
1499+
>>> del server['python-tests']
1500+
1501+
:param index: `list` of indexes to create
1502+
:param ddoc_name: `tuple` or `list` containing first the name of the
1503+
design document, in which the index will be created,
1504+
and second name of the index. Both can be `None`.
1505+
"""
1506+
query = {'index': {'fields': index}}
1507+
ddoc, name = ddoc_name # expect ddoc / name to be a slice or list
1508+
if ddoc:
1509+
query['ddoc'] = ddoc
1510+
if name:
1511+
query['name'] = name
1512+
self.resource.post_json(body=query)
1513+
1514+
def __delitem__(self, ddoc_name):
1515+
"""Remove an index from the database.
1516+
1517+
>>> server = Server()
1518+
>>> db = server.create('python-tests')
1519+
>>> db['johndoe'] = dict(type='Person', name='John Doe')
1520+
>>> db['maryjane'] = dict(type='Person', name='Mary Jane')
1521+
>>> db['gotham'] = dict(type='City', name='Gotham City')
1522+
>>> idx = db.index()
1523+
>>> idx['foo', 'bar'] = [{'type': 'asc'}] #doctest: +SKIP
1524+
>>> del idx['foo', 'bar'] #doctest: +SKIP
1525+
>>> list(idx) #doctest: +SKIP
1526+
[{'ddoc': None,
1527+
'def': {'fields': [{'_id': 'asc'}]},
1528+
'name': '_all_docs',
1529+
'type': 'special'}]
1530+
>>> del server['python-tests']
1531+
1532+
:param ddoc: name of the design document containing the index
1533+
:param name: name of the index that is to be removed
1534+
:return: `dict` containing the `id`, the `name` and the `result` of
1535+
creating the index
1536+
"""
1537+
self.resource.delete_json([ddoc_name[0], 'json', ddoc_name[1]])
1538+
1539+
def _list(self):
1540+
_, _, data = self.resource.get_json()
1541+
return data
1542+
1543+
def __iter__(self):
1544+
"""Iterate all indexes of the associated database.
1545+
1546+
>>> server = Server()
1547+
>>> db = server.create('python-tests')
1548+
>>> idx = db.index()
1549+
>>> list(idx) #doctest: +SKIP
1550+
[{'ddoc': None,
1551+
'def': {'fields': [{'_id': 'asc'}]},
1552+
'name': '_all_docs',
1553+
'type': 'special'}]
1554+
>>> del server['python-tests']
1555+
1556+
:return: iterator yielding `dict`'s describing each index
1557+
"""
1558+
return iter(self._list()['indexes'])

couchdb/tests/client.py

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -384,14 +384,18 @@ def test_find(self):
384384
dict(type='City', name='Gotham City')
385385
]
386386
self.db.update(docs)
387+
# the sort needs an index over `name`, the selector selects by `type`
388+
idx = self.db.index()
389+
idx['foo', 'bar'] = [{'type': 'asc'}, {'name': 'asc'}]
387390

388391
res = list(self.db.find(
389392
{
390393
'selector': {
391394
'type': 'Person'
392395
},
393396
'fields': ['name'],
394-
'sort': [{'name': 'asc'}]
397+
# we need to specify the complete index here
398+
'sort': [{'type': 'asc'}, {'name': 'asc'}]
395399
}
396400
))
397401
self.assertEqual(2, len(res))
@@ -415,34 +419,43 @@ def test_index(self):
415419
if self.server.version_info()[0] < 2:
416420
return
417421

418-
res = self.db.index()
419-
self.assertEqual(1, res['total_rows'])
420-
self.assertEqual(1, len(res['indexes']))
422+
res = list(self.db.index())
423+
self.assertEqual(1, len(res))
421424
self.assertEqual({'ddoc': None, 'def': {'fields': [{'_id': 'asc'}]},
422425
'name': '_all_docs', 'type': 'special'},
423-
res['indexes'][0])
426+
res[0])
424427

425428
def test_add_index(self):
426429
if self.server.version_info()[0] < 2:
427430
return
428431

429-
res = self.db.add_index({'fields': [{'type': 'asc'}]}, ddoc='foo', name='bar')
430-
self.assertEqual({'id': '_design/foo',
431-
'name': 'bar',
432-
'result': 'created'},
433-
res)
434-
res = self.db.index()
435-
self.assertEqual(2, res['total_rows'])
432+
idx = self.db.index()
433+
idx['foo', 'bar'] = [{'type': 'asc'}]
434+
idxs = list(idx)
435+
436+
self.assertEqual(2, len(idxs))
437+
for i in idxs:
438+
if i['ddoc'] is not None: # special `_all_docs` index
439+
self.assertEqual({'ddoc': '_design/foo',
440+
'def': {'fields': [{'type': 'asc'}]},
441+
'name': 'bar',
442+
'type': 'json'},
443+
i)
444+
return
445+
self.failed()
436446

437447
def test_remove_index(self):
438448
if self.server.version_info()[0] < 2:
439449
return
440450

441-
self.db.add_index({'fields': [{'type': 'asc'}]}, ddoc='foo', name='bar')
442-
res = self.db.remove_index('foo', 'bar')
443-
self.assertEqual({'ok': True}, res)
444-
res = self.db.index()
445-
self.assertEqual(1, res['total_rows'])
451+
idx = self.db.index()
452+
idx['foo', 'bar'] = [{'type': 'asc'}]
453+
res = list(idx)
454+
self.assertEqual(2, len(res))
455+
del idx['foo', 'bar']
456+
457+
res = list(idx)
458+
self.assertEqual(1, len(res))
446459

447460
def test_bulk_update_conflict(self):
448461
docs = [

0 commit comments

Comments
 (0)