graphql-engine/server/src-lib/Hasura/RQL/DDL/Schema/Catalog.hs
Vamshi Surabhi b84db36ebb
allow custom mutations through actions (#3042)
* basic doc for actions

* custom_types, sync and async actions

* switch to graphql-parser-hs on github

* update docs

* metadata import/export

* webhook calls are now supported

* relationships in sync actions

* initialise.sql is now in sync with the migration file

* fix metadata tests

* allow specifying arguments of actions

* fix blacklist check on check_build_worthiness job

* track custom_types and actions related tables

* handlers are now triggered on async actions

* default to pgjson unless a field is involved in relationships, for generating definition list

* use 'true' for action filter for non admin role

* fix create_action_permission sql query

* drop permissions when dropping an action

* add a hdb_role view (and relationships) to fetch all roles in the system

* rename 'webhook' key in action definition to 'handler'

* allow templating actions wehook URLs with env vars

* add 'update_action' /v1/query type

* allow forwarding client headers by setting `forward_client_headers` in action definition

* add 'headers' configuration in action definition

* handle webhook error response based on status codes

* support array relationships for custom types

* implement single row mutation, see https://github.com/hasura/graphql-engine/issues/3731

* single row mutation: rename 'pk_columns' -> 'columns' and no-op refactor

* use top level primary key inputs for delete_by_pk & account select permissions for single row mutations

* use only REST semantics to resolve the webhook response

* use 'pk_columns' instead of 'columns' for update_by_pk input

* add python basic tests for single row mutations

* add action context (name) in webhook payload

* Async action response is accessible for non admin roles only if
  the request session vars equals to action's

* clean nulls, empty arrays for actions, custom types in export metadata

* async action mutation returns only the UUID of the action

* unit tests for URL template parser

* Basic sync actions python tests

* fix output in async query & add async tests

* add admin secret header in async actions python test

* document async action architecture in Resolve/Action.hs file

* support actions returning array of objects

* tests for list type response actions

* update docs with actions and custom types metadata API reference

* update actions python tests as per #f8e1330

Co-authored-by: Tirumarai Selvan <tirumarai.selvan@gmail.com>
Co-authored-by: Aravind Shankar <face11301@gmail.com>
Co-authored-by: Rakesh Emmadi <12475069+rakeshkky@users.noreply.github.com>
2020-02-13 23:08:23 +05:30

85 lines
3.3 KiB
Haskell

-- | Functions for loading and modifying the catalog. See the module documentation for
-- "Hasura.RQL.DDL.Schema" for more details.
module Hasura.RQL.DDL.Schema.Catalog
( fetchCatalogData
, saveTableToCatalog
, updateTableIsEnumInCatalog
, updateTableConfig
, deleteTableFromCatalog
, getTableConfig
, purgeDependentObject
) where
import Hasura.Prelude
import qualified Database.PG.Query as Q
import Data.Aeson
import Hasura.Db
import Hasura.RQL.DDL.ComputedField
import Hasura.RQL.DDL.EventTrigger
import Hasura.RQL.DDL.Permission.Internal
import Hasura.RQL.DDL.Relationship
import Hasura.RQL.DDL.Schema.Function
import Hasura.RQL.Types
import Hasura.RQL.Types.Catalog
import Hasura.SQL.Types
fetchCatalogData :: (MonadTx m) => m CatalogMetadata
fetchCatalogData =
liftTx $ Q.getAltJ . runIdentity . Q.getRow <$> Q.withQE defaultTxErrorHandler
$(Q.sqlFromFile "src-rsr/catalog_metadata.sql") () True
purgeDependentObject :: (MonadTx m) => SchemaObjId -> m ()
purgeDependentObject = \case
SOTableObj tn (TOPerm rn pt) -> liftTx $ dropPermFromCatalog tn rn pt
SOTableObj qt (TORel rn) -> liftTx $ delRelFromCatalog qt rn
SOFunction qf -> liftTx $ delFunctionFromCatalog qf
SOTableObj _ (TOTrigger trn) -> liftTx $ delEventTriggerFromCatalog trn
SOTableObj qt (TOComputedField ccn) -> dropComputedFieldFromCatalog qt ccn
schemaObjId -> throw500 $ "unexpected dependent object: " <> reportSchemaObj schemaObjId
saveTableToCatalog
:: (MonadTx m, HasSystemDefined m) => QualifiedTable -> Bool -> TableConfig -> m ()
saveTableToCatalog (QualifiedObject sn tn) isEnum config = do
systemDefined <- askSystemDefined
liftTx $ Q.unitQE defaultTxErrorHandler [Q.sql|
INSERT INTO "hdb_catalog"."hdb_table"
(table_schema, table_name, is_system_defined, is_enum, configuration)
VALUES ($1, $2, $3, $4, $5)
|] (sn, tn, systemDefined, isEnum, configVal) False
where
configVal = Q.AltJ $ toJSON config
updateTableIsEnumInCatalog :: (MonadTx m) => QualifiedTable -> Bool -> m ()
updateTableIsEnumInCatalog (QualifiedObject sn tn) isEnum = liftTx $
Q.unitQE defaultTxErrorHandler [Q.sql|
UPDATE "hdb_catalog"."hdb_table" SET is_enum = $3
WHERE table_schema = $1 AND table_name = $2
|] (sn, tn, isEnum) False
updateTableConfig :: (MonadTx m) => QualifiedTable -> TableConfig -> m ()
updateTableConfig (QualifiedObject sn tn) config = liftTx $
Q.unitQE defaultTxErrorHandler [Q.sql|
UPDATE "hdb_catalog"."hdb_table"
SET configuration = $1
WHERE table_schema = $2 AND table_name = $3
|] (configVal, sn, tn) False
where
configVal = Q.AltJ $ toJSON config
deleteTableFromCatalog :: (MonadTx m) => QualifiedTable -> m ()
deleteTableFromCatalog (QualifiedObject sn tn) = liftTx $ Q.unitQE defaultTxErrorHandler [Q.sql|
DELETE FROM "hdb_catalog"."hdb_table"
WHERE table_schema = $1 AND table_name = $2
|] (sn, tn) False
getTableConfig :: MonadTx m => QualifiedTable -> m TableConfig
getTableConfig (QualifiedObject sn tn) = liftTx $
Q.getAltJ . runIdentity . Q.getRow <$> Q.withQE defaultTxErrorHandler
[Q.sql|
SELECT configuration::json FROM hdb_catalog.hdb_table
WHERE table_schema = $1 AND table_name = $2
|] (sn, tn) True