server: drop the dropping trigger logic while creating/recreating an event trigger

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/4101
GitOrigin-RevId: 12a2736e4d88dfb8379cd54f4beaedac32795d7d
This commit is contained in:
Karthikeyan Chinnakonda 2022-04-01 16:08:33 +05:30 committed by hasura-bot
parent 4189122a3d
commit 330f9b6e26
3 changed files with 105 additions and 51 deletions

View File

@ -494,7 +494,7 @@ dropTriggerOp triggerName triggerOp =
getDropFuncSql op =
"DROP FUNCTION IF EXISTS"
<> " hdb_catalog."
<> pgIdenTrigger op triggerName
<> unQualifiedTriggerName (pgIdenTrigger op triggerName)
<> "()"
<> " CASCADE"
@ -564,15 +564,26 @@ unlockEventsTx eventIds =
---- Postgres event trigger utility functions ---------------------
-- | QualifiedTriggerName is a type to store the name of the SQL trigger.
-- An example of it is `"notify_hasura_users_all_INSERT"` where `users_all`
-- is the name of the event trigger.
newtype QualifiedTriggerName = QualifiedTriggerName {unQualifiedTriggerName :: Text}
deriving (Show, Eq, Q.ToPrepArg)
pgTriggerName :: Ops -> TriggerName -> QualifiedTriggerName
pgTriggerName op trn = qualifyTriggerName op $ triggerNameToTxt trn
where
qualifyTriggerName op' trn' =
QualifiedTriggerName $ "notify_hasura_" <> trn' <> "_" <> tshow op'
pgIdenTrigger :: Ops -> TriggerName -> QualifiedTriggerName
pgIdenTrigger op = QualifiedTriggerName . pgFmtIdentifier . unQualifiedTriggerName . pgTriggerName op
-- | pgIdenTrigger is a method used to construct the name of the pg function
-- used for event triggers which are present in the hdb_catalog schema.
pgIdenTrigger :: Ops -> TriggerName -> Text
pgIdenTrigger op trn = pgFmtIdentifier . qualifyTriggerName op $ triggerNameToTxt trn
where
qualifyTriggerName op' trn' = "notify_hasura_" <> trn' <> "_" <> tshow op'
-- | Define the pgSQL trigger functions on database events.
mkTriggerQ ::
mkTriggerFunctionQ ::
forall pgKind m.
(Backend ('Postgres pgKind), MonadTx m, MonadReader ServerConfigCtx m) =>
TriggerName ->
@ -580,50 +591,51 @@ mkTriggerQ ::
[ColumnInfo ('Postgres pgKind)] ->
Ops ->
SubscribeOpSpec ('Postgres pgKind) ->
m ()
mkTriggerQ trn qt@(QualifiedObject schema table) allCols op (SubscribeOpSpec listenColumns deliveryColumns') = do
m QualifiedTriggerName
mkTriggerFunctionQ triggerName (QualifiedObject schema table) allCols op (SubscribeOpSpec listenColumns deliveryColumns') = do
strfyNum <- stringifyNum . _sccSQLGenCtx <$> ask
liftTx $
Q.multiQE defaultTxErrorHandler $
Q.fromText . TL.toStrict $
let -- If there are no specific delivery columns selected by user then all the columns will be delivered
-- in payload hence 'SubCStar'.
deliveryColumns = fromMaybe SubCStar deliveryColumns'
getApplicableColumns = \case
SubCStar -> allCols
SubCArray cols -> getColInfos cols allCols
let dbQualifiedTriggerName = pgIdenTrigger op triggerName
() <-
liftTx $
Q.multiQE defaultTxErrorHandler $
Q.fromText . TL.toStrict $
let -- If there are no specific delivery columns selected by user then all the columns will be delivered
-- in payload hence 'SubCStar'.
deliveryColumns = fromMaybe SubCStar deliveryColumns'
getApplicableColumns = \case
SubCStar -> allCols
SubCArray cols -> getColInfos cols allCols
-- Columns that should be present in the payload. By default, all columns are present.
applicableDeliveryCols = getApplicableColumns deliveryColumns
getRowExpression opVar = applyRowToJson' $ mkRowExpression opVar strfyNum applicableDeliveryCols
-- Columns that should be present in the payload. By default, all columns are present.
applicableDeliveryCols = getApplicableColumns deliveryColumns
getRowExpression opVar = applyRowToJson' $ mkRowExpression opVar strfyNum applicableDeliveryCols
-- Columns that user subscribed to listen for changes. By default, we listen on all columns.
applicableListenCols = getApplicableColumns listenColumns
renderRow opVar = applyRow $ mkRowExpression opVar strfyNum applicableListenCols
-- Columns that user subscribed to listen for changes. By default, we listen on all columns.
applicableListenCols = getApplicableColumns listenColumns
renderRow opVar = applyRow $ mkRowExpression opVar strfyNum applicableListenCols
oldDataExp = case op of
INSERT -> SENull
UPDATE -> getRowExpression OLD
DELETE -> getRowExpression OLD
MANUAL -> SENull
newDataExp = case op of
INSERT -> getRowExpression NEW
UPDATE -> getRowExpression NEW
DELETE -> SENull
MANUAL -> SENull
oldDataExp = case op of
INSERT -> SENull
UPDATE -> getRowExpression OLD
DELETE -> getRowExpression OLD
MANUAL -> SENull
newDataExp = case op of
INSERT -> getRowExpression NEW
UPDATE -> getRowExpression NEW
DELETE -> SENull
MANUAL -> SENull
name = triggerNameToTxt trn
qualifiedTriggerName = pgIdenTrigger op trn
qualifiedTable = toSQLTxt qt
schemaName = pgFmtLit $ getSchemaTxt schema
tableName = pgFmtLit $ getTableTxt table
name = triggerNameToTxt triggerName
qualifiedTriggerName = unQualifiedTriggerName dbQualifiedTriggerName
schemaName = pgFmtLit $ getSchemaTxt schema
tableName = pgFmtLit $ getTableTxt table
operation = tshow op
oldRow = toSQLTxt $ renderRow OLD
newRow = toSQLTxt $ renderRow NEW
oldPayloadExpression = toSQLTxt oldDataExp
newPayloadExpression = toSQLTxt newDataExp
in $(makeRelativeToProject "src-rsr/trigger.sql.shakespeare" >>= ST.stextFile)
oldRow = toSQLTxt $ renderRow OLD
newRow = toSQLTxt $ renderRow NEW
oldPayloadExpression = toSQLTxt oldDataExp
newPayloadExpression = toSQLTxt newDataExp
in $(makeRelativeToProject "src-rsr/trigger.sql.shakespeare" >>= ST.stextFile)
pure dbQualifiedTriggerName
where
applyRowToJson' e = SEFnApp "row_to_json" [e] Nothing
applyRow e = SEFnApp "row" [e] Nothing
@ -645,6 +657,50 @@ mkTriggerQ trn qt@(QualifiedObject schema table) allCols op (SubscribeOpSpec lis
| otherwise = Extractor sqlExp Nothing
getAlias col = toAlias $ Identifier $ getPGColTxt (ciColumn col)
checkIfTriggerExists ::
QualifiedTriggerName ->
QualifiedTable ->
Q.TxE QErr Bool
checkIfTriggerExists (QualifiedTriggerName triggerName) table =
fmap (runIdentity . Q.getRow) $
Q.withQE
defaultTxErrorHandler
[Q.sql|
SELECT EXISTS (
SELECT 1
FROM pg_trigger
WHERE NOT tgisinternal
AND tgname = $1 AND tgrelid = $2::regclass
)
|]
(triggerName, qualifiedObjectToText table)
True
mkTrigger ::
forall pgKind m.
(Backend ('Postgres pgKind), MonadTx m, MonadReader ServerConfigCtx m) =>
TriggerName ->
QualifiedTable ->
[ColumnInfo ('Postgres pgKind)] ->
Ops ->
SubscribeOpSpec ('Postgres pgKind) ->
m ()
mkTrigger triggerName table allCols op subOpSpec = do
-- create/replace the trigger function
dbTriggerName <- mkTriggerFunctionQ triggerName table allCols op subOpSpec
-- check if the SQL trigger exists and only if the SQL trigger doesn't exist
-- we create the SQL trigger.
doesTriggerExist <- liftTx $ checkIfTriggerExists (pgTriggerName op triggerName) table
unless doesTriggerExist $
let sqlQuery =
Q.fromText $ createTriggerSQL dbTriggerName (toSQLTxt table) (tshow op)
in liftTx $ Q.unitQE defaultTxErrorHandler sqlQuery () False
where
createTriggerSQL (QualifiedTriggerName triggerNameTxt) tableName opText =
[ST.st|
CREATE TRIGGER #{triggerNameTxt} AFTER #{opText} ON #{tableName} FOR EACH ROW EXECUTE PROCEDURE hdb_catalog.#{triggerNameTxt}()
|]
mkAllTriggersQ ::
forall pgKind m.
(Backend ('Postgres pgKind), MonadTx m, MonadReader ServerConfigCtx m) =>
@ -653,7 +709,7 @@ mkAllTriggersQ ::
[ColumnInfo ('Postgres pgKind)] ->
TriggerOpsDef ('Postgres pgKind) ->
m ()
mkAllTriggersQ trn qt allCols fullspec = do
onJust (tdInsert fullspec) (mkTriggerQ trn qt allCols INSERT)
onJust (tdUpdate fullspec) (mkTriggerQ trn qt allCols UPDATE)
onJust (tdDelete fullspec) (mkTriggerQ trn qt allCols DELETE)
mkAllTriggersQ triggerName table allCols fullspec = do
onJust (tdInsert fullspec) (mkTrigger triggerName table allCols INSERT)
onJust (tdUpdate fullspec) (mkTrigger triggerName table allCols UPDATE)
onJust (tdDelete fullspec) (mkTrigger triggerName table allCols DELETE)

View File

@ -35,5 +35,3 @@ CREATE OR REPLACE function hdb_catalog.#{qualifiedTriggerName}() RETURNS trigger
RETURN NULL;
END;
$$;
DROP TRIGGER IF EXISTS #{qualifiedTriggerName} ON #{qualifiedTable};
CREATE TRIGGER #{qualifiedTriggerName} AFTER #{operation} ON #{qualifiedTable} FOR EACH ROW EXECUTE PROCEDURE hdb_catalog.#{qualifiedTriggerName}();

View File

@ -270,7 +270,7 @@ def validate_gql_ws_q(hge_ctx, conf, headers, retry=False, via_subscription=Fals
print(ws_client.ws_url)
if not headers or len(headers) == 0:
ws_client.init({})
if ws_client.remote_closed or ws_client.is_closing:
ws_client.create_conn()
if not headers or len(headers) == 0 or hge_ctx.hge_key is None: