Skip to content
This repository was archived by the owner on Aug 30, 2024. It is now read-only.

Commit fd6abd9

Browse files
authored
Merge pull request #305 from cloudant/304-fix-bad-startkey-in-all-doc-iter
304 fix bad startkey in all doc iter
2 parents 9b82d4c + abd620a commit fd6abd9

File tree

4 files changed

+46
-6
lines changed

4 files changed

+46
-6
lines changed

CHANGES.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
- [FIXED] Fixed Cloudant exception code 409 with 412 when creating a database that already exists.
77
- [FIXED] Catch error if ``throw_on_exists`` flag is ``False`` for document create.
88
- [FIXED] Fixed /_all_docs call where ``keys`` is an empty list.
9+
- [FIXED] Issue where docs with IDs that sorted lower than 0 were not returned when iterating through _all_docs.
910

1011
2.4.0 (2017-02-14)
1112
==================

src/cloudant/_2to3.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
# pylint: disable=undefined-variable
3333
LONGTYPE = long if PY2 else int
3434

35+
# pylint: disable=undefined-variable
36+
UNICHR = unichr if PY2 else chr
37+
3538
if PY2:
3639
# pylint: disable=wrong-import-position,no-name-in-module,import-error,unused-import
3740
from urllib import quote as url_quote, quote_plus as url_quote_plus

src/cloudant/database.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -630,18 +630,20 @@ def __iter__(self, remote=True):
630630
if not remote:
631631
super(CouchDatabase, self).__iter__()
632632
else:
633-
next_startkey = '0'
633+
# Use unicode Null U+0000 as the initial lower bound to ensure any
634+
# document id could exist in the results set.
635+
next_startkey = u'\u0000'
634636
while next_startkey is not None:
635637
docs = self.all_docs(
636-
limit=self._fetch_limit + 1, # Get one extra doc
637-
# to use as
638-
# next_startkey
638+
limit=self._fetch_limit,
639639
include_docs=True,
640640
startkey=next_startkey
641641
).get('rows', [])
642642

643-
if len(docs) > self._fetch_limit:
644-
next_startkey = docs.pop()['id']
643+
if len(docs) >= self._fetch_limit:
644+
# Ensure the next document batch contains ids that sort
645+
# strictly higher than the previous document id fetched.
646+
next_startkey = docs[-1]['id'] + u'\u0000'
645647
else:
646648
# This is the last batch of docs, so we set
647649
# ourselves up to break out of the while loop

tests/unit/database_tests.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import os
3030
import uuid
3131

32+
from cloudant._2to3 import UNICHR
3233
from cloudant.result import Result, QueryResult
3334
from cloudant.error import CloudantArgumentError, CloudantDatabaseException
3435
from cloudant.document import Document
@@ -605,6 +606,39 @@ def test_document_iteration_over_fetch_limit(self):
605606
self.assertEqual(doc['name'], 'julia')
606607
self.assertEqual(doc['age'], int(id[len(id) - 3: len(id)]))
607608

609+
def test_document_iteration_completeness(self):
610+
"""
611+
Test __iter__ works as expected, fetching all documents from the
612+
database.
613+
"""
614+
for _ in self.db:
615+
self.fail('There should be no documents in the database yet!!')
616+
617+
# sample code point ranges
618+
include_ranges = [
619+
(0x0023, 0x0026),
620+
(0x00A1, 0x00AC),
621+
(0x0370, 0x0377),
622+
(0x037A, 0x037E),
623+
(0x0384, 0x038A),
624+
(0x16A0, 0x16F0),
625+
(0x2C60, 0x2C7F)
626+
]
627+
628+
all_docs = [{'_id': UNICHR(i) + UNICHR(j)} for a, b in include_ranges
629+
for i in range(a, b)
630+
for j in range(a, b)]
631+
batch_size = 500
632+
for i in range(0, len(all_docs), batch_size):
633+
self.db.bulk_docs(all_docs[i:i+batch_size])
634+
635+
doc_count = 0
636+
for i, doc in enumerate(self.db):
637+
doc_count += 1
638+
self.assertEqual(doc['_id'], all_docs[i]['_id'])
639+
640+
self.assertEqual(doc_count, len(all_docs))
641+
608642
def test_document_iteration_returns_valid_documents(self):
609643
"""
610644
This test will check that the __iter__ method returns documents that are

0 commit comments

Comments
 (0)