packages feed

servant-matrix-param-0.3.3: src/Servant/MatrixParam/Client/Internal.hs

{-# LANGUAGE DataKinds            #-}
{-# LANGUAGE FlexibleInstances    #-}
{-# LANGUAGE ScopedTypeVariables  #-}
{-# LANGUAGE TypeFamilies         #-}
{-# LANGUAGE TypeOperators        #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Servant.MatrixParam.Client.Internal where

import           Data.Proxy
import qualified Data.Text           as T
import           GHC.TypeLits
import           Servant.API
import           Servant.Client
import           Servant.Common.Req
import           Servant.MatrixParam

instance
  ( HasClient (WMP mat :> api)
  , KnownSymbol path
  )
  => HasClient (WithMatrixParams path mat :> api) where

  type Client (WithMatrixParams path mat :> api)
    = Client (WMP mat :> api)

  clientWithRoute Proxy req =
    clientWithRoute (Proxy :: Proxy (WMP mat :> api))
                    req { reqPath = reqPath req ++ "/" ++ path }
    where
     path = symbolVal (Proxy :: Proxy path)

instance
  ( HasClient (WMP mat :> api)
  , ToHttpApiData captureType
  )
  => HasClient (CaptureWithMatrixParams info captureType mat :> api) where

  type Client (CaptureWithMatrixParams info captureType mat :> api)
    = captureType -> Client (WMP mat :> api)

  clientWithRoute Proxy req = \capture ->
    clientWithRoute (Proxy :: Proxy (WMP mat :> api))
                    req { reqPath = reqPath req ++ "/" ++ T.unpack (toUrlPiece capture) }


-- This is just a dummy used to keep track of whether we have already processed
-- the leading path. If we are in a WMP instance, we have already dealt with
-- the leading path, and can just proceed recursively over the matrix params.
-- If not, we deal with the leading path, and call the WMP instance. WMP itself
-- should not be exported.
data WMP (x :: [*])

instance
  ( HasClient (WMP rest :> api)
  , ToHttpApiData v
  , KnownSymbol k
  ) => HasClient (WMP (MatrixParam k v ': rest) :> api) where

  type Client (WMP (MatrixParam k v ': rest) :> api)
    = Maybe v -> Client (WMP rest :> api)

  clientWithRoute Proxy req x = case x of
    Nothing -> clientWithRoute nextProxy req
    Just v  -> clientWithRoute nextProxy
      req { reqPath = reqPath req ++ ";" ++ key ++ "=" ++ T.unpack (toQueryParam v) }
    where
      nextProxy :: Proxy (WMP rest :> api)
      nextProxy = Proxy

      key :: String
      key = symbolVal (Proxy :: Proxy k)

instance
  ( HasClient (WMP rest :> api)
  , KnownSymbol k
  ) => HasClient (WMP (MatrixFlag k ': rest) :> api) where

  type Client (WMP (MatrixFlag k ': rest) :> api)
    = Bool -> Client (WMP rest :> api)

  clientWithRoute Proxy req flag
    | flag = clientWithRoute nextProxy
        req { reqPath = reqPath req ++ ";" ++ key }
    | otherwise = clientWithRoute nextProxy req
    where
      nextProxy :: Proxy (WMP rest :> api)
      nextProxy = Proxy

      key :: String
      key = symbolVal (Proxy :: Proxy k)

instance
  ( HasClient api
  ) => HasClient (WMP '[] :> api) where

  type Client (WMP '[] :> api) = Client api

  clientWithRoute Proxy req =
    clientWithRoute (Proxy :: Proxy api) req