-- | This module contains types which are common to event triggers and scheduled triggers.
module Hasura.RQL.Types.Eventing
  ( ClientError (..),
    EventId (..),
    Invocation (..),
    InvocationVersion,
    PGTextArray (..),
    Response (..),
    TriggerTypes (..),
    WebhookRequest (..),
    WebhookResponse (..),
    OpVar (..),
    invocationVersionET,
    invocationVersionST,
  )
where

import Data.Aeson
import Data.SerializableBlob qualified as SB
import Data.Text.Extended
import Database.PG.Query qualified as PG
import Database.PG.Query.PTI qualified as PTI
import Hasura.Prelude
import Hasura.RQL.Types.Headers (HeaderConf)
import PostgreSQL.Binary.Encoding qualified as PE

newtype EventId = EventId {EventId -> InvocationVersion
unEventId :: Text}
  deriving (Int -> EventId -> ShowS
[EventId] -> ShowS
EventId -> String
(Int -> EventId -> ShowS)
-> (EventId -> String) -> ([EventId] -> ShowS) -> Show EventId
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> EventId -> ShowS
showsPrec :: Int -> EventId -> ShowS
$cshow :: EventId -> String
show :: EventId -> String
$cshowList :: [EventId] -> ShowS
showList :: [EventId] -> ShowS
Show, EventId -> EventId -> Bool
(EventId -> EventId -> Bool)
-> (EventId -> EventId -> Bool) -> Eq EventId
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: EventId -> EventId -> Bool
== :: EventId -> EventId -> Bool
$c/= :: EventId -> EventId -> Bool
/= :: EventId -> EventId -> Bool
Eq, Eq EventId
Eq EventId
-> (EventId -> EventId -> Ordering)
-> (EventId -> EventId -> Bool)
-> (EventId -> EventId -> Bool)
-> (EventId -> EventId -> Bool)
-> (EventId -> EventId -> Bool)
-> (EventId -> EventId -> EventId)
-> (EventId -> EventId -> EventId)
-> Ord EventId
EventId -> EventId -> Bool
EventId -> EventId -> Ordering
EventId -> EventId -> EventId
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: EventId -> EventId -> Ordering
compare :: EventId -> EventId -> Ordering
$c< :: EventId -> EventId -> Bool
< :: EventId -> EventId -> Bool
$c<= :: EventId -> EventId -> Bool
<= :: EventId -> EventId -> Bool
$c> :: EventId -> EventId -> Bool
> :: EventId -> EventId -> Bool
$c>= :: EventId -> EventId -> Bool
>= :: EventId -> EventId -> Bool
$cmax :: EventId -> EventId -> EventId
max :: EventId -> EventId -> EventId
$cmin :: EventId -> EventId -> EventId
min :: EventId -> EventId -> EventId
Ord, Eq EventId
Eq EventId
-> (Int -> EventId -> Int) -> (EventId -> Int) -> Hashable EventId
Int -> EventId -> Int
EventId -> Int
forall a. Eq a -> (Int -> a -> Int) -> (a -> Int) -> Hashable a
$chashWithSalt :: Int -> EventId -> Int
hashWithSalt :: Int -> EventId -> Int
$chash :: EventId -> Int
hash :: EventId -> Int
Hashable, EventId -> InvocationVersion
(EventId -> InvocationVersion) -> ToTxt EventId
forall a. (a -> InvocationVersion) -> ToTxt a
$ctoTxt :: EventId -> InvocationVersion
toTxt :: EventId -> InvocationVersion
ToTxt, Value -> Parser [EventId]
Value -> Parser EventId
(Value -> Parser EventId)
-> (Value -> Parser [EventId]) -> FromJSON EventId
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
$cparseJSON :: Value -> Parser EventId
parseJSON :: Value -> Parser EventId
$cparseJSONList :: Value -> Parser [EventId]
parseJSONList :: Value -> Parser [EventId]
FromJSON, [EventId] -> Value
[EventId] -> Encoding
EventId -> Value
EventId -> Encoding
(EventId -> Value)
-> (EventId -> Encoding)
-> ([EventId] -> Value)
-> ([EventId] -> Encoding)
-> ToJSON EventId
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
$ctoJSON :: EventId -> Value
toJSON :: EventId -> Value
$ctoEncoding :: EventId -> Encoding
toEncoding :: EventId -> Encoding
$ctoJSONList :: [EventId] -> Value
toJSONList :: [EventId] -> Value
$ctoEncodingList :: [EventId] -> Encoding
toEncodingList :: [EventId] -> Encoding
ToJSON, ToJSONKeyFunction [EventId]
ToJSONKeyFunction EventId
ToJSONKeyFunction EventId
-> ToJSONKeyFunction [EventId] -> ToJSONKey EventId
forall a.
ToJSONKeyFunction a -> ToJSONKeyFunction [a] -> ToJSONKey a
$ctoJSONKey :: ToJSONKeyFunction EventId
toJSONKey :: ToJSONKeyFunction EventId
$ctoJSONKeyList :: ToJSONKeyFunction [EventId]
toJSONKeyList :: ToJSONKeyFunction [EventId]
ToJSONKey, Maybe ByteString -> Either InvocationVersion EventId
(Maybe ByteString -> Either InvocationVersion EventId)
-> FromCol EventId
forall a.
(Maybe ByteString -> Either InvocationVersion a) -> FromCol a
$cfromCol :: Maybe ByteString -> Either InvocationVersion EventId
fromCol :: Maybe ByteString -> Either InvocationVersion EventId
PG.FromCol, EventId -> PrepArg
(EventId -> PrepArg) -> ToPrepArg EventId
forall a. (a -> PrepArg) -> ToPrepArg a
$ctoPrepVal :: EventId -> PrepArg
toPrepVal :: EventId -> PrepArg
PG.ToPrepArg, (forall x. EventId -> Rep EventId x)
-> (forall x. Rep EventId x -> EventId) -> Generic EventId
forall x. Rep EventId x -> EventId
forall x. EventId -> Rep EventId x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. EventId -> Rep EventId x
from :: forall x. EventId -> Rep EventId x
$cto :: forall x. Rep EventId x -> EventId
to :: forall x. Rep EventId x -> EventId
Generic, EventId -> ()
(EventId -> ()) -> NFData EventId
forall a. (a -> ()) -> NFData a
$crnf :: EventId -> ()
rnf :: EventId -> ()
NFData)

