Skip to content

Conversation

@brianjlai
Copy link
Contributor

@brianjlai brianjlai commented Apr 15, 2025

What

While migrating source-hubspot @tolik0 identified a bug in how we perform OffsetIncrement pagination. When we perform record filtering, we can potentially end up with fewer records than the amount returned in the API response. The paginator then falsely thinks the paging is complete because received records is smaller than the max page size.

How

This PR fixes the said problem above by utilizing the existing RecordExtractor model defined by the developer and utilizes it in the OffsetIncrement pagination strategy. While determine if there are more pages to read in next_page_token() we have the extractor parse the response parameter (which will not perform filtering) to get the accurate count.

We opted for this solution because reusing an extractor is more accurate than recreating the dpath parsing behavior.

Summary by CodeRabbit

  • New Features

    • Pagination strategies now support extracting records from responses using an extractor, improving handling of paginated data.
  • Bug Fixes

    • Pagination logic now correctly handles cases where the expected record path is missing in the response.
  • Tests

    • Enhanced test coverage for pagination, including realistic response scenarios and validation of extractor integration.

@brianjlai brianjlai requested review from darynaishchenko, maxi297, pnilan and tolik0 and removed request for pnilan April 15, 2025 00:07
@github-actions github-actions bot added the bug Something isn't working label Apr 15, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Apr 15, 2025

📝 Walkthrough

Walkthrough

The changes introduce the ability for pagination strategies, specifically the OffsetIncrement strategy, to utilize a record extractor when determining pagination behavior. The factory responsible for constructing these components now accepts and propagates an optional extractor model, enabling paginators and offset increment strategies to be aware of the extraction context. Test suites for the factory and paginator strategies have been updated to use the new extractor-aware constructors and to validate correct integration, including scenarios where the response lacks the expected record path.

Changes

Files / Grouped Paths Change Summary
airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py Updated factory methods (create_default_paginator, create_offset_increment, create_simple_retriever) to accept and propagate an optional extractor_model parameter, enabling extractor context to be passed to paginator and offset increment components.
airbyte_cdk/sources/declarative/requesters/paginators/strategies/offset_increment.py Extended OffsetIncrement to accept an optional RecordExtractor and use it in next_page_token for counting records in the response, influencing pagination logic.
unit_tests/sources/declarative/parsers/test_model_to_component_factory.py Updated tests to pass extractor models to paginator and offset increment strategies, added assertions to verify extractor integration, and adjusted test expectations accordingly.
unit_tests/sources/declarative/requesters/paginators/test_default_paginator.py Modified tests to construct OffsetIncrement with a DpathExtractor, updated response bodies to include realistic record lists, and ensured paginator logic aligns with the new extractor usage.
unit_tests/sources/declarative/requesters/paginators/test_offset_increment.py Enhanced tests to use DpathExtractor for record extraction, updated test inputs to include record lists, added a test for missing record paths, and adjusted existing tests for extractor-aware paginator construction.

Sequence Diagram(s)

sequenceDiagram
    participant Factory as ModelToComponentFactory
    participant ExtractorModel
    participant Paginator
    participant OffsetIncrement
    participant Extractor

    Factory->>Paginator: create_default_paginator(extractor_model)
    Paginator->>OffsetIncrement: create_offset_increment(extractor_model)
    OffsetIncrement->>Extractor: instantiate Extractor from extractor_model
    OffsetIncrement->>OffsetIncrement: next_page_token(response)
    OffsetIncrement->>Extractor: extract records from response
    Extractor-->>OffsetIncrement: return records
    OffsetIncrement-->>Paginator: determine next page token
Loading

Suggested labels

bug

Suggested reviewers

  • maxi297
  • tolik0

Would you like to consider adding more tests for edge cases where the extractor returns unexpected types or empty lists, just to further solidify the new logic—wdyt?

Tip

⚡💬 Agentic Chat (Pro Plan, General Availability)
  • We're introducing multi-step agentic chat in review comments and issue comments, within and outside of PR's. This feature enhances review and issue discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments and add commits to existing pull requests.
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

‼️ IMPORTANT
Auto-reply has been disabled for this repository in the CodeRabbit settings. The CodeRabbit bot will not respond to your replies unless it is explicitly tagged.

  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py (1)

2599-2610: Thoughtful implementation with clear explanation

The detailed comment explains the design decision to create separate extractors with identical behavior. This maintains existing behavior while enabling the fix.

Would a future refactoring to reuse the same component (rather than create identical ones) be beneficial for maintenance, wdyt?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 289705d and c3bca7a.

