-- |Representation of HTTP requests.
module Web.Route.Invertible.Request
  ( Request(..)
  , blankRequest
  ) where

import Web.Route.Invertible.Host
import Web.Route.Invertible.Method
import Web.Route.Invertible.Path
import Web.Route.Invertible.Query
import Web.Route.Invertible.ContentType

-- |A reduced representation of an HTTP request, sufficient for routing.
-- This lets us both pre-process/parse the request to optimize routing, and be agnostic about the incoming request representation.
-- These can be created with one of the framework-specific layers.
data Request = Request
  { Request -> Bool
requestSecure :: Bool
  , Request -> [ByteString]
requestHost :: [HostString]
  , Request -> Method
requestMethod :: Method
  , Request -> [PathString]
requestPath :: [PathString]
  , Request -> QueryParams
requestQuery :: QueryParams
  , Request -> ByteString
requestContentType :: ContentType
  } deriving (Int -> Request -> ShowS
[Request] -> ShowS
Request -> String
(Int -> Request -> ShowS)
-> (Request -> String) -> ([Request] -> ShowS) -> Show Request
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Request -> ShowS
showsPrec :: Int -> Request -> ShowS
$cshow :: Request -> String
show :: Request -> String
$cshowList :: [Request] -> ShowS
showList :: [Request] -> ShowS
Show, Request -> Request -> Bool
(Request -> Request -> Bool)
-> (Request -> Request -> Bool) -> Eq Request
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Request -> Request -> Bool
== :: Request -> Request -> Bool
$c/= :: Request -> Request -> Bool
/= :: Request -> Request -> Bool
Eq)

-- |A blank/unknown request; effectively the default value
blankRequest :: Request
blankRequest :: Request
blankRequest = Request
  { requestSecure :: Bool
requestSecure = Bool
False
  , requestHost :: [ByteString]
requestHost = []
  , requestMethod :: Method
requestMethod = ByteString -> Method
ExtensionMethod ByteString
forall a. Monoid a => a
mempty
  , requestPath :: [PathString]
requestPath = []
  , requestQuery :: QueryParams
requestQuery = QueryParams
forall a. Monoid a => a
mempty
  , requestContentType :: ByteString
requestContentType = ByteString
forall a. Monoid a => a
mempty
  }

-- |Merge two requests, where non-blank values in the second argument take precedence.
instance Semigroup Request where
  Request
a <> :: Request -> Request -> Request
<> Request
b = Request
    { requestSecure :: Bool
requestSecure = (Request -> Bool) -> Bool
forall {a}. Eq a => (Request -> a) -> a
m Request -> Bool
requestSecure
    , requestHost :: [ByteString]
requestHost = (Request -> [ByteString]) -> [ByteString]
forall {a}. Eq a => (Request -> a) -> a
m Request -> [ByteString]
requestHost
    , requestMethod :: Method
requestMethod = (Request -> Method) -> Method
forall {a}. Eq a => (Request -> a) -> a
m Request -> Method
requestMethod
    , requestPath :: [PathString]
requestPath = (Request -> [PathString]) -> [PathString]
forall {a}. Eq a => (Request -> a) -> a
m Request -> [PathString]
requestPath
    , requestQuery :: QueryParams
requestQuery = (Request -> QueryParams) -> QueryParams
forall {a}. Eq a => (Request -> a) -> a
m Request -> QueryParams
requestQuery
    , requestContentType :: ByteString
requestContentType = (Request -> ByteString) -> ByteString
forall {a}. Eq a => (Request -> a) -> a
m Request -> ByteString
requestContentType
    } where
    m :: (Request -> a) -> a
m Request -> a
f
      | Request -> a
f Request
b a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== Request -> a
f Request
blankRequest = Request -> a
f Request
a
      | Bool
otherwise = Request -> a
f Request
b

instance Monoid Request where
  mempty :: Request
mempty = Request
blankRequest