-- |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 -> [HostString]
requestHost :: [HostString]
  , Request -> Method
requestMethod :: Method
  , Request -> [PathString]
requestPath :: [PathString]
  , Request -> QueryParams
requestQuery :: QueryParams
  , Request -> HostString
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
showList :: [Request] -> ShowS
$cshowList :: [Request] -> ShowS
show :: Request -> String
$cshow :: Request -> String
showsPrec :: Int -> Request -> ShowS
$cshowsPrec :: Int -> Request -> ShowS
Show, Request -> Request -> Bool
(Request -> Request -> Bool)
-> (Request -> Request -> Bool) -> Eq Request
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Request -> Request -> Bool
$c/= :: Request -> Request -> Bool
== :: Request -> Request -> Bool
$c== :: Request -> Request -> Bool
Eq)

-- |A blank/unknown request; effectively the default value
blankRequest :: Request
blankRequest :: Request
blankRequest = Request :: Bool
-> [HostString]
-> Method
-> [PathString]
-> QueryParams
-> HostString
-> Request
Request
  { requestSecure :: Bool
requestSecure = Bool
False
  , requestHost :: [HostString]
requestHost = []
  , requestMethod :: Method
requestMethod = HostString -> Method
ExtensionMethod HostString
forall a. Monoid a => a
mempty
  , requestPath :: [PathString]
requestPath = []
  , requestQuery :: QueryParams
requestQuery = QueryParams
forall a. Monoid a => a
mempty
  , requestContentType :: HostString
requestContentType = HostString
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 :: Bool
-> [HostString]
-> Method
-> [PathString]
-> QueryParams
-> HostString
-> Request
Request
    { requestSecure :: Bool
requestSecure = (Request -> Bool) -> Bool
forall p. Eq p => (Request -> p) -> p
m Request -> Bool
requestSecure
    , requestHost :: [HostString]
requestHost = (Request -> [HostString]) -> [HostString]
forall p. Eq p => (Request -> p) -> p
m Request -> [HostString]
requestHost
    , requestMethod :: Method
requestMethod = (Request -> Method) -> Method
forall p. Eq p => (Request -> p) -> p
m Request -> Method
requestMethod
    , requestPath :: [PathString]
requestPath = (Request -> [PathString]) -> [PathString]
forall p. Eq p => (Request -> p) -> p
m Request -> [PathString]
requestPath
    , requestQuery :: QueryParams
requestQuery = (Request -> QueryParams) -> QueryParams
forall p. Eq p => (Request -> p) -> p
m Request -> QueryParams
requestQuery
    , requestContentType :: HostString
requestContentType = (Request -> HostString) -> HostString
forall p. Eq p => (Request -> p) -> p
m Request -> HostString
requestContentType
    } where
    m :: (Request -> p) -> p
m Request -> p
f
      | Request -> p
f Request
b p -> p -> Bool
forall a. Eq a => a -> a -> Bool
== Request -> p
f Request
blankRequest = Request -> p
f Request
a
      | Bool
otherwise = Request -> p
f Request
b

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