content: {-# LANGUAGE DataKinds #-}
  {-# LANGUAGE FlexibleContexts #-}
  {-# LANGUAGE FlexibleInstances #-}
  {-# LANGUAGE GADTs #-}
  {-# LANGUAGE MultiParamTypeClasses #-}
  {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE ScopedTypeVariables #-}
  {-# LANGUAGE TypeFamilies #-}
  {-# LANGUAGE TypeOperators #-}
  {-# LANGUAGE UndecidableInstances #-}
  {-# LANGUAGE NoImplicitPrelude #-}
  
  module Data.Morpheus.Server.Types.NamedResolvers
    ( ResolveNamed (..),
      NamedResolverT (..),
      resolve,
      useBatched,
      Dependency,
      ignoreBatching,
      NamedRef,
    )
  where
  
  import Control.Monad.Except
  import Data.Aeson (ToJSON)
  import Data.Morpheus.Types.ID (ID)
  import Data.Morpheus.Types.Internal.AST (GQLError, internal)
  import Data.Vector (Vector)
  import Relude
  
  type family Target a :: Type where
    Target (Maybe a) = a
    Target [a] = a
    Target (Set a) = a
    Target (NonEmpty a) = a
    Target (Seq a) = a
    Target (Vector a) = a
    Target a = a
  
  type family Dependency a :: Type where
    -- wrappers
    Dependency (Maybe a) = Dependency a
    Dependency [a] = Dependency a
    Dependency (Set a) = Dependency a
    Dependency (NonEmpty a) = Dependency a
    Dependency (Seq a) = Dependency a
    Dependency (Vector a) = Dependency a
    -- custom
    Dependency a = Dep a
  
  ignoreBatching :: (Monad m) => (a -> m b) -> [a] -> m [Maybe b]
  ignoreBatching f = traverse (fmap Just . f)
  
  forward :: (Monad m, Dependency a ~ a) => [Dependency a] -> m [Maybe a]
  forward = pure . map Just
  
  {-# DEPRECATED useBatched " this function is obsolete" #-}
  useBatched :: (ResolveNamed m a, MonadError GQLError m) => Dependency a -> m a
  useBatched x = resolveBatched [x] >>= res
    where
      res [Just v] = pure v
      res _ = throwError (internal "named resolver should return single value for single argument")
  
  {-# DEPRECATED resolveNamed "use: resolveBatched" #-}
  
  instance ResolveNamed m Int where
    type Dep Int = Int
    resolveBatched = forward
  
  instance ResolveNamed m Float where
    type Dep Float = Float
    resolveBatched = forward
  
  instance ResolveNamed m Double where
    type Dep Double = Double
    resolveBatched = forward
  
  instance ResolveNamed m Text where
    type Dep Text = Text
    resolveBatched = forward
  
  instance ResolveNamed m Bool where
    type Dep Bool = Bool
    resolveBatched = forward
  
  instance ResolveNamed m ID where
    type Dep ID = ID
    resolveBatched = forward
  
  class (ToJSON (Dependency a)) => ResolveNamed (m :: Type -> Type) (a :: Type) where
    type Dep a :: Type
    resolveBatched :: (MonadError GQLError m) => [Dependency a] -> m [Maybe a]
  
    resolveNamed :: (MonadError GQLError m) => Dependency a -> m a
    resolveNamed = useBatched
  
  data NamedResolverT (m :: Type -> Type) a where
    NamedResolverT :: (ResolveNamed m (Target a)) => m (NamedRef a) -> NamedResolverT m a
  
  type family NamedRef a :: Type where
    NamedRef [a] = [Dependency a]
    NamedRef (Set a) = [Dependency a]
    NamedRef (NonEmpty a) = [Dependency a]
    NamedRef (Seq a) = [Dependency a]
    NamedRef (Vector a) = [Dependency a]
    NamedRef a = Dependency a
  
  resolve :: (ResolveNamed m (Target a)) => m (NamedRef a) -> NamedResolverT m a
  resolve = NamedResolverT
  