packages feed

notion-client-0.5.0.0: src/Notion/V1/Pagination.hs

-- | Pagination utilities for Notion API
module Notion.V1.Pagination
  ( -- * Pagination types
    PaginationParams (..),
    defaultPaginationParams,

    -- * Auto-pagination
    paginateAll,
    paginateCollect,
    PaginationResult (..),
  )
where

import Data.Vector qualified as Vector
import Notion.Prelude
import Notion.V1.ListOf (ListOf (..))

-- | Pagination parameters for Notion API requests
data PaginationParams = PaginationParams
  { pageSize :: Maybe Natural,
    startCursor :: Maybe Text
  }
  deriving stock (Generic, Show)

instance ToJSON PaginationParams where
  toJSON = genericToJSON aesonOptions

-- | Default pagination parameters
defaultPaginationParams :: PaginationParams
defaultPaginationParams =
  PaginationParams
    { pageSize = Nothing,
      startCursor = Nothing
    }

-- | Result of auto-pagination, including all collected results and page count.
data PaginationResult a = PaginationResult
  { allResults :: Vector a,
    totalPages :: Natural
  }
  deriving stock (Show)

-- | Automatically paginate through all results by following cursors.
--
-- The callback receives an optional cursor ('Nothing' for the first page)
-- and returns a paginated response. The function calls the callback
-- repeatedly until 'hasMore' is 'False' or 'nextCursor' is 'Nothing',
-- collecting all results into a single 'Vector'.
--
-- Example:
--
-- @
-- allPages <- paginateAll $ \\cursor ->
--   queryDataSource methods dsId QueryDataSource
--     { filter = Nothing
--     , sorts = Nothing
--     , startCursor = cursor
--     , pageSize = Just 100
--     , inTrash = Nothing
--     , filterProperties = Nothing
--     }
-- @
paginateAll :: (Maybe Text -> IO (ListOf a)) -> IO (Vector a)
paginateAll fetch = allResults <$> paginateCollect fetch

-- | Like 'paginateAll' but also returns the number of pages fetched.
paginateCollect :: (Maybe Text -> IO (ListOf a)) -> IO (PaginationResult a)
paginateCollect fetch = go Nothing Vector.empty 0
  where
    go cursor acc pages = do
      List {results, nextCursor, hasMore} <- fetch cursor
      let acc' = acc <> results
          pages' = pages + 1
      if hasMore
        then case nextCursor of
          Just nc -> go (Just nc) acc' pages'
          Nothing -> pure PaginationResult {allResults = acc', totalPages = pages'}
        else pure PaginationResult {allResults = acc', totalPages = pages'}