{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}

module Jordan.Servant.Client.Query where

import Data.Proxy (Proxy (Proxy))
import qualified Data.Text as T
import GHC.Exts (IsList (..))
import GHC.TypeLits
import Jordan
import Jordan.Servant.Query
import Jordan.Servant.Query.Render
import Servant.API
import Servant.API.Modifiers
import Servant.Client.Core

-- | Note: this instances assumes that the Jordan.FromJSON and Jordan.ToJSON instances match.
instance
  forall a sym m api mods.
  (KnownSymbol sym, ToJSON a, HasClient m api, SBoolI (FoldRequired mods)) =>
  HasClient m (JordanQuery' sym mods a :> api)
  where
  type Client m (JordanQuery' sym mods a :> api) = RequiredArgument mods a -> Client m api
  clientWithRoute :: Proxy m
-> Proxy (JordanQuery' sym mods a :> api)
-> Request
-> Client m (JordanQuery' sym mods a :> api)
clientWithRoute Proxy m
pm Proxy (JordanQuery' sym mods a :> api)
Proxy Request
req If (FoldRequired mods) a (Maybe a)
mparam =
    Proxy m -> Proxy api -> Request -> Client m api
forall (m :: * -> *) api.
HasClient m api =>
Proxy m -> Proxy api -> Request -> Client m api
clientWithRoute Proxy m
pm (Proxy api
forall k (t :: k). Proxy t
Proxy @api) (Request -> Client m api) -> Request -> Client m api
forall a b. (a -> b) -> a -> b
$ Proxy mods
-> (a -> Request)
-> (Maybe a -> Request)
-> If (FoldRequired mods) a (Maybe a)
-> Request
forall (mods :: [*]) a r.
SBoolI (FoldRequired mods) =>
Proxy mods
-> (a -> r) -> (Maybe a -> r) -> RequiredArgument mods a -> r
foldRequiredArgument (Proxy mods
forall k (t :: k). Proxy t
Proxy @mods) a -> Request
add (Request -> (a -> Request) -> Maybe a -> Request
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Request
req a -> Request
add) If (FoldRequired mods) a (Maybe a)
mparam
    where
      add :: a -> Request
      add :: a -> Request
add a
param =
        Request
req {requestQueryString :: Seq QueryItem
requestQueryString = Request -> Seq QueryItem
forall body path. RequestF body path -> Seq QueryItem
requestQueryString Request
req Seq QueryItem -> Seq QueryItem -> Seq QueryItem
forall a. Semigroup a => a -> a -> a
<> Seq QueryItem
newItems}
        where
          newItems :: Seq QueryItem
newItems =
            [Item (Seq QueryItem)] -> Seq QueryItem
forall l. IsList l => [Item l] -> l
fromList ([Item (Seq QueryItem)] -> Seq QueryItem)
-> [Item (Seq QueryItem)] -> Seq QueryItem
forall a b. (a -> b) -> a -> b
$
              Text -> a -> Query
forall a. ToJSON a => Text -> a -> Query
renderQueryAtKey
                (String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ Proxy sym -> String
forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal (Proxy sym -> String) -> Proxy sym -> String
forall a b. (a -> b) -> a -> b
$ Proxy sym
forall k (t :: k). Proxy t
Proxy @sym)
                a
param
  hoistClientMonad :: Proxy m
-> Proxy (JordanQuery' sym mods a :> api)
-> (forall x. mon x -> mon' x)
-> Client mon (JordanQuery' sym mods a :> api)
-> Client mon' (JordanQuery' sym mods a :> api)
hoistClientMonad Proxy m
pm Proxy (JordanQuery' sym mods a :> api)
_ forall x. mon x -> mon' x
f Client mon (JordanQuery' sym mods a :> api)
cl = Proxy m
-> Proxy api
-> (forall x. mon x -> mon' x)
-> Client mon api
-> Client mon' api
forall (m :: * -> *) api (mon :: * -> *) (mon' :: * -> *).
HasClient m api =>
Proxy m
-> Proxy api
-> (forall x. mon x -> mon' x)
-> Client mon api
-> Client mon' api
hoistClientMonad Proxy m
pm (Proxy api
forall k (t :: k). Proxy t
Proxy @api) forall x. mon x -> mon' x
f (Client mon api -> Client mon' api)
-> (If (FoldRequired mods) a (Maybe a) -> Client mon api)
-> If (FoldRequired mods) a (Maybe a)
-> Client mon' api
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Client mon (JordanQuery' sym mods a :> api)
If (FoldRequired mods) a (Maybe a) -> Client mon api
cl