{-# LANGUAGE DeriveAnyClass #-}

module Hasura.RQL.Types.Webhook.Transform.QueryParams
  ( QueryParams (..),
    QueryParamsTransformFn (..),
    TransformCtx (..),
    TransformFn (..),
  )
where

import Autodocodec (HasCodec (codec), dimapCodec, disjointEitherCodec, hashMapCodec)
import Data.Aeson (FromJSON, ToJSON)
import Data.Aeson qualified as J
import Data.HashMap.Strict qualified as HashMap
import Hasura.Prelude
import Hasura.RQL.Types.Webhook.Transform.Class (TransformCtx, TransformFn, UnescapedTemplate)
import Hasura.RQL.Types.Webhook.Transform.Request (RequestTransformCtx)
import Network.HTTP.Client.Transformable qualified as HTTP

-- | The actual query params we are transforming.
--
-- This newtype is necessary because otherwise we end up with an
-- orphan instance.
newtype QueryParams = QueryParams {QueryParams -> Query
unQueryParams :: HTTP.Query}

-- | The defunctionalized transformation 'QueryParams'
data QueryParamsTransformFn
  = AddOrReplace [(UnescapedTemplate, Maybe UnescapedTemplate)]
  | ParamTemplate UnescapedTemplate
  deriving (QueryParamsTransformFn -> ()
(QueryParamsTransformFn -> ()) -> NFData QueryParamsTransformFn
forall a. (a -> ()) -> NFData a
$crnf :: QueryParamsTransformFn -> ()
rnf :: QueryParamsTransformFn -> ()
NFData)
  deriving stock (QueryParamsTransformFn -> QueryParamsTransformFn -> Bool
(QueryParamsTransformFn -> QueryParamsTransformFn -> Bool)
-> (QueryParamsTransformFn -> QueryParamsTransformFn -> Bool)
-> Eq QueryParamsTransformFn
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: QueryParamsTransformFn -> QueryParamsTransformFn -> Bool
== :: QueryParamsTransformFn -> QueryParamsTransformFn -> Bool
$c/= :: QueryParamsTransformFn -> QueryParamsTransformFn -> Bool
/= :: QueryParamsTransformFn -> QueryParamsTransformFn -> Bool
Eq, (forall x. QueryParamsTransformFn -> Rep QueryParamsTransformFn x)
-> (forall x.
    Rep QueryParamsTransformFn x -> QueryParamsTransformFn)
-> Generic QueryParamsTransformFn
forall x. Rep QueryParamsTransformFn x -> QueryParamsTransformFn
forall x. QueryParamsTransformFn -> Rep QueryParamsTransformFn x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. QueryParamsTransformFn -> Rep QueryParamsTransformFn x
from :: forall x. QueryParamsTransformFn -> Rep QueryParamsTransformFn x
$cto :: forall x. Rep QueryParamsTransformFn x -> QueryParamsTransformFn
to :: forall x. Rep QueryParamsTransformFn x -> QueryParamsTransformFn
Generic, Int -> QueryParamsTransformFn -> ShowS
[QueryParamsTransformFn] -> ShowS
QueryParamsTransformFn -> String
(Int -> QueryParamsTransformFn -> ShowS)
-> (QueryParamsTransformFn -> String)
-> ([QueryParamsTransformFn] -> ShowS)
-> Show QueryParamsTransformFn
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> QueryParamsTransformFn -> ShowS
showsPrec :: Int -> QueryParamsTransformFn -> ShowS
$cshow :: QueryParamsTransformFn -> String
show :: QueryParamsTransformFn -> String
$cshowList :: [QueryParamsTransformFn] -> ShowS
showList :: [QueryParamsTransformFn] -> ShowS
Show)

instance HasCodec QueryParamsTransformFn where
  codec :: JSONCodec QueryParamsTransformFn
codec = (Either
   (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
   UnescapedTemplate
 -> QueryParamsTransformFn)
-> (QueryParamsTransformFn
    -> Either
         (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
         UnescapedTemplate)
-> Codec
     Value
     (Either
        (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
        UnescapedTemplate)
     (Either
        (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
        UnescapedTemplate)
-> JSONCodec QueryParamsTransformFn
forall oldOutput newOutput newInput oldInput context.
(oldOutput -> newOutput)
-> (newInput -> oldInput)
-> Codec context oldInput oldOutput
-> Codec context newInput newOutput
dimapCodec Either
  (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
  UnescapedTemplate
-> QueryParamsTransformFn
dec QueryParamsTransformFn
-> Either
     (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
     UnescapedTemplate
enc (Codec
   Value
   (Either
      (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
      UnescapedTemplate)
   (Either
      (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
      UnescapedTemplate)
 -> JSONCodec QueryParamsTransformFn)
-> Codec
     Value
     (Either
        (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
        UnescapedTemplate)
     (Either
        (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
        UnescapedTemplate)
-> JSONCodec QueryParamsTransformFn
forall a b. (a -> b) -> a -> b
$ Codec
  Value
  (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
  (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
-> Codec Value UnescapedTemplate UnescapedTemplate
-> Codec
     Value
     (Either
        (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
        UnescapedTemplate)
     (Either
        (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
        UnescapedTemplate)
forall context input1 output1 input2 output2.
Codec context input1 output1
-> Codec context input2 output2
-> Codec context (Either input1 input2) (Either output1 output2)
disjointEitherCodec Codec
  Value
  (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
  (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
addOrReplaceCodec Codec Value UnescapedTemplate UnescapedTemplate
templateCodec
    where
      addOrReplaceCodec :: Codec
  Value
  (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
  (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
addOrReplaceCodec = JSONCodec (Maybe UnescapedTemplate)
-> Codec
     Value
     (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
     (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
forall k v.
(Eq k, Hashable k, FromJSONKey k, ToJSONKey k) =>
JSONCodec v -> JSONCodec (HashMap k v)
hashMapCodec (forall value. HasCodec value => JSONCodec value
codec @(Maybe UnescapedTemplate))
      templateCodec :: Codec Value UnescapedTemplate UnescapedTemplate
templateCodec = forall value. HasCodec value => JSONCodec value
codec @UnescapedTemplate

      dec :: Either
  (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
  UnescapedTemplate
-> QueryParamsTransformFn
dec (Left HashMap UnescapedTemplate (Maybe UnescapedTemplate)
qps) = [(UnescapedTemplate, Maybe UnescapedTemplate)]
-> QueryParamsTransformFn
AddOrReplace ([(UnescapedTemplate, Maybe UnescapedTemplate)]
 -> QueryParamsTransformFn)
-> [(UnescapedTemplate, Maybe UnescapedTemplate)]
-> QueryParamsTransformFn
forall a b. (a -> b) -> a -> b
$ HashMap UnescapedTemplate (Maybe UnescapedTemplate)
-> [(UnescapedTemplate, Maybe UnescapedTemplate)]
forall k v. HashMap k v -> [(k, v)]
HashMap.toList HashMap UnescapedTemplate (Maybe UnescapedTemplate)
qps
      dec (Right UnescapedTemplate
template) = UnescapedTemplate -> QueryParamsTransformFn
ParamTemplate UnescapedTemplate
template

      enc :: QueryParamsTransformFn
-> Either
     (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
     UnescapedTemplate
enc (AddOrReplace [(UnescapedTemplate, Maybe UnescapedTemplate)]
addOrReplace) = HashMap UnescapedTemplate (Maybe UnescapedTemplate)
-> Either
     (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
     UnescapedTemplate
forall a b. a -> Either a b
Left (HashMap UnescapedTemplate (Maybe UnescapedTemplate)
 -> Either
      (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
      UnescapedTemplate)
-> HashMap UnescapedTemplate (Maybe UnescapedTemplate)
-> Either
     (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
     UnescapedTemplate
forall a b. (a -> b) -> a -> b
$ [(UnescapedTemplate, Maybe UnescapedTemplate)]
-> HashMap UnescapedTemplate (Maybe UnescapedTemplate)
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList [(UnescapedTemplate, Maybe UnescapedTemplate)]
addOrReplace
      enc (ParamTemplate UnescapedTemplate
template) = UnescapedTemplate
-> Either
     (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
     UnescapedTemplate
forall a b. b -> Either a b
Right UnescapedTemplate
template

instance J.ToJSON QueryParamsTransformFn where
  toJSON :: QueryParamsTransformFn -> Value
toJSON (AddOrReplace [(UnescapedTemplate, Maybe UnescapedTemplate)]
addOrReplace) = HashMap UnescapedTemplate (Maybe UnescapedTemplate) -> Value
forall a. ToJSON a => a -> Value
J.toJSON (HashMap UnescapedTemplate (Maybe UnescapedTemplate) -> Value)
-> HashMap UnescapedTemplate (Maybe UnescapedTemplate) -> Value
forall a b. (a -> b) -> a -> b
$ [(UnescapedTemplate, Maybe UnescapedTemplate)]
-> HashMap UnescapedTemplate (Maybe UnescapedTemplate)
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList [(UnescapedTemplate, Maybe UnescapedTemplate)]
addOrReplace
  toJSON (ParamTemplate UnescapedTemplate
template) = UnescapedTemplate -> Value
forall a. ToJSON a => a -> Value
J.toJSON UnescapedTemplate
template

instance J.FromJSON QueryParamsTransformFn where
  parseJSON :: Value -> Parser QueryParamsTransformFn
parseJSON xs :: Value
xs@(J.Object Object
_) = [(UnescapedTemplate, Maybe UnescapedTemplate)]
-> QueryParamsTransformFn
AddOrReplace ([(UnescapedTemplate, Maybe UnescapedTemplate)]
 -> QueryParamsTransformFn)
-> (HashMap UnescapedTemplate (Maybe UnescapedTemplate)
    -> [(UnescapedTemplate, Maybe UnescapedTemplate)])
-> HashMap UnescapedTemplate (Maybe UnescapedTemplate)
-> QueryParamsTransformFn
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HashMap UnescapedTemplate (Maybe UnescapedTemplate)
-> [(UnescapedTemplate, Maybe UnescapedTemplate)]
forall k v. HashMap k v -> [(k, v)]
HashMap.toList (HashMap UnescapedTemplate (Maybe UnescapedTemplate)
 -> QueryParamsTransformFn)
-> Parser (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
-> Parser QueryParamsTransformFn
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value
-> Parser (HashMap UnescapedTemplate (Maybe UnescapedTemplate))
forall a. FromJSON a => Value -> Parser a
J.parseJSON Value
xs
  parseJSON xs :: Value
xs@(J.String Text
_) = UnescapedTemplate -> QueryParamsTransformFn
ParamTemplate (UnescapedTemplate -> QueryParamsTransformFn)
-> Parser UnescapedTemplate -> Parser QueryParamsTransformFn
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser UnescapedTemplate
forall a. FromJSON a => Value -> Parser a
J.parseJSON Value
xs
  parseJSON Value
_ = String -> Parser QueryParamsTransformFn
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Invalid query parameter"

-- NOTE: GHC does not let us attach Haddock documentation to data family
-- instances, so 'QueryParamsTransformFn' is defined separately from this
-- wrapper.
newtype instance TransformFn QueryParams
  = QueryParamsTransformFn_ QueryParamsTransformFn
  deriving stock (Int -> TransformFn QueryParams -> ShowS
[TransformFn QueryParams] -> ShowS
TransformFn QueryParams -> String
(Int -> TransformFn QueryParams -> ShowS)
-> (TransformFn QueryParams -> String)
-> ([TransformFn QueryParams] -> ShowS)
-> Show (TransformFn QueryParams)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> TransformFn QueryParams -> ShowS
showsPrec :: Int -> TransformFn QueryParams -> ShowS
$cshow :: TransformFn QueryParams -> String
show :: TransformFn QueryParams -> String
$cshowList :: [TransformFn QueryParams] -> ShowS
showList :: [TransformFn QueryParams] -> ShowS
Show, TransformFn QueryParams -> TransformFn QueryParams -> Bool
(TransformFn QueryParams -> TransformFn QueryParams -> Bool)
-> (TransformFn QueryParams -> TransformFn QueryParams -> Bool)
-> Eq (TransformFn QueryParams)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: TransformFn QueryParams -> TransformFn QueryParams -> Bool
== :: TransformFn QueryParams -> TransformFn QueryParams -> Bool
$c/= :: TransformFn QueryParams -> TransformFn QueryParams -> Bool
/= :: TransformFn QueryParams -> TransformFn QueryParams -> Bool
Eq, (forall x.
 TransformFn QueryParams -> Rep (TransformFn QueryParams) x)
-> (forall x.
    Rep (TransformFn QueryParams) x -> TransformFn QueryParams)
-> Generic (TransformFn QueryParams)
forall x.
Rep (TransformFn QueryParams) x -> TransformFn QueryParams
forall x.
TransformFn QueryParams -> Rep (TransformFn QueryParams) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x.
TransformFn QueryParams -> Rep (TransformFn QueryParams) x
from :: forall x.
TransformFn QueryParams -> Rep (TransformFn QueryParams) x
$cto :: forall x.
Rep (TransformFn QueryParams) x -> TransformFn QueryParams
to :: forall x.
Rep (TransformFn QueryParams) x -> TransformFn QueryParams
Generic)
  deriving newtype (TransformFn QueryParams -> ()
(TransformFn QueryParams -> ()) -> NFData (TransformFn QueryParams)
forall a. (a -> ()) -> NFData a
$crnf :: TransformFn QueryParams -> ()
rnf :: TransformFn QueryParams -> ()
NFData, Value -> Parser [TransformFn QueryParams]
Value -> Parser (TransformFn QueryParams)
(Value -> Parser (TransformFn QueryParams))
-> (Value -> Parser [TransformFn QueryParams])
-> FromJSON (TransformFn QueryParams)
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
$cparseJSON :: Value -> Parser (TransformFn QueryParams)
parseJSON :: Value -> Parser (TransformFn QueryParams)
$cparseJSONList :: Value -> Parser [TransformFn QueryParams]
parseJSONList :: Value -> Parser [TransformFn QueryParams]
FromJSON, [TransformFn QueryParams] -> Value
[TransformFn QueryParams] -> Encoding
TransformFn QueryParams -> Value
TransformFn QueryParams -> Encoding
(TransformFn QueryParams -> Value)
-> (TransformFn QueryParams -> Encoding)
-> ([TransformFn QueryParams] -> Value)
-> ([TransformFn QueryParams] -> Encoding)
-> ToJSON (TransformFn QueryParams)
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
$ctoJSON :: TransformFn QueryParams -> Value
toJSON :: TransformFn QueryParams -> Value
$ctoEncoding :: TransformFn QueryParams -> Encoding
toEncoding :: TransformFn QueryParams -> Encoding
$ctoJSONList :: [TransformFn QueryParams] -> Value
toJSONList :: [TransformFn QueryParams] -> Value
$ctoEncodingList :: [TransformFn QueryParams] -> Encoding
toEncodingList :: [TransformFn QueryParams] -> Encoding
ToJSON)

newtype instance TransformCtx QueryParams = TransformCtx RequestTransformCtx