{-# LANGUAGE ConstrainedClassMethods #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE NoImplicitPrelude #-}

module Data.Morpheus.Client.Fetch.RequestType
  ( toRequest,
    decodeResponse,
    Request (..),
    RequestType (..),
    processResponse,
    ClientTypeConstraint,
    isSubscription,
  )
where

import Data.Aeson
  ( FromJSON,
    ToJSON (..),
    eitherDecode,
  )
import qualified Data.Aeson as A
import qualified Data.Aeson.Types as A
import Data.ByteString.Lazy (ByteString)
import Data.Morpheus.Client.Fetch.Types
  ( FetchError (..),
  )
import Data.Morpheus.Client.Schema.JSON.Types
  ( JSONResponse (..),
  )
import Data.Morpheus.Types.IO
  ( GQLRequest (..),
  )
import Data.Morpheus.Types.Internal.AST
  ( FieldName,
    OperationType (..),
  )
import Data.Text
  ( pack,
  )
import Relude hiding (ByteString)

fixVars :: A.Value -> Maybe A.Value
fixVars :: Value -> Maybe Value
fixVars Value
x
  | Value
x forall a. Eq a => a -> a -> Bool
== Value
A.emptyArray = forall a. Maybe a
Nothing
  | Bool
otherwise = forall a. a -> Maybe a
Just Value
x

toRequest :: (RequestType a, ToJSON (RequestArgs a)) => Request a -> GQLRequest
toRequest :: forall a.
(RequestType a, ToJSON (RequestArgs a)) =>
Request a -> GQLRequest
toRequest r :: Request a
r@Request {RequestArgs a
requestArgs :: forall a. Request a -> RequestArgs a
requestArgs :: RequestArgs a
requestArgs} =
  ( GQLRequest
      { operationName :: Maybe FieldName
operationName = forall a. a -> Maybe a
Just (forall a (f :: * -> *). RequestType a => f a -> FieldName
__name Request a
r),
        query :: Text
query = String -> Text
pack (forall a (f :: * -> *). RequestType a => f a -> String
__query Request a
r),
        variables :: Maybe Value
variables = Value -> Maybe Value
fixVars (forall a. ToJSON a => a -> Value
toJSON RequestArgs a
requestArgs)
      }
  )

decodeResponse :: FromJSON a => ByteString -> Either (FetchError a) a
decodeResponse :: forall a. FromJSON a => ByteString -> Either (FetchError a) a
decodeResponse = (forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first forall a. String -> FetchError a
FetchErrorParseFailure forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromJSON a => ByteString -> Either String a
eitherDecode) forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> forall a. JSONResponse a -> Either (FetchError a) a
processResponse

processResponse :: JSONResponse a -> Either (FetchError a) a
processResponse :: forall a. JSONResponse a -> Either (FetchError a) a
processResponse JSONResponse {$sel:responseData:JSONResponse :: forall a. JSONResponse a -> Maybe a
responseData = Just a
x, $sel:responseErrors:JSONResponse :: forall a. JSONResponse a -> [GQLError]
responseErrors = []} = forall a b. b -> Either a b
Right a
x
processResponse JSONResponse {$sel:responseData:JSONResponse :: forall a. JSONResponse a -> Maybe a
responseData = Maybe a
Nothing, $sel:responseErrors:JSONResponse :: forall a. JSONResponse a -> [GQLError]
responseErrors = []} = forall a b. a -> Either a b
Left forall a. FetchError a
FetchErrorNoResult
processResponse JSONResponse {$sel:responseData:JSONResponse :: forall a. JSONResponse a -> Maybe a
responseData = Maybe a
result, $sel:responseErrors:JSONResponse :: forall a. JSONResponse a -> [GQLError]
responseErrors = (GQLError
x : [GQLError]
xs)} = forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ forall a. GQLErrors -> Maybe a -> FetchError a
FetchErrorProducedErrors (GQLError
x forall a. a -> [a] -> NonEmpty a
:| [GQLError]
xs) Maybe a
result

type ClientTypeConstraint (a :: Type) = (RequestType a, ToJSON (RequestArgs a), FromJSON a)

class RequestType a where
  type RequestArgs a :: Type
  __name :: f a -> FieldName
  __query :: f a -> String
  __type :: f a -> OperationType

newtype Request (a :: Type) = Request {forall a. Request a -> RequestArgs a
requestArgs :: RequestArgs a}

isSubscription :: RequestType a => Request a -> Bool
isSubscription :: forall a. RequestType a => Request a -> Bool
isSubscription Request a
x = forall a (f :: * -> *). RequestType a => f a -> OperationType
__type Request a
x forall a. Eq a => a -> a -> Bool
== OperationType
OPERATION_SUBSCRIPTION