-- | There are two types of events: EventType (for event triggers) and ScheduledType (for scheduled triggers)
data TriggerTypes = EventType | ScheduledType

data WebhookRequest = WebhookRequest
  { WebhookRequest -> Value
_rqPayload :: Value,
    WebhookRequest -> [HeaderConf]
_rqHeaders :: [HeaderConf],
    WebhookRequest -> InvocationVersion
_rqVersion :: Text
  }
  deriving stock ((forall x. WebhookRequest -> Rep WebhookRequest x)
-> (forall x. Rep WebhookRequest x -> WebhookRequest)
-> Generic WebhookRequest
forall x. Rep WebhookRequest x -> WebhookRequest
forall x. WebhookRequest -> Rep WebhookRequest x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. WebhookRequest -> Rep WebhookRequest x
from :: forall x. WebhookRequest -> Rep WebhookRequest x
$cto :: forall x. Rep WebhookRequest x -> WebhookRequest
to :: forall x. Rep WebhookRequest x -> WebhookRequest
Generic)

instance ToJSON WebhookRequest where
  toJSON :: WebhookRequest -> Value
toJSON = Options -> WebhookRequest -> Value
forall a.
(Generic a, GToJSON' Value Zero (Rep a)) =>
Options -> a -> Value
genericToJSON Options
hasuraJSON {omitNothingFields :: Bool
omitNothingFields = Bool
True}
  toEncoding :: WebhookRequest -> Encoding
toEncoding = Options -> WebhookRequest -> Encoding
forall a.
(Generic a, GToJSON' Encoding Zero (Rep a)) =>
Options -> a -> Encoding
genericToEncoding Options
hasuraJSON {omitNothingFields :: Bool
omitNothingFields = Bool
True}

data WebhookResponse = WebhookResponse
  { WebhookResponse -> SerializableBlob
_wrsBody :: SB.SerializableBlob,
    WebhookResponse -> [HeaderConf]
_wrsHeaders :: [HeaderConf],
    WebhookResponse -> Int
_wrsStatus :: Int
  }
  deriving stock ((forall x. WebhookResponse -> Rep WebhookResponse x)
-> (forall x. Rep WebhookResponse x -> WebhookResponse)
-> Generic WebhookResponse
forall x. Rep WebhookResponse x -> WebhookResponse
forall x. WebhookResponse -> Rep WebhookResponse x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. WebhookResponse -> Rep WebhookResponse x
from :: forall x. WebhookResponse -> Rep WebhookResponse x
$cto :: forall x. Rep WebhookResponse x -> WebhookResponse
to :: forall x. Rep WebhookResponse x -> WebhookResponse
Generic)

instance ToJSON WebhookResponse where
  toJSON :: WebhookResponse -> Value
toJSON = Options -> WebhookResponse -> Value
forall a.
(Generic a, GToJSON' Value Zero (Rep a)) =>
Options -> a -> Value
genericToJSON Options
hasuraJSON {omitNothingFields :: Bool
omitNothingFields = Bool
True}
  toEncoding :: WebhookResponse -> Encoding
toEncoding = Options -> WebhookResponse -> Encoding
forall a.
(Generic a, GToJSON' Encoding Zero (Rep a)) =>
Options -> a -> Encoding
genericToEncoding Options
hasuraJSON {omitNothingFields :: Bool
omitNothingFields = Bool
True}

newtype ClientError = ClientError {ClientError -> SerializableBlob
_ceMessage :: SB.SerializableBlob}
  deriving stock ((forall x. ClientError -> Rep ClientError x)
-> (forall x. Rep ClientError x -> ClientError)
-> Generic ClientError
forall x. Rep ClientError x -> ClientError
forall x. ClientError -> Rep ClientError x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. ClientError -> Rep ClientError x
from :: forall x. ClientError -> Rep ClientError x
$cto :: forall x. Rep ClientError x -> ClientError
to :: forall x. Rep ClientError x -> ClientError
Generic)

instance ToJSON ClientError where
  toJSON :: ClientError -> Value
toJSON = Options -> ClientError -> Value
forall a.
(Generic a, GToJSON' Value Zero (Rep a)) =>
Options -> a -> Value
genericToJSON Options
hasuraJSON {omitNothingFields :: Bool
omitNothingFields = Bool
True}
  toEncoding :: ClientError -> Encoding
toEncoding = Options -> ClientError -> Encoding
forall a.
(Generic a, GToJSON' Encoding Zero (Rep a)) =>
Options -> a -> Encoding
genericToEncoding Options
hasuraJSON {omitNothingFields :: Bool
omitNothingFields = Bool
True}

data Response (a :: TriggerTypes)
  = ResponseHTTP WebhookResponse
  | ResponseError ClientError

type InvocationVersion = Text

invocationVersionET :: InvocationVersion
invocationVersionET :: InvocationVersion
invocationVersionET = InvocationVersion
"2"

invocationVersionST :: InvocationVersion
invocationVersionST :: InvocationVersion
invocationVersionST = InvocationVersion
"1"

instance ToJSON (Response 'EventType) where
  toJSON :: Response 'EventType -> Value
toJSON (ResponseHTTP WebhookResponse
resp) =
    [Pair] -> Value
object
      [ Key
"type" Key -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= InvocationVersion -> Value
String InvocationVersion
"webhook_response",
        Key
"data" Key -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= WebhookResponse -> Value
forall a. ToJSON a => a -> Value
toJSON WebhookResponse
resp,
        Key
"version" Key -> InvocationVersion -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= InvocationVersion
invocationVersionET
      ]
  toJSON (ResponseError ClientError
err) =
    [Pair] -> Value
object
      [ Key
"type" Key -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= InvocationVersion -> Value
String InvocationVersion
"client_error",
        Key
"data" Key -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= ClientError -> Value
forall a. ToJSON a => a -> Value
toJSON ClientError
err,
        Key
"version" Key -> InvocationVersion -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= InvocationVersion
invocationVersionET
      ]

instance ToJSON (Response 'ScheduledType) where
  toJSON :: Response 'ScheduledType -> Value
toJSON (ResponseHTTP WebhookResponse
resp) =
    [Pair] -> Value
object
      [ Key
"type" Key -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= InvocationVersion -> Value
String InvocationVersion
"webhook_response",
        Key
"data" Key -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= WebhookResponse -> Value
forall a. ToJSON a => a -> Value
toJSON WebhookResponse
resp,
        Key
"version" Key -> InvocationVersion -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= InvocationVersion
invocationVersionST
      ]
  toJSON (ResponseError ClientError
err) =
    [Pair] -> Value
object
      [ Key
"type" Key -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= InvocationVersion -> Value
String InvocationVersion
"client_error",
        Key
"data" Key -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= ClientError -> Value
forall a. ToJSON a => a -> Value
toJSON ClientError
err,
        Key
"version" Key -> InvocationVersion -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= InvocationVersion
invocationVersionST
      ]

data Invocation (a :: TriggerTypes) = Invocation
  { forall (a :: TriggerTypes). Invocation a -> EventId
iEventId :: EventId,
    forall (a :: TriggerTypes). Invocation a -> Maybe Int
iStatus :: Maybe Int,
    forall (a :: TriggerTypes). Invocation a -> WebhookRequest
iRequest :: WebhookRequest,
    forall (a :: TriggerTypes). Invocation a -> Response a
iResponse :: Response a
  }

-- | PGTextArray is only used for PG array encoding
newtype PGTextArray = PGTextArray {PGTextArray -> [InvocationVersion]
unPGTextArray :: [Text]}
  deriving (Int -> PGTextArray -> ShowS
[PGTextArray] -> ShowS
PGTextArray -> String
(Int -> PGTextArray -> ShowS)
-> (PGTextArray -> String)
-> ([PGTextArray] -> ShowS)
-> Show PGTextArray
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PGTextArray -> ShowS
showsPrec :: Int -> PGTextArray -> ShowS
$cshow :: PGTextArray -> String
show :: PGTextArray -> String
$cshowList :: [PGTextArray] -> ShowS
showList :: [PGTextArray] -> ShowS
Show, PGTextArray -> PGTextArray -> Bool
(PGTextArray -> PGTextArray -> Bool)
-> (PGTextArray -> PGTextArray -> Bool) -> Eq PGTextArray
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PGTextArray -> PGTextArray -> Bool
== :: PGTextArray -> PGTextArray -> Bool
$c/= :: PGTextArray -> PGTextArray -> Bool
/= :: PGTextArray -> PGTextArray -> Bool
Eq)

instance PG.ToPrepArg PGTextArray where
  toPrepVal :: PGTextArray -> PrepArg
toPrepVal (PGTextArray [InvocationVersion]
l) =
    Oid
-> ([InvocationVersion] -> Encoding)
-> [InvocationVersion]
-> PrepArg
forall a. Oid -> (a -> Encoding) -> a -> PrepArg
PG.toPrepValHelper Oid
PTI.unknown [InvocationVersion] -> Encoding
encoder [InvocationVersion]
l
    where
      -- 25 is the OID value of TEXT, https://jdbc.postgresql.org/development/privateapi/constant-values.html
      encoder :: [InvocationVersion] -> Encoding
encoder = Word32 -> Array -> Encoding
PE.array Word32
25 (Array -> Encoding)
-> ([InvocationVersion] -> Array)
-> [InvocationVersion]
-> Encoding
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall b.
 (b -> InvocationVersion -> b) -> b -> [InvocationVersion] -> b)
-> (InvocationVersion -> Array) -> [InvocationVersion] -> Array
forall a c.
(forall b. (b -> a -> b) -> b -> c -> b)
-> (a -> Array) -> c -> Array
PE.dimensionArray (b -> InvocationVersion -> b) -> b -> [InvocationVersion] -> b
forall b.
(b -> InvocationVersion -> b) -> b -> [InvocationVersion] -> b
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (Encoding -> Array
PE.encodingArray (Encoding -> Array)
-> (InvocationVersion -> Encoding) -> InvocationVersion -> Array
forall b c a. (b -> c) -> (a -> b) -> a -> c
. InvocationVersion -> Encoding
PE.text_strict)

-- | Used to construct the payload of Event Trigger
--
-- OLD: Depicts the old database row value for UPDATE/DELETE trigger operations.
--      This is used to construct the 'data.old' field of the event trigger
--      payload. The value of 'data.old' is null in INSERT trigger operation.
--
-- NEW: Depicts the new database row value for INSERT/UPDATE trigger operations.
--      This is used to construct the 'data.new' field of the event trigger
--      payload. The value of 'data.new' is null in DELETE trigger operation.
data OpVar = OLD | NEW deriving (Int -> OpVar -> ShowS
[OpVar] -> ShowS
OpVar -> String
(Int -> OpVar -> ShowS)
-> (OpVar -> String) -> ([OpVar] -> ShowS) -> Show OpVar
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> OpVar -> ShowS
showsPrec :: Int -> OpVar -> ShowS
$cshow :: OpVar -> String
show :: OpVar -> String
$cshowList :: [OpVar] -> ShowS
showList :: [OpVar] -> ShowS
Show)