Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Additional paginator for offset without a "total_param" #1530

Closed
Thommel-nl opened this issue Jul 1, 2024 · 2 comments · Fixed by #1677
Closed

Additional paginator for offset without a "total_param" #1530

Thommel-nl opened this issue Jul 1, 2024 · 2 comments · Fixed by #1677
Assignees
Labels
enhancement New feature or request

Comments

@Thommel-nl
Copy link

Feature description

There are some API's that do use an offset and limit pagination type, but do not respond with a total_param. My proposed solution adds a paginator option that checks whether the records list in the response is empty. If that's the case then the loop stops and data is further handled (normalization and loading).

Are you a dlt user?

Yes, I'm already a dlt user.

Use case

Adds a pagination option for offset and limit pagination types which do not have a total_param in the response.

Proposed solution

class OffsetNoTotalPaginator(BasePaginator):
    def __init__(
            self,
            limit: int,
            offset: int = 0,
            offset_param: str = "offset",
            limit_param: str = "limit",
            list_param: str = "records"
    ) -> None:
        super().__init__()
        self.limit_param = limit_param
        self.limit = limit
        self.offset_param = offset_param
        self.offset = offset
        self.list_param = list_param
        """
        Args:
            limit (int): The maximum number of items to retrieve
                in each request.
            offset (int): The offset for the first request.
                Defaults to 0.
            offset_param (str): The query parameter name for the offset.
                Defaults to 'offset'.
            limit_param (str): The query parameter name for the limit.
                Defaults to 'limit'.
            list_param (str): The param that contains the list of results.
                Defaults to 'records'
        """

    def init_request(
            self,
            request: Request
        ) -> None:
        self.update_request(request)

    def update_state(
        self,
        response: Response
    ) -> None:
        # Assumes that the API returns an empty list when no more data is available
        if not response.json()[self.list_param]:
            self._has_next_page = False
        else:
            self.offset += self.limit

    def update_request(
            self,
            request: Request
        ) -> None:
        request.params[self.offset_param] = self.offset
        request.params[self.limit_param] = self.limit

Related issues

No response

@steinitzu
Copy link
Collaborator

Would be a food feature.

Spitballing on the implementation.
Imo this should use the page data list which is already resolved by the client before calling paginator.update_state. Maybe paginator's should always have access to it, i.e. we change the signature of update_state to:

def update_state(self, response: Response, page_data: List[Any]):

Existing OffsetPaginator can be extended instead of making this a separate class:

  1. Make the total_path argument optional
  2. When total_path is missing, fall back to checking whether page_data is empty

@burnash burnash self-assigned this Aug 9, 2024
@burnash burnash added the enhancement New feature or request label Aug 9, 2024
@burnash
Copy link
Collaborator

burnash commented Aug 9, 2024

This functionality has been requested again #1637 after an internal discussion we decided to proceed with implementing it in #1677

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

3 participants