mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-15 09:22:43 +03:00
server: safely signal backend support for event triggers
Hooks up event trigger codecs from #7237. This required fixing a problem where some backend types implemented `defaultTriggerOnReplication` with `error` which caused the server to crash when evaluating those for default values in codecs. The changes here add a type family to `Backend` called `XEventTriggers` that signals backend support for event triggers, and changes the type of `defaultTriggerOnReplication` to from `TriggerOnReplication` to `Maybe (XEventTriggers b, TriggerOnReplication)` so that it can only be implemented with a `Just` value if `XEventTriggers b` is inhabited. This emulates some existing type families in `Backend`. (Thanks to @daniel-chambers for this suggestion!) I used the implementation of `defaultTriggerOnReplication` as a signal for event triggers support to prune the Metadata API so that event trigger fields will not appear in the OpenAPI spec for backend types that do not support event triggers. The codec version of the API will also not emit or accept those fields for those backend types. I think I could use `Typeable` to test whether `XEventTriggers` is `Void` instead of testing whether `defaultTriggerOnReplication` is `Nothing`. But the codec implementation will crash anyway if `defaultTriggerOnReplication` is `Nothing`. I checked to make sure that graphql-engine-pro still compiles. Ticket: https://hasurahq.atlassian.net/browse/GDC-521 PR-URL: https://github.com/hasura/graphql-engine-mono/pull/7295 GitOrigin-RevId: 2b2dd44291513266107ca25cf330319bf53a8b66
This commit is contained in:
parent
204ec89c61
commit
f4fa960ec6
@ -44,6 +44,7 @@ instance Backend 'BigQuery where
|
||||
type XComputedField 'BigQuery = XEnable
|
||||
type XRelay 'BigQuery = XDisable
|
||||
type XNodesAgg 'BigQuery = XEnable
|
||||
type XEventTriggers 'BigQuery = XDisable
|
||||
type XNestedInserts 'BigQuery = XDisable
|
||||
type XStreamingSubscription 'BigQuery = XDisable
|
||||
|
||||
@ -113,4 +114,4 @@ instance Backend 'BigQuery where
|
||||
-- BigQuery does not posses connection pooling
|
||||
pure ()
|
||||
|
||||
defaultTriggerOnReplication = error "Event triggers are not supported for the BigQuery source."
|
||||
defaultTriggerOnReplication = Nothing
|
||||
|
@ -74,6 +74,7 @@ instance Backend 'DataConnector where
|
||||
type XComputedField 'DataConnector = XDisable
|
||||
type XRelay 'DataConnector = XDisable
|
||||
type XNodesAgg 'DataConnector = XEnable
|
||||
type XEventTriggers 'DataConnector = XDisable
|
||||
type XNestedInserts 'DataConnector = XDisable
|
||||
type XStreamingSubscription 'DataConnector = XDisable
|
||||
|
||||
@ -159,7 +160,7 @@ instance Backend 'DataConnector where
|
||||
-- Data connectors do not have concept of connection pools
|
||||
pure ()
|
||||
|
||||
defaultTriggerOnReplication = error "Event triggers is not implemented for the data connector backend."
|
||||
defaultTriggerOnReplication = Nothing
|
||||
|
||||
data CustomBooleanOperator a = CustomBooleanOperator
|
||||
{ _cboName :: Text,
|
||||
|
@ -60,6 +60,7 @@ instance Backend 'MSSQL where
|
||||
type XComputedField 'MSSQL = XDisable
|
||||
type XRelay 'MSSQL = XDisable
|
||||
type XNodesAgg 'MSSQL = XEnable
|
||||
type XEventTriggers 'MSSQL = XEnable
|
||||
type XNestedInserts 'MSSQL = XDisable
|
||||
type XStreamingSubscription 'MSSQL = XDisable
|
||||
|
||||
@ -121,4 +122,4 @@ instance Backend 'MSSQL where
|
||||
resizeSourcePools sourceConfig =
|
||||
MSSQL.mssqlResizePools (MSSQL._mscExecCtx sourceConfig)
|
||||
|
||||
defaultTriggerOnReplication = TOREnableTrigger
|
||||
defaultTriggerOnReplication = Just ((), TOREnableTrigger)
|
||||
|
@ -42,6 +42,7 @@ instance Backend 'MySQL where
|
||||
type XRelay 'MySQL = Void
|
||||
type XNodesAgg 'MySQL = XEnable
|
||||
type ExtraTableMetadata 'MySQL = ()
|
||||
type XEventTriggers 'MySQL = XDisable
|
||||
type XNestedInserts 'MySQL = XDisable
|
||||
type XStreamingSubscription 'MySQL = XDisable
|
||||
|
||||
@ -145,4 +146,4 @@ instance Backend 'MySQL where
|
||||
-- Trim pool by destroying excess resources, if any
|
||||
Pool.tryTrimPool pool
|
||||
|
||||
defaultTriggerOnReplication = error "Event triggers are not implemented for the MySQL source."
|
||||
defaultTriggerOnReplication = Nothing
|
||||
|
@ -118,6 +118,7 @@ instance
|
||||
type XComputedField ('Postgres pgKind) = XEnable
|
||||
type XRelay ('Postgres pgKind) = XEnable
|
||||
type XNodesAgg ('Postgres pgKind) = XEnable
|
||||
type XEventTriggers ('Postgres pgKind) = XEnable
|
||||
type XNestedInserts ('Postgres pgKind) = XEnable
|
||||
type XStreamingSubscription ('Postgres pgKind) = XEnable
|
||||
|
||||
@ -153,4 +154,4 @@ instance
|
||||
|
||||
resizeSourcePools sourceConfig = Postgres._pecResizePools (Postgres._pscExecCtx sourceConfig)
|
||||
|
||||
defaultTriggerOnReplication = TORDisableTrigger
|
||||
defaultTriggerOnReplication = Just ((), TORDisableTrigger)
|
||||
|
@ -137,7 +137,10 @@ instance Backend b => FromJSON (CreateEventTriggerQuery b) where
|
||||
(Just _, Just _) -> fail "only one of webhook or webhook_from_env should be given"
|
||||
_ -> fail "must provide webhook or webhook_from_env"
|
||||
mapM_ checkEmptyCols [insert, update, delete]
|
||||
triggerOnReplication <- o .:? "trigger_on_replication" .!= defaultTriggerOnReplication @b
|
||||
defTOR <- case defaultTriggerOnReplication @b of
|
||||
Just (_, dt) -> pure dt
|
||||
Nothing -> fail "No default setting for trigger_on_replication is defined for backend type."
|
||||
triggerOnReplication <- o .:? "trigger_on_replication" .!= defTOR
|
||||
return $ CreateEventTriggerQuery sourceName name table insert update delete (Just enableManual) retryConf webhook webhookFromEnv headers replace requestTransform responseTransform cleanupConfig triggerOnReplication
|
||||
where
|
||||
checkEmptyCols spec =
|
||||
|
@ -311,6 +311,9 @@ class
|
||||
type XRelay b :: Type
|
||||
type XNodesAgg b :: Type
|
||||
|
||||
-- | Flag the availability of event triggers.
|
||||
type XEventTriggers b :: Type
|
||||
|
||||
-- | Extension to flag the availability of object and array relationships in inserts (aka nested inserts).
|
||||
type XNestedInserts b :: Type
|
||||
|
||||
@ -355,8 +358,10 @@ class
|
||||
-- Resize source pools based on the count of server replicas
|
||||
resizeSourcePools :: SourceConfig b -> ServerReplicas -> IO ()
|
||||
|
||||
-- Default behaviour of SQL triggers on logically replicated database
|
||||
defaultTriggerOnReplication :: TriggerOnReplication
|
||||
-- | Default behaviour of SQL triggers on logically replicated database.
|
||||
-- Setting this to @Nothing@ will disable event trigger configuration in the
|
||||
-- metadata.
|
||||
defaultTriggerOnReplication :: Maybe (XEventTriggers b, TriggerOnReplication)
|
||||
|
||||
-- Prisms
|
||||
$(makePrisms ''ComputedFieldReturnType)
|
||||
|
@ -37,7 +37,7 @@ module Hasura.RQL.Types.EventTrigger
|
||||
)
|
||||
where
|
||||
|
||||
import Autodocodec (HasCodec, codec, dimapCodec, disjointEitherCodec, listCodec, literalTextCodec, optionalField', optionalFieldWithDefault', requiredField')
|
||||
import Autodocodec (HasCodec, codec, dimapCodec, disjointEitherCodec, listCodec, literalTextCodec, optionalField', optionalFieldWithDefault', optionalFieldWithOmittedDefault', requiredField')
|
||||
import Autodocodec qualified as AC
|
||||
import Data.Aeson
|
||||
import Data.Aeson.Extended ((.=?))
|
||||
@ -405,7 +405,11 @@ instance (Backend b) => HasCodec (EventTriggerConf b) where
|
||||
<*> optionalField' "request_transform" AC..= etcRequestTransform
|
||||
<*> optionalField' "response_transform" AC..= etcResponseTransform
|
||||
<*> optionalField' "cleanup_config" AC..= etcCleanupConfig
|
||||
<*> optionalFieldWithDefault' "trigger_on_replication" (defaultTriggerOnReplication @b) AC..= etcTriggerOnReplication
|
||||
<*> triggerOnReplication
|
||||
where
|
||||
triggerOnReplication = case defaultTriggerOnReplication @b of
|
||||
Just (_, defTOR) -> optionalFieldWithOmittedDefault' "trigger_on_replication" defTOR AC..= etcTriggerOnReplication
|
||||
Nothing -> error "No default setting for trigger_on_replication is defined for backend type."
|
||||
|
||||
instance Backend b => FromJSON (EventTriggerConf b) where
|
||||
parseJSON = withObject "EventTriggerConf" \o -> do
|
||||
@ -418,7 +422,10 @@ instance Backend b => FromJSON (EventTriggerConf b) where
|
||||
requestTransform <- o .:? "request_transform"
|
||||
responseTransform <- o .:? "response_transform"
|
||||
cleanupConfig <- o .:? "cleanup_config"
|
||||
triggerOnReplication <- o .:? "trigger_on_replication" .!= defaultTriggerOnReplication @b
|
||||
defTOR <- case defaultTriggerOnReplication @b of
|
||||
Just (_, dt) -> pure dt
|
||||
Nothing -> fail "No default setting for trigger_on_replication is defined for backend type."
|
||||
triggerOnReplication <- o .:? "trigger_on_replication" .!= defTOR
|
||||
return $ EventTriggerConf name definition webhook webhookFromEnv retryConf headers requestTransform responseTransform cleanupConfig triggerOnReplication
|
||||
|
||||
instance Backend b => ToJSON (EventTriggerConf b) where
|
||||
@ -436,9 +443,9 @@ instance Backend b => ToJSON (EventTriggerConf b) where
|
||||
"response_transform" .=? responseTransform,
|
||||
"cleanup_config" .=? cleanupConfig,
|
||||
"trigger_on_replication"
|
||||
.=? if triggerOnReplication == defaultTriggerOnReplication @b
|
||||
then Nothing
|
||||
else Just triggerOnReplication
|
||||
.=? case defaultTriggerOnReplication @b of
|
||||
Just (_, defTOR) -> if triggerOnReplication == defTOR then Nothing else Just triggerOnReplication
|
||||
Nothing -> Just triggerOnReplication
|
||||
]
|
||||
|
||||
updateCleanupConfig :: Maybe AutoTriggerLogCleanupConfig -> EventTriggerConf b -> EventTriggerConf b
|
||||
|
@ -197,7 +197,6 @@ deriving instance (Backend b) => Eq (TableMetadata b)
|
||||
instance (Backend b) => ToJSON (TableMetadata b) where
|
||||
toJSON = genericToJSON hasuraJSON
|
||||
|
||||
-- TODO: Replace uses of placeholderCodecViaJSON with proper codecs
|
||||
instance (Backend b) => HasCodec (TableMetadata b) where
|
||||
codec =
|
||||
CommentCodec "Representation of a table in metadata, 'tables.yaml' and 'metadata.json'" $
|
||||
@ -214,16 +213,14 @@ instance (Backend b) => HasCodec (TableMetadata b) where
|
||||
<*> optSortedList "select_permissions" _pdRole .== _tmSelectPermissions
|
||||
<*> optSortedList "update_permissions" _pdRole .== _tmUpdatePermissions
|
||||
<*> optSortedList "delete_permissions" _pdRole .== _tmDeletePermissions
|
||||
<*> optSortedListViaJSON "event_triggers" etcName .== _tmEventTriggers
|
||||
<*> eventTriggers
|
||||
<*> optionalFieldOrNull' "apollo_federation_config" .== _tmApolloFederationConfig
|
||||
where
|
||||
optSortedListViaJSON ::
|
||||
(Eq a, FromJSON a, ToJSON a, Hashable k, Ord k, T.ToTxt k) =>
|
||||
Text ->
|
||||
(a -> k) ->
|
||||
ObjectCodec (InsOrdHashMap k a) (InsOrdHashMap k a)
|
||||
optSortedListViaJSON name keyForElem =
|
||||
AC.optionalFieldWithOmittedDefaultWith' name (sortedElemsCodecWith placeholderCodecViaJSON keyForElem) mempty
|
||||
-- Some backends do not implement event triggers. In those cases we tailor
|
||||
-- the codec to omit the @"event_triggers"@ field from the API.
|
||||
eventTriggers = case defaultTriggerOnReplication @b of
|
||||
Just _ -> optSortedList "event_triggers" etcName .== _tmEventTriggers
|
||||
Nothing -> pure mempty
|
||||
|
||||
optSortedList ::
|
||||
(HasCodec a, Eq a, Hashable k, Ord k, T.ToTxt k) =>
|
||||
|
@ -331,9 +331,9 @@ sourcesToOrdJSONList sources =
|
||||
eventTriggerConfToOrdJSON :: forall b. Backend b => EventTriggerConf b -> AO.Value
|
||||
eventTriggerConfToOrdJSON (EventTriggerConf name definition webhook webhookFromEnv retryConf headers reqTransform respTransform cleanupConfig triggerOnReplication) =
|
||||
let triggerOnReplicationMaybe =
|
||||
if triggerOnReplication == defaultTriggerOnReplication @b
|
||||
then Nothing
|
||||
else Just triggerOnReplication
|
||||
case defaultTriggerOnReplication @b of
|
||||
Just (_, defTOR) -> if triggerOnReplication == defTOR then Nothing else Just triggerOnReplication
|
||||
Nothing -> Just triggerOnReplication
|
||||
in AO.object $
|
||||
[ ("name", AO.toOrdered name),
|
||||
("definition", AO.toOrdered definition),
|
||||
|
Loading…
Reference in New Issue
Block a user