{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE NoImplicitPrelude #-}

-- | GQL Types
module Data.Morpheus.Types
  ( GQLType (KIND, description, implements, getDescriptions, typeOptions, getDirectives),
    EncodeScalar (..),
    EncodeWrapper (..),
    DecodeScalar (..),
    DecodeWrapper (..),
    GQLRequest (..),
    GQLResponse (..),
    ID (..),
    ScalarValue (..),
    RootResolver (..),
    constRes,
    constMutRes,
    Undefined (..),
    Resolver,
    QUERY,
    MUTATION,
    SUBSCRIPTION,
    lift,
    liftEither,
    failRes,
    WithOperation,
    publish,
    subscribe,
    unsafeInternalContext,
    ResolverContext (..),
    -- Resolvers
    ResolverO,
    ComposedResolver,
    ResolverQ,
    ResolverM,
    ResolverS,
    -- Resolvers Deprecated
    ResolveQ,
    ResolveM,
    ResolveS,
    Res,
    MutRes,
    SubRes,
    IORes,
    IOMutRes,
    IOSubRes,
    interface,
    SubscriptionField,
    App,
    RenderGQL,
    render,
    GQLTypeOptions (..),
  )
where

import Control.Applicative (pure)
import Control.Monad (Monad ((>>=)))
import Control.Monad.Fail (fail)
import Control.Monad.Trans.Class (MonadTrans (..))
import Data.Either
  ( Either (..),
    either,
  )
import Data.Morpheus.App
  ( App,
  )
import Data.Morpheus.App.Internal.Resolving
  ( Failure,
    PushEvents (..),
    Resolver,
    ResolverContext (..),
    SubscriptionField,
    WithOperation,
    failure,
    pushEvents,
    subscribe,
    unsafeInternalContext,
  )
import Data.Morpheus.Core
  ( RenderGQL,
    render,
  )
import Data.Morpheus.Server.Deriving.Schema
  ( DeriveType,
    SchemaT,
    deriveImplementsInterface,
  )
import Data.Morpheus.Server.Types.GQLType
  ( GQLType (..),
    GQLTypeOptions (..),
  )
import Data.Morpheus.Server.Types.Types (Undefined (..))
import Data.Morpheus.Types.GQLScalar
  ( DecodeScalar (..),
    EncodeScalar (..),
  )
import Data.Morpheus.Types.GQLWrapper
  ( DecodeWrapper (..),
    EncodeWrapper (..),
  )
import Data.Morpheus.Types.ID (ID (..))
import Data.Morpheus.Types.IO
  ( GQLRequest (..),
    GQLResponse (..),
  )
import Data.Morpheus.Types.Internal.AST
  ( MUTATION,
    Message,
    OUT,
    QUERY,
    SUBSCRIPTION,
    ScalarValue (..),
    TypeName,
    msg,
  )
import Data.Proxy
  ( Proxy (..),
  )
import Prelude
  ( ($),
    (.),
    IO,
    String,
    const,
  )

class FlexibleResolver (f :: * -> *) (a :: k) where
  type Flexible (m :: * -> *) a :: *
  type Composed (m :: * -> *) f a :: *

instance FlexibleResolver f (a :: *) where
  type Flexible m a = m a
  type Composed m f a = m (f a)

instance FlexibleResolver f (a :: (* -> *) -> *) where
  type Flexible m a = m (a m)
  type Composed m f a = m (f (a m))

-- Recursive Resolvers
type ResolverO o e m a =
  (WithOperation o) =>
  Flexible (Resolver o e m) a

type ComposedResolver o e m f a =
  (WithOperation o) =>
  Composed (Resolver o e m) f a

type ResolverQ e m a = Flexible (Resolver QUERY e m) a

type ResolverM e m a = Flexible (Resolver MUTATION e m) a

type ResolverS e m a = Flexible (Resolver SUBSCRIPTION e m) a

{-# DEPRECATED Res "use ResolverQ" #-}

type Res = Resolver QUERY

{-# DEPRECATED MutRes "use ResolverM" #-}

type MutRes = Resolver MUTATION

{-# DEPRECATED SubRes "use ResolverS" #-}

type SubRes = Resolver SUBSCRIPTION

{-# DEPRECATED IORes "use ResolverQ" #-}

type IORes e = Res e IO

{-# DEPRECATED IOMutRes "use ResolverM" #-}

type IOMutRes e = MutRes e IO

{-# DEPRECATED IOSubRes "use ResolverS" #-}

type IOSubRes e = SubRes e IO

{-# DEPRECATED ResolveQ "use ResolverQ" #-}

type ResolveQ e m a = ResolverQ e m a

{-# DEPRECATED ResolveM "use ResolverM" #-}

type ResolveM e m a = ResolverM e m a

{-# DEPRECATED ResolveS "use ResolverS" #-}

type ResolveS e m a = ResolverS e m a

publish :: Monad m => [e] -> Resolver MUTATION e m ()
publish :: [e] -> Resolver MUTATION e m ()
publish = [e] -> Resolver MUTATION e m ()
forall e (m :: * -> *). PushEvents e m => [e] -> m ()
pushEvents

-- resolves constant value on any argument
constRes :: (WithOperation o, Monad m) => b -> a -> Resolver o e m b
constRes :: b -> a -> Resolver o e m b
constRes = Resolver o e m b -> a -> Resolver o e m b
forall a b. a -> b -> a
const (Resolver o e m b -> a -> Resolver o e m b)
-> (b -> Resolver o e m b) -> b -> a -> Resolver o e m b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> Resolver o e m b
forall (f :: * -> *) a. Applicative f => a -> f a
pure

constMutRes :: Monad m => [e] -> a -> args -> ResolverM e m a
constMutRes :: [e] -> a -> args -> ResolverM e m a
constMutRes [e]
events a
value = Resolver MUTATION e m a -> args -> Resolver MUTATION e m a
forall a b. a -> b -> a
const (Resolver MUTATION e m a -> args -> Resolver MUTATION e m a)
-> Resolver MUTATION e m a -> args -> Resolver MUTATION e m a
forall a b. (a -> b) -> a -> b
$ do
  [e] -> Resolver MUTATION e m ()
forall (m :: * -> *) e. Monad m => [e] -> Resolver MUTATION e m ()
publish [e]
events
  a -> Resolver MUTATION e m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
value

{-# DEPRECATED failRes "use \"fail\" from \"MonadFail\"" #-}
failRes ::
  ( Monad m,
    WithOperation o
  ) =>
  String ->
  Resolver o e m a
failRes :: String -> Resolver o e m a
failRes = String -> Resolver o e m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail

liftEither :: (MonadTrans t, Monad (t m), Failure Message (t m)) => Monad m => m (Either String a) -> t m a
liftEither :: m (Either String a) -> t m a
liftEither m (Either String a)
x = m (Either String a) -> t m (Either String a)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift m (Either String a)
x t m (Either String a) -> (Either String a -> t m a) -> t m a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (String -> t m a) -> (a -> t m a) -> Either String a -> t m a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (Message -> t m a
forall error (f :: * -> *) v. Failure error f => error -> f v
failure (Message -> t m a) -> (String -> Message) -> String -> t m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Message
forall a. Msg a => a -> Message
msg) a -> t m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure

-- | GraphQL Root resolver, also the interpreter generates a GQL schema from it.
--  'queryResolver' is required, 'mutationResolver' and 'subscriptionResolver' are optional,
--  if your schema does not supports __mutation__ or __subscription__ , you can use __()__ for it.
data RootResolver (m :: * -> *) event (query :: (* -> *) -> *) (mut :: (* -> *) -> *) (sub :: (* -> *) -> *) = RootResolver
  { RootResolver m event query mut sub
-> query (Resolver QUERY event m)
queryResolver :: query (Resolver QUERY event m),
    RootResolver m event query mut sub
-> mut (Resolver MUTATION event m)
mutationResolver :: mut (Resolver MUTATION event m),
    RootResolver m event query mut sub
-> sub (Resolver SUBSCRIPTION event m)
subscriptionResolver :: sub (Resolver SUBSCRIPTION event m)
  }

interface :: (GQLType a, DeriveType OUT a) => Proxy a -> SchemaT OUT TypeName
interface :: Proxy a -> SchemaT OUT TypeName
interface = Proxy a -> SchemaT OUT TypeName
forall a (f :: * -> *).
(GQLType a, DeriveType OUT a) =>
f a -> SchemaT OUT TypeName
deriveImplementsInterface