server: remove the extraneous drop function while creating an event trigger

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/3956
GitOrigin-RevId: 6d97ffce00fe17ca7f15a8e74acbc1b3d974f7b4
This commit is contained in:
Karthikeyan Chinnakonda 2022-03-15 14:11:03 +05:30 committed by hasura-bot
parent 69501b2657
commit c6a7f4c488
6 changed files with 94 additions and 24 deletions

View File

@ -9,6 +9,7 @@ module Hasura.Backends.Postgres.DDL.EventTrigger
dropTriggerAndArchiveEvents, dropTriggerAndArchiveEvents,
createTableEventTrigger, createTableEventTrigger,
dropTriggerQ, dropTriggerQ,
dropDanglingSQLTrigger,
mkAllTriggersQ, mkAllTriggersQ,
getMaintenanceModeVersion, getMaintenanceModeVersion,
fetchUndeliveredEvents, fetchUndeliveredEvents,
@ -189,12 +190,24 @@ createTableEventTrigger ::
Maybe (PrimaryKey ('Postgres pgKind) (ColumnInfo ('Postgres pgKind))) -> Maybe (PrimaryKey ('Postgres pgKind) (ColumnInfo ('Postgres pgKind))) ->
m (Either QErr ()) m (Either QErr ())
createTableEventTrigger serverConfigCtx sourceConfig table columns triggerName opsDefinition _ = runPgSourceWriteTx sourceConfig $ do createTableEventTrigger serverConfigCtx sourceConfig table columns triggerName opsDefinition _ = runPgSourceWriteTx sourceConfig $ do
-- Clean all existing triggers
liftTx $ dropTriggerQ triggerName -- executes DROP IF EXISTS.. sql
-- Create the given triggers -- Create the given triggers
flip runReaderT serverConfigCtx $ flip runReaderT serverConfigCtx $
mkAllTriggersQ triggerName table columns opsDefinition mkAllTriggersQ triggerName table columns opsDefinition
dropDanglingSQLTrigger ::
( MonadIO m,
MonadError QErr m
) =>
SourceConfig ('Postgres pgKind) ->
TriggerName ->
HashSet Ops ->
m ()
dropDanglingSQLTrigger sourceConfig triggerName ops =
liftEitherM $
liftIO $
runPgSourceWriteTx sourceConfig $
traverse_ (dropTriggerOp triggerName) ops
updateColumnInEventTrigger :: updateColumnInEventTrigger ::
QualifiedTable -> QualifiedTable ->
PGCol -> PGCol ->
@ -464,21 +477,21 @@ setRetryTx e time = \case
dropTriggerQ :: TriggerName -> Q.TxE QErr () dropTriggerQ :: TriggerName -> Q.TxE QErr ()
dropTriggerQ trn = dropTriggerQ trn =
mapM_ mapM_ (dropTriggerOp trn) [INSERT, UPDATE, DELETE]
( \op ->
dropTriggerOp :: TriggerName -> Ops -> Q.TxE QErr ()
dropTriggerOp triggerName triggerOp =
Q.unitQE Q.unitQE
defaultTxErrorHandler defaultTxErrorHandler
(Q.fromText $ getDropFuncSql op) (Q.fromText $ getDropFuncSql triggerOp)
() ()
False False
)
[INSERT, UPDATE, DELETE]
where where
getDropFuncSql :: Ops -> Text getDropFuncSql :: Ops -> Text
getDropFuncSql op = getDropFuncSql op =
"DROP FUNCTION IF EXISTS" "DROP FUNCTION IF EXISTS"
<> " hdb_catalog." <> " hdb_catalog."
<> pgIdenTrigger op trn <> pgIdenTrigger op triggerName
<> "()" <> "()"
<> " CASCADE" <> " CASCADE"

View File

@ -35,6 +35,7 @@ import Data.ByteString.Lazy qualified as LBS
import Data.Environment qualified as Env import Data.Environment qualified as Env
import Data.HashMap.Strict qualified as HM import Data.HashMap.Strict qualified as HM
import Data.HashMap.Strict.InsOrd qualified as OMap import Data.HashMap.Strict.InsOrd qualified as OMap
import Data.HashSet qualified as Set
import Data.Text qualified as T import Data.Text qualified as T
import Data.Text.Extended import Data.Text.Extended
import Hasura.Base.Error import Hasura.Base.Error
@ -146,7 +147,7 @@ resolveEventTriggerQuery ::
forall b m. forall b m.
(Backend b, UserInfoM m, QErrM m, CacheRM m) => (Backend b, UserInfoM m, QErrM m, CacheRM m) =>
CreateEventTriggerQuery b -> CreateEventTriggerQuery b ->
m (TableCoreInfo b, Bool, EventTriggerConf b) m (Bool, EventTriggerConf b)
resolveEventTriggerQuery (CreateEventTriggerQuery source name qt insert update delete enableManual retryConf webhook webhookFromEnv mheaders replace reqTransform respTransform) = do resolveEventTriggerQuery (CreateEventTriggerQuery source name qt insert update delete enableManual retryConf webhook webhookFromEnv mheaders replace reqTransform respTransform) = do
ti <- askTableCoreInfo source qt ti <- askTableCoreInfo source qt
-- can only replace for same table -- can only replace for same table
@ -159,20 +160,31 @@ resolveEventTriggerQuery (CreateEventTriggerQuery source name qt insert update d
assertCols ti delete assertCols ti delete
let rconf = fromMaybe defaultRetryConf retryConf let rconf = fromMaybe defaultRetryConf retryConf
return (ti, replace, EventTriggerConf name (TriggerOpsDef insert update delete enableManual) webhook webhookFromEnv rconf mheaders reqTransform respTransform) return (replace, EventTriggerConf name (TriggerOpsDef insert update delete enableManual) webhook webhookFromEnv rconf mheaders reqTransform respTransform)
where where
assertCols :: TableCoreInfo b -> Maybe (SubscribeOpSpec b) -> m () assertCols :: TableCoreInfo b -> Maybe (SubscribeOpSpec b) -> m ()
assertCols ti opSpec = onJust opSpec \sos -> case sosColumns sos of assertCols ti opSpec = onJust opSpec \sos -> case sosColumns sos of
SubCStar -> return () SubCStar -> return ()
SubCArray columns -> forM_ columns (assertColumnExists @b (_tciFieldInfoMap ti) "") SubCArray columns -> forM_ columns (assertColumnExists @b (_tciFieldInfoMap ti) "")
droppedTriggerOps :: TriggerOpsDef b -> TriggerOpsDef b -> HashSet Ops
droppedTriggerOps oldEventTriggerOps newEventTriggerOps =
Set.fromList $
catMaybes $
[ (bool Nothing (Just INSERT) (isDroppedOp (tdInsert oldEventTriggerOps) (tdInsert newEventTriggerOps))),
(bool Nothing (Just UPDATE) (isDroppedOp (tdUpdate oldEventTriggerOps) (tdUpdate newEventTriggerOps))),
(bool Nothing (Just DELETE) (isDroppedOp (tdDelete oldEventTriggerOps) (tdDelete newEventTriggerOps)))
]
where
isDroppedOp old new = isJust old && isNothing new
createEventTriggerQueryMetadata :: createEventTriggerQueryMetadata ::
forall b m. forall b m.
(BackendMetadata b, QErrM m, UserInfoM m, CacheRWM m, MetadataM m) => (BackendMetadata b, QErrM m, UserInfoM m, CacheRWM m, MetadataM m, BackendEventTrigger b, MonadIO m) =>
CreateEventTriggerQuery b -> CreateEventTriggerQuery b ->
m (TableCoreInfo b, EventTriggerConf b) m ()
createEventTriggerQueryMetadata q = do createEventTriggerQueryMetadata q = do
(tableCoreInfo, replace, triggerConf) <- resolveEventTriggerQuery q (replace, triggerConf) <- resolveEventTriggerQuery q
let table = _cetqTable q let table = _cetqTable q
source = _cetqSource q source = _cetqSource q
triggerName = etcName triggerConf triggerName = etcName triggerConf
@ -181,21 +193,26 @@ createEventTriggerQueryMetadata q = do
AB.mkAnyBackend $ AB.mkAnyBackend $
SMOTableObj @b table $ SMOTableObj @b table $
MTOTrigger triggerName MTOTrigger triggerName
sourceInfo <- askSourceInfo @b source
when replace $ do
existingEventTriggerOps <- etiOpsDef <$> askEventTriggerInfo @b source triggerName
let droppedOps = droppedTriggerOps existingEventTriggerOps (etcDefinition triggerConf)
dropDanglingSQLTrigger @b (_siConfiguration sourceInfo) triggerName droppedOps
buildSchemaCacheFor metadataObj $ buildSchemaCacheFor metadataObj $
MetadataModifier $ MetadataModifier $
tableMetadataSetter @b source table . tmEventTriggers tableMetadataSetter @b source table . tmEventTriggers
%~ if replace %~ if replace
then ix triggerName .~ triggerConf then ix triggerName .~ triggerConf
else OMap.insert triggerName triggerConf else OMap.insert triggerName triggerConf
pure (tableCoreInfo, triggerConf)
runCreateEventTriggerQuery :: runCreateEventTriggerQuery ::
forall b m. forall b m.
(BackendMetadata b, QErrM m, UserInfoM m, CacheRWM m, MetadataM m) => (BackendMetadata b, BackendEventTrigger b, QErrM m, UserInfoM m, CacheRWM m, MetadataM m, MonadIO m) =>
CreateEventTriggerQuery b -> CreateEventTriggerQuery b ->
m EncJSON m EncJSON
runCreateEventTriggerQuery q = do runCreateEventTriggerQuery q = do
void $ createEventTriggerQueryMetadata @b q createEventTriggerQueryMetadata @b q
pure successMsg pure successMsg
runDeleteEventTriggerQuery :: runDeleteEventTriggerQuery ::

View File

@ -30,6 +30,7 @@ import Data.Has (Has, getter)
import Data.HashMap.Strict qualified as Map import Data.HashMap.Strict qualified as Map
import Data.HashMap.Strict.InsOrd.Extended qualified as OMap import Data.HashMap.Strict.InsOrd.Extended qualified as OMap
import Data.HashSet qualified as HS import Data.HashSet qualified as HS
import Data.HashSet qualified as Set
import Data.List qualified as L import Data.List qualified as L
import Data.TByteString qualified as TBS import Data.TByteString qualified as TBS
import Data.Text qualified as T import Data.Text qualified as T
@ -58,6 +59,7 @@ import Hasura.RQL.DDL.Webhook.Transform
import Hasura.RQL.DDL.Webhook.Transform.Class (mkReqTransformCtx) import Hasura.RQL.DDL.Webhook.Transform.Class (mkReqTransformCtx)
import Hasura.RQL.Types import Hasura.RQL.Types
import Hasura.RQL.Types.Endpoint import Hasura.RQL.Types.Endpoint
import Hasura.RQL.Types.EventTrigger qualified as ET
import Hasura.RQL.Types.Eventing.Backend (BackendEventTrigger (..)) import Hasura.RQL.Types.Eventing.Backend (BackendEventTrigger (..))
import Hasura.SQL.AnyBackend qualified as AB import Hasura.SQL.AnyBackend qualified as AB
import Network.HTTP.Client.Transformable qualified as HTTP import Network.HTTP.Client.Transformable qualified as HTTP
@ -279,7 +281,8 @@ runReplaceMetadataV2 ReplaceMetadataV2 {..} = do
dispatch oldBackendSourceMetadata \oldSourceMetadata -> do dispatch oldBackendSourceMetadata \oldSourceMetadata -> do
let oldTriggersMap = getTriggersMap oldSourceMetadata let oldTriggersMap = getTriggersMap oldSourceMetadata
newTriggersMap = getTriggersMap newSourceMetadata newTriggersMap = getTriggersMap newSourceMetadata
droppedTriggers = OMap.keys $ oldTriggersMap `OMap.difference` newTriggersMap droppedEventTriggers = OMap.keys $ oldTriggersMap `OMap.difference` newTriggersMap
retainedNewTriggers = newTriggersMap `OMap.intersection` oldTriggersMap
catcher e@QErr {qeCode} catcher e@QErr {qeCode}
| qeCode == Unexpected = pure () -- NOTE: This information should be returned by the inconsistent_metadata response, so doesn't need additional logging. | qeCode == Unexpected = pure () -- NOTE: This information should be returned by the inconsistent_metadata response, so doesn't need additional logging.
| otherwise = throwError e -- rethrow other errors | otherwise = throwError e -- rethrow other errors
@ -292,7 +295,20 @@ runReplaceMetadataV2 ReplaceMetadataV2 {..} = do
return $ return $
flip catchError catcher do flip catchError catcher do
sourceConfig <- askSourceConfig @b source sourceConfig <- askSourceConfig @b source
for_ droppedTriggers $ dropTriggerAndArchiveEvents @b sourceConfig for_ droppedEventTriggers $ dropTriggerAndArchiveEvents @b sourceConfig
for_ (OMap.toList retainedNewTriggers) $ \(retainedNewTriggerName, retainedNewTriggerConf) ->
case OMap.lookup retainedNewTriggerName oldTriggersMap of
Nothing -> pure ()
Just oldTriggerConf -> do
let newTriggerOps = etcDefinition retainedNewTriggerConf
oldTriggerOps = etcDefinition oldTriggerConf
isDroppedOp old new = isJust old && isNothing new
droppedOps =
[ (bool Nothing (Just INSERT) (isDroppedOp (tdInsert oldTriggerOps) (tdInsert newTriggerOps))),
(bool Nothing (Just UPDATE) (isDroppedOp (tdUpdate oldTriggerOps) (tdUpdate newTriggerOps))),
(bool Nothing (Just ET.DELETE) (isDroppedOp (tdDelete oldTriggerOps) (tdDelete newTriggerOps)))
]
dropDanglingSQLTrigger @b sourceConfig retainedNewTriggerName (Set.fromList $ catMaybes droppedOps)
where where
getTriggersMap = OMap.unions . map _tmEventTriggers . OMap.elems . _smTables getTriggersMap = OMap.unions . map _tmEventTriggers . OMap.elems . _smTables

View File

@ -63,7 +63,9 @@ newtype TriggerName = TriggerName {unTriggerName :: NonEmptyText}
triggerNameToTxt :: TriggerName -> Text triggerNameToTxt :: TriggerName -> Text
triggerNameToTxt = unNonEmptyText . unTriggerName triggerNameToTxt = unNonEmptyText . unTriggerName
data Ops = INSERT | UPDATE | DELETE | MANUAL deriving (Show) data Ops = INSERT | UPDATE | DELETE | MANUAL deriving (Show, Eq, Generic)
instance Hashable Ops
data SubscribeColumns (b :: BackendType) = SubCStar | SubCArray [Column b] data SubscribeColumns (b :: BackendType) = SubCStar | SubCArray [Column b]
deriving (Generic) deriving (Generic)

View File

@ -150,6 +150,21 @@ class Backend b => BackendEventTrigger (b :: BackendType) where
TriggerName -> TriggerName ->
m () m ()
-- | @dropDanglingSQLTriggger@ is used to delete the extraneous SQL triggers created
-- by an event trigger. The extraneous SQL triggers can be created when
-- an event trigger's definition is replaced to a new definition. For example,
-- an event trigger `authors_all` had an INSERT and UPDATE trigger defined
-- earlier and after it has UPDATE and DELETE triggers. So, in this case, we need
-- to drop the trigger created by us earlier for the INSERT trigger.
dropDanglingSQLTrigger ::
( MonadIO m,
MonadError QErr m
) =>
SourceConfig b ->
TriggerName ->
HashSet Ops ->
m ()
redeliverEvent :: redeliverEvent ::
(MonadIO m, MonadError QErr m) => (MonadIO m, MonadError QErr m) =>
SourceConfig b -> SourceConfig b ->
@ -192,6 +207,7 @@ instance BackendEventTrigger ('Postgres 'Vanilla) where
recordError = PG.recordError recordError = PG.recordError
recordError' = PG.recordError' recordError' = PG.recordError'
dropTriggerAndArchiveEvents = PG.dropTriggerAndArchiveEvents dropTriggerAndArchiveEvents = PG.dropTriggerAndArchiveEvents
dropDanglingSQLTrigger = PG.dropDanglingSQLTrigger
redeliverEvent = PG.redeliverEvent redeliverEvent = PG.redeliverEvent
unlockEventsInSource = PG.unlockEventsInSource unlockEventsInSource = PG.unlockEventsInSource
createTableEventTrigger = PG.createTableEventTrigger createTableEventTrigger = PG.createTableEventTrigger
@ -205,6 +221,7 @@ instance BackendEventTrigger ('Postgres 'Citus) where
recordError _ _ _ _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for Citus sources" recordError _ _ _ _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for Citus sources"
recordError' _ _ _ _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for Citus sources" recordError' _ _ _ _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for Citus sources"
dropTriggerAndArchiveEvents _ _ = throw400 NotSupported "Event triggers are not supported for Citus sources" dropTriggerAndArchiveEvents _ _ = throw400 NotSupported "Event triggers are not supported for Citus sources"
dropDanglingSQLTrigger _ _ _ = throw400 NotSupported "Event triggers are not supported for Citus sources"
redeliverEvent _ _ = throw400 NotSupported "Event triggers are not supported for Citus sources" redeliverEvent _ _ = throw400 NotSupported "Event triggers are not supported for Citus sources"
unlockEventsInSource _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for Citus sources" unlockEventsInSource _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for Citus sources"
createTableEventTrigger _ _ _ _ _ _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for Citus sources" createTableEventTrigger _ _ _ _ _ _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for Citus sources"
@ -218,6 +235,7 @@ instance BackendEventTrigger 'MSSQL where
recordError _ _ _ _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for MS-SQL sources" recordError _ _ _ _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for MS-SQL sources"
recordError' _ _ _ _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for MS-SQL sources" recordError' _ _ _ _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for MS-SQL sources"
dropTriggerAndArchiveEvents _ _ = throw400 NotSupported "Event triggers are not supported for MS-SQL sources" dropTriggerAndArchiveEvents _ _ = throw400 NotSupported "Event triggers are not supported for MS-SQL sources"
dropDanglingSQLTrigger _ _ _ = throw400 NotSupported "Event triggers are not supported for MS-SQL sources"
redeliverEvent _ _ = throw400 NotSupported "Event triggers are not supported for MS-SQL sources" redeliverEvent _ _ = throw400 NotSupported "Event triggers are not supported for MS-SQL sources"
unlockEventsInSource _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for MS-SQL sources" unlockEventsInSource _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for MS-SQL sources"
createTableEventTrigger = MSSQL.createTableEventTrigger createTableEventTrigger = MSSQL.createTableEventTrigger
@ -231,6 +249,7 @@ instance BackendEventTrigger 'BigQuery where
recordError _ _ _ _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for BigQuery sources" recordError _ _ _ _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for BigQuery sources"
recordError' _ _ _ _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for BigQuery sources" recordError' _ _ _ _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for BigQuery sources"
dropTriggerAndArchiveEvents _ _ = throw400 NotSupported "Event triggers are not supported for BigQuery sources" dropTriggerAndArchiveEvents _ _ = throw400 NotSupported "Event triggers are not supported for BigQuery sources"
dropDanglingSQLTrigger _ _ _ = throw400 NotSupported "Event triggers are not supported for BigQuery sources"
redeliverEvent _ _ = throw400 NotSupported "Event triggers are not supported for BigQuery sources" redeliverEvent _ _ = throw400 NotSupported "Event triggers are not supported for BigQuery sources"
unlockEventsInSource _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for BigQuery sources" unlockEventsInSource _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for BigQuery sources"
createTableEventTrigger _ _ _ _ _ _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for BigQuery sources" createTableEventTrigger _ _ _ _ _ _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for BigQuery sources"
@ -244,6 +263,7 @@ instance BackendEventTrigger 'MySQL where
recordError _ _ _ _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for MySQL sources" recordError _ _ _ _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for MySQL sources"
recordError' _ _ _ _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for MySQL sources" recordError' _ _ _ _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for MySQL sources"
dropTriggerAndArchiveEvents _ _ = throw400 NotSupported "Event triggers are not supported for MySQL sources" dropTriggerAndArchiveEvents _ _ = throw400 NotSupported "Event triggers are not supported for MySQL sources"
dropDanglingSQLTrigger _ _ _ = throw400 NotSupported "Event triggers are not supported for MySQL sources"
redeliverEvent _ _ = throw400 NotSupported "Event triggers are not supported for MySQL sources" redeliverEvent _ _ = throw400 NotSupported "Event triggers are not supported for MySQL sources"
unlockEventsInSource _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for MySQL sources" unlockEventsInSource _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for MySQL sources"
createTableEventTrigger _ _ _ _ _ _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for MySQL sources" createTableEventTrigger _ _ _ _ _ _ _ = runExceptT $ throw400 NotSupported "Event triggers are not supported for MySQL sources"
@ -271,6 +291,8 @@ instance BackendEventTrigger 'DataWrapper where
runExceptT $ throw400 NotSupported "Event triggers are not supported for GraphQL Data Wrappers." runExceptT $ throw400 NotSupported "Event triggers are not supported for GraphQL Data Wrappers."
dropTriggerAndArchiveEvents _ _ = dropTriggerAndArchiveEvents _ _ =
throw400 NotSupported "Event triggers are not supported for GraphQL Data Wrappers." throw400 NotSupported "Event triggers are not supported for GraphQL Data Wrappers."
dropDanglingSQLTrigger _ _ _ =
throw400 NotSupported "Event triggers are not supported for GraphQL Data Wrappers"
redeliverEvent _ _ = redeliverEvent _ _ =
throw400 NotSupported "Event triggers are not supported for GraphQL Data Wrappers." throw400 NotSupported "Event triggers are not supported for GraphQL Data Wrappers."
unlockEventsInSource _ _ = unlockEventsInSource _ _ =

View File

@ -433,7 +433,7 @@ runMetadataQueryV1M env currentResourceVersion = \case
RMAddComputedField q -> runAddComputedField q RMAddComputedField q -> runAddComputedField q
RMDropComputedField q -> runDropComputedField q RMDropComputedField q -> runDropComputedField q
RMCreateEventTrigger q -> RMCreateEventTrigger q ->
dispatchMetadata dispatchMetadataAndEventTrigger
( validateTransforms ( validateTransforms
(unUnvalidate1 . cetqRequestTransform . _Just) (unUnvalidate1 . cetqRequestTransform . _Just)
(runCreateEventTriggerQuery . _unUnvalidate1) (runCreateEventTriggerQuery . _unUnvalidate1)