content: {-# LANGUAGE FlexibleInstances #-}
  module Network.HTTP.Types.QueryLike
  (
    QueryLike(..)
  , QueryKeyLike(..)
  , QueryValueLike(..)
  )
  where
  
  import           Network.HTTP.Types.URI
  import           Data.Maybe
  import qualified Data.ByteString        as B
  import qualified Data.ByteString.Lazy   as L
  import qualified Data.Text              as T
  import qualified Data.Text.Encoding     as T
  import           Control.Arrow
  
  -- | Types which can, and commonly are, converted to 'Query' are in this class.
  -- 
  -- You can use lists of simple key value pairs, with 'B.ByteString' (strict, or lazy: 
  -- 'L.ByteString'), 'T.Text', or 'String' as the key/value types. You can also have the value
  -- type lifted into a Maybe to support keys without values; and finally it is possible to put
  -- each pair into a Maybe for key-value pairs that aren't always present.
  class QueryLike a where
    -- | Convert to 'Query'.
    toQuery :: a -> Query
  
  -- | Types which, in a Query-like key-value list, are used in the Key position.
  class QueryKeyLike a where
    toQueryKey :: a -> B.ByteString
  
  -- | Types which, in a Query-like key-value list, are used in the Value position.
  class QueryValueLike a where
    toQueryValue :: a -> Maybe B.ByteString
  
  instance (QueryKeyLike k, QueryValueLike v) => QueryLike [(k, v)] where
    toQuery = map (toQueryKey *** toQueryValue)
  
  instance (QueryKeyLike k, QueryValueLike v) => QueryLike [Maybe (k, v)] where
    toQuery = toQuery . catMaybes
  
  instance QueryKeyLike B.ByteString where toQueryKey = id
  instance QueryKeyLike L.ByteString where toQueryKey = B.concat . L.toChunks
  instance QueryKeyLike T.Text where toQueryKey = T.encodeUtf8
  instance QueryKeyLike [Char] where toQueryKey = T.encodeUtf8 . T.pack
  
  instance QueryValueLike B.ByteString where toQueryValue = Just
  instance QueryValueLike L.ByteString where toQueryValue = Just . B.concat . L.toChunks
  instance QueryValueLike T.Text where toQueryValue = Just . T.encodeUtf8
  instance QueryValueLike [Char] where toQueryValue = Just . T.encodeUtf8 . T.pack
  
  instance QueryValueLike a => QueryValueLike (Maybe a) where
    toQueryValue = maybe Nothing toQueryValue