📒 Files selected for processing (5)
  • airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py (5 hunks)
  • airbyte_cdk/sources/declarative/requesters/paginators/strategies/offset_increment.py (3 hunks)
  • unit_tests/sources/declarative/parsers/test_model_to_component_factory.py (4 hunks)
  • unit_tests/sources/declarative/requesters/paginators/test_default_paginator.py (5 hunks)
  • unit_tests/sources/declarative/requesters/paginators/test_offset_increment.py (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
airbyte_cdk/sources/declarative/requesters/paginators/strategies/offset_increment.py (3)
airbyte_cdk/sources/declarative/extractors/record_extractor.py (2)
  • RecordExtractor (12-27)
  • extract_records (18-27)
unit_tests/sources/declarative/parsers/test_model_to_component_factory.py (1)
  • extract_records (3612-3616)
airbyte_cdk/sources/declarative/extractors/dpath_extractor.py (1)
  • extract_records (71-86)
⏰ Context from checks skipped due to timeout of 90000ms (9)
  • GitHub Check: Check: 'source-pokeapi' (skip=false)
  • GitHub Check: Check: 'source-amplitude' (skip=false)
  • GitHub Check: Check: 'source-shopify' (skip=false)
  • GitHub Check: Check: 'source-hardcoded-records' (skip=false)
  • GitHub Check: Pytest (All, Python 3.11, Ubuntu)
  • GitHub Check: Pytest (All, Python 3.10, Ubuntu)
  • GitHub Check: Pytest (Fast)
  • GitHub Check: SDM Docker Image Build
  • GitHub Check: Analyze (python)
🔇 Additional comments (21)
airbyte_cdk/sources/declarative/requesters/paginators/strategies/offset_increment.py (3)

15-15: Import looks good.

The added import for RecordExtractor from dpath_extractor matches the new functionality being introduced.


50-50: Nice addition of the optional extractor parameter.

This parameter will allow the OffsetIncrement strategy to get record counts directly from responses. Good call making it optional for backward compatibility, wdyt?


80-86: Good implementation of record extraction.

This implementation correctly uses the extractor (when provided) to get the raw count of records from the response before any filtering occurs. I like how you've made the page_size_from_response fallback to the incoming last_page_size to handle edge cases. This should fix the issue with pagination when record filtering is applied.

unit_tests/sources/declarative/parsers/test_model_to_component_factory.py (3)

69-69: Good addition of the DpathExtractorModel import.

This import is needed for the updated test cases that now use extractors with pagination strategies.


1835-1835: Test properly updated with extractor model.

The test_create_default_paginator function now correctly includes an extractor_model parameter with a field path of ["results"], which aligns with the new functionality.


2648-2670: Great test update for OffsetIncrement with extractor.

This test is thoroughly updated to validate the new extractor functionality:

  1. Created the expected_extractor with the correct field_path
  2. Created the extractor_model to pass to the factory
  3. Added the extractor to the expected_strategy
  4. Updated the factory.create_offset_increment call to include the extractor_model
  5. Added assertions to verify the extractor is correctly set

This gives good coverage for the new functionality, especially with the field_path assertions.

unit_tests/sources/declarative/requesters/paginators/test_default_paginator.py (5)

12-12: Added DpathExtractor import.

This import is necessary for the updated tests that now use extractor instances.


331-337: Test updated for OffsetIncrement with extractor.

The test_initial_token_with_offset_pagination test now correctly includes a DpathExtractor when creating the OffsetIncrement strategy. The empty field_path should be fine for this test since it's just validating the initial token behavior.


358-364: Good test update with realistic field_path.

The parameterized test now includes a DpathExtractor with field_path=["results"], which matches the realistic test response data added further down. This ensures we're properly testing the extractor functionality in pagination.


389-402: Nice addition of realistic test data.

You've updated the test_no_inject_on_first_request_offset_pagination test to include a realistic JSON response with a "results" array containing 10 records. This matches the field_path in the extractor and the expected page size, making this test much more representative of real-world usage. Great improvement!


459-464: Updated test for OffsetIncrement with extractor.

The test_paginator_with_page_option_no_page_size test now correctly includes a DpathExtractor when creating the OffsetIncrement strategy. The empty field_path is fine for this edge case test that verifies error handling for missing page size.

airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py (4)

2057-2058: Good addition of extractor_model parameter

This parameter allows the OffsetIncrement strategy to use the same extractor as the record selector, which is essential for accurate pagination when record filtering is involved.


2579-2585: Nice refactoring to incorporate extractor-based pagination

The addition of the extractor_model parameter here enables the pagination strategy to access the raw API response before filtering, addressing the core issue in the PR.


2612-2617: Key fix: adding extractor to OffsetIncrement

This is the critical change that enables the pagination strategy to use the extracted records before filtering to determine if more pages remain.


2980-2981: Important connection point

This change connects the dots by passing the record selector's extractor model to the paginator creation, ensuring consistent extraction logic throughout the pipeline.

unit_tests/sources/declarative/requesters/paginators/test_offset_increment.py (6)

11-11: Appropriate import for the DpathExtractor

The import aligns with the new functionality being tested.


17-19: Test signature updated to include response_results

Good update to the test parameters to include the actual response results, which are now crucial for pagination decisions.


72-75: Key test update: using DpathExtractor

The tests now correctly instantiate the OffsetIncrement with a DpathExtractor that looks for records in the "results" path, matching real-world API responses.


80-84: More realistic test data structure

This change creates a more realistic API response structure with results nested under a "results" key, better representing real-world scenarios.


99-115: Excellent additional test case

This new test verifies the paginator's behavior when the response lacks the expected record path, ensuring robust error handling.


139-146: Consistent test updates

The initial token test has been updated to maintain consistency with the new constructor signature, using an empty string field path.

@tolik0 tolik0 merged commit bf998bd into main Apr 15, 2025
30 checks passed
@tolik0 tolik0 deleted the brian/offset_increment_extract_page_size_from_response branch April 15, 2025 13:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants