content: {-# LANGUAGE
      CPP
    , FlexibleContexts
    , FlexibleInstances
    , GADTs
    , KindSignatures
    , MultiParamTypeClasses
    , NamedFieldPuns
    , NoImplicitPrelude
    , RankNTypes
    , TypeSynonymInstances
    #-}
  #if MIN_VERSION_base(4,9,0)
  {-# OPTIONS_GHC -Wno-redundant-constraints #-}
  #endif
  -- | A 'Resource' type for representing a REST resource, as well as
  -- smart constructors for empty resources which can then be filled in
  -- using record updates.
  module Rest.Resource
    ( Resource (..)
    , mkResource
    , mkResourceId
    , mkResourceReader
    , mkResourceReaderWith
    , module Rest.Types.Void
    ) where
  
  import Prelude.Compat
  
  import Control.Monad.Reader
  
  import Rest.Handler
  import Rest.Schema (Schema (..), Step (..))
  import Rest.Types.Void
  
  -- * The @Resource@ type.
  
  -- | The 'Resource' data type represents a single resource in a REST
  -- API. Handlers run in a monad @m@, while things below this resource
  -- run in @s@. The identifiers @sid@, @mid@ and @aid@ identify a
  -- single item, a listing and an action.
  
  data Resource m s sid mid aid where
    Resource :: (Applicative m, Monad m, Applicative s, Monad s) =>
      { name        :: String                      -- ^ The name for this resource, used as a path segment in routing.
      , description :: String                      -- ^ A description of the resource, used for documentation.
      , schema      :: Schema sid mid aid          -- ^ The schema for routing and identification.
      , private     :: Bool                        -- ^ Private resources are not documented, but they are exposed.
      , enter       :: forall b. sid -> s b -> m b -- ^ How to run a subresource given an id.
  
      , list        :: mid -> ListHandler m        -- ^ List handler, both toplevel and deeper (search).
  
      , statics     :: aid -> Handler m            -- ^ Static actions, e.g. signin.
  
      , get         :: Maybe (Handler s)           -- ^ Get a single resource identified by id.
      , update      :: Maybe (Handler s)           -- ^ Update a single resource identified by id.
      , remove      :: Maybe (Handler s)           -- ^ Delete a single resource identified by id.
      , create      :: Maybe (Handler m)           -- ^ Create a single resource, generating a new id.
      , actions     :: [(String, Handler s)]       -- ^ Actions performed on a single resource.
      , selects     :: [(String, Handler s)]       -- ^ Properties of a single resource.
      } -> Resource m s sid mid aid
  
  -- * Smart constructors for empty resources.
  
  -- | Create an empty resource given an 'enter' function. It has no
  -- name, so if you wish to route to this resource, you should set one.
  
  mkResource :: (Applicative m, Monad m, Applicative s, Monad s) => (forall b. sid -> s b -> m b) -> Resource m s sid Void Void
  mkResource e = Resource
    { name           = ""
    , description    = ""
    , schema         = Schema Nothing (Named [])
    , private        = False
    , enter          = e
  
    , list           = magic
  
    , statics        = magic
  
    , get            = Nothing
    , update         = Nothing
    , remove         = Nothing
    , create         = Nothing
    , actions        = []
    , selects        = []
    }
  
  -- | Make a resource that doesn't add any information for
  -- subresources (i.e. 'enter' is set to 'id').
  
  mkResourceId :: (Applicative m, Monad m) => Resource m m sid Void Void
  mkResourceId = mkResource (const id)
  
  -- | Make a resource that provides the single resource identifier to
  -- its subresources.
  
  mkResourceReader :: (Applicative m, Monad m) => Resource m (ReaderT sid m) sid Void Void
  mkResourceReader = mkResourceReaderWith id
  
  -- | Make a resource that provides the single resource identifier to
  -- its subresources, by giving a conversion function to a 'ReaderT'.
  -- If @s@ is a newtype around 'ReaderT', for example, the function
  -- should unwrap the newtype.
  
  mkResourceReaderWith :: (Applicative m, Monad m, Applicative s, Monad s) => (forall b. s b -> ReaderT sid m b) -> Resource m s sid Void Void
  mkResourceReaderWith f = mkResource (\a -> flip runReaderT a . f)
  