-- | Pagination instance for HasClient

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}

module Blockfrost.Client.Pagination
  ( Paged (..)
  , page
  , paged
  , nextPage
  , allPages
  ) where

import Data.Default (Default (def))
import Data.Proxy (Proxy (..))
import Servant.API ((:>))
import Servant.Client.Core (Client, HasClient (..))

import Blockfrost.Util.Pagination
  ( Paged (..)
  , Pagination
  , PaginationExpanded
  , page
  , paged
  , maxPageSize
  , nextPage
  )

-- | Query all results, until we get less than maximum
-- items per page.
allPages :: Monad m => (Paged -> m [a]) -> m [a]
allPages :: forall (m :: * -> *) a. Monad m => (Paged -> m [a]) -> m [a]
allPages Paged -> m [a]
act = do
  let fetch :: Paged -> m [a]
fetch Paged
page' = do
        [a]
res <- Paged -> m [a]
act Paged
page'
        case [a]
res of
          [a]
xs | [a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
xs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
maxPageSize -> [a] -> m [a]
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [a]
xs
          [a]
xs -> do
            [a]
next <- Paged -> m [a]
fetch (Paged -> Paged
nextPage Paged
page')
            [a] -> m [a]
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([a] -> m [a]) -> [a] -> m [a]
forall a b. (a -> b) -> a -> b
$ [a]
xs [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
++ [a]
next
  Paged -> m [a]
fetch Paged
forall a. Default a => a
def

instance HasClient m subApi => HasClient m (Pagination :> subApi) where
    type Client m (Pagination :> subApi) = Paged -> Client m subApi
    clientWithRoute :: Proxy m
-> Proxy (Pagination :> subApi)
-> Request
-> Client m (Pagination :> subApi)
clientWithRoute Proxy m
pm Proxy (Pagination :> subApi)
_ Request
req Paged
paged' =
      Proxy m
-> Proxy (PaginationExpanded subApi)
-> Request
-> Client m (PaginationExpanded subApi)
forall (m :: * -> *) api.
HasClient m api =>
Proxy m -> Proxy api -> Request -> Client m api
clientWithRoute
        Proxy m
pm
        (forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @(PaginationExpanded subApi))
        Request
req
        (Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int) -> Int -> Maybe Int
forall a b. (a -> b) -> a -> b
$ Paged -> Int
countPerPage Paged
paged')
        (Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int) -> Int -> Maybe Int
forall a b. (a -> b) -> a -> b
$ Paged -> Int
pageNumber Paged
paged')

    hoistClientMonad :: forall (mon :: * -> *) (mon' :: * -> *).
Proxy m
-> Proxy (Pagination :> subApi)
-> (forall x. mon x -> mon' x)
-> Client mon (Pagination :> subApi)
-> Client mon' (Pagination :> subApi)
hoistClientMonad Proxy m
pm Proxy (Pagination :> subApi)
_ forall x. mon x -> mon' x
hst Client mon (Pagination :> subApi)
subCli = Proxy m
-> Proxy subApi
-> (forall x. mon x -> mon' x)
-> Client mon subApi
-> Client mon' subApi
forall (m :: * -> *) api (mon :: * -> *) (mon' :: * -> *).
HasClient m api =>
Proxy m
-> Proxy api
-> (forall x. mon x -> mon' x)
-> Client mon api
-> Client mon' api
forall (mon :: * -> *) (mon' :: * -> *).
Proxy m
-> Proxy subApi
-> (forall x. mon x -> mon' x)
-> Client mon subApi
-> Client mon' subApi
hoistClientMonad Proxy m
pm (forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @subApi) mon x -> mon' x
forall x. mon x -> mon' x
hst (Client mon subApi -> Client mon' subApi)
-> (Paged -> Client mon subApi) -> Paged -> Client mon' subApi
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Client mon (Pagination :> subApi)
Paged -> Client mon subApi
subCli