Skip to content

Conversation

@histrio
Copy link
Owner

@histrio histrio commented Sep 30, 2025

No description provided.

@histrio histrio requested a review from Copilot September 30, 2025 07:25
@codecov-commenter
Copy link

codecov-commenter commented Sep 30, 2025

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 94.62366% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.48%. Comparing base (320ad31) to head (da5587e).

Files with missing lines Patch % Lines
pycouchdb/client.py 90.00% 3 Missing ⚠️
pycouchdb/pagination.py 96.42% 2 Missing ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #112      +/-   ##
==========================================
+ Coverage   88.74%   89.48%   +0.73%     
==========================================
  Files           7        8       +1     
  Lines         622      713      +91     
==========================================
+ Hits          552      638      +86     
- Misses         70       75       +5     
Flag Coverage Δ
unittests 89.48% <94.62%> (+0.73%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds cursor-based pagination functionality to pycouchdb, implementing both view and Mango query pagination along with client API methods. The main purpose is to provide stable, memory-efficient pagination without the pitfalls of skip-based pagination.

Key changes:

  • Adds a new pagination.py module with view_pages() and mango_pages() functions for cursor-based pagination
  • Extends the Database class with find(), view_pages(), and mango_pages() methods
  • Includes comprehensive test coverage for both unit and integration testing

Reviewed Changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pycouchdb/pagination.py Core pagination logic implementing cursor-based pagination for views and Mango queries
pycouchdb/client.py Database class extensions adding pagination methods and Mango query support
pycouchdb/types.py Type aliases for pagination-related types
pycouchdb/utils.py Enhanced UTF-8 decoding with error handling
test/test_pagination.py Unit tests for pagination functions with mocked dependencies
test/test_database.py Unit tests for new Database methods
test/integration/test_pagination_integration.py Comprehensive integration tests with real CouchDB
test/integration/test_integration.py Additional integration tests for pagination functionality
docs/source/quickstart.rst Documentation updates explaining pagination features

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

last_row = rows[page_size - 1]
startkey = last_row['key']
startkey_docid = last_row['id']
skip = 1 # Skip the row we used as cursor
Copy link

Copilot AI Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The inline comment explains what skip=1 does, but it would be clearer to explain why this is necessary to avoid duplicate results in cursor-based pagination.

Suggested change
skip = 1 # Skip the row we used as cursor
skip = 1 # Skip the row used as the cursor to avoid returning it again (prevents duplicate results in cursor-based pagination)

Copilot uses AI. Check for mistakes.
Comment on lines 147 to 153
def _prepare_mango_data(selector: Dict[str, Any], params: Dict[str, Any]) -> bytes:
"""Prepare Mango query data for HTTP request."""
data_dict = {
'selector': selector,
**params
}
return utils.force_bytes(json.dumps(data_dict))
Copy link

Copilot AI Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _prepare_mango_data function is defined but never used in the code. Consider removing it or adding a comment explaining its intended future use.

Suggested change
def _prepare_mango_data(selector: Dict[str, Any], params: Dict[str, Any]) -> bytes:
"""Prepare Mango query data for HTTP request."""
data_dict = {
'selector': selector,
**params
}
return utils.force_bytes(json.dumps(data_dict))

Copilot uses AI. Check for mistakes.
:param params: Additional query parameters
:returns: Iterator yielding lists of rows for each page
.. versionadded: 1.17
Copy link

Copilot AI Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring format should be .. versionadded:: 1.17 with double colons, not single colon.

Suggested change
.. versionadded: 1.17
.. versionadded:: 1.17

Copilot uses AI. Check for mistakes.
:param params: Additional query parameters
:returns: Iterator yielding lists of documents for each page
.. versionadded: 1.17
Copy link

Copilot AI Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring format should be .. versionadded:: 1.17 with double colons, not single colon.

Suggested change
.. versionadded: 1.17
.. versionadded:: 1.17

Copilot uses AI. Check for mistakes.
@histrio histrio requested a review from Copilot September 30, 2025 08:25
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.


Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

last_row = rows[page_size - 1]
startkey = last_row['key']
startkey_docid = last_row['id']
skip = 1 # Skip the row used as the cursor to avoid returning it again (prevents duplicate results in cursor-based pagination)
Copy link

Copilot AI Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The comment is overly verbose and could be clearer. Consider simplifying to 'Skip cursor row to avoid duplicates'.

Suggested change
skip = 1 # Skip the row used as the cursor to avoid returning it again (prevents duplicate results in cursor-based pagination)
skip = 1 # Skip cursor row to avoid duplicates

Copilot uses AI. Check for mistakes.
Comment on lines +83 to +84
startkey = last_row['key']
startkey_docid = last_row['id']
Copy link

Copilot AI Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code uses magic string keys 'key' and 'id' without validation. Consider adding defensive checks or constants for these keys to improve maintainability.

Copilot uses AI. Check for mistakes.
Comment on lines +148 to +149
# Valid JSON but with invalid UTF-8 sequence in the middle
self.content = b'{"key": "value", "invalid": "\xff\xfe"}'
Copy link

Copilot AI Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The byte string contains invalid UTF-8 sequences inside a JSON string literal, but this creates invalid JSON, not just invalid UTF-8. The test may not be testing the intended scenario.

Suggested change
# Valid JSON but with invalid UTF-8 sequence in the middle
self.content = b'{"key": "value", "invalid": "\xff\xfe"}'
# Valid JSON, but the value for "invalid" is a string with bytes that are invalid UTF-8
self.content = b'{"key": "value", "invalid": "' + b'\xff\xfe'.decode("latin1").encode("utf-8", "surrogateescape") + b'"}'

Copilot uses AI. Check for mistakes.
Comment on lines +161 to +162
# Valid JSON with invalid UTF-8 that will be replaced with replacement character
self.content = b'{"key": "value", "invalid": "\xff\xfe\x80"}'
Copy link

Copilot AI Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the previous test, this creates invalid JSON syntax rather than testing UTF-8 decode errors. The invalid bytes should be outside the JSON string structure.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants