mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-18 13:02:11 +03:00
b84db36ebb
* 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>
237 lines
7.1 KiB
Haskell
237 lines
7.1 KiB
Haskell
module Hasura.GraphQL.Schema.Mutation.Insert
|
|
( mkInsInp
|
|
, mkInsInpTy
|
|
, mkRelInsInps
|
|
, mkInsMutFld
|
|
, mkInsertOneMutationField
|
|
, mkOnConflictTypes
|
|
) where
|
|
|
|
import qualified Data.HashMap.Strict as Map
|
|
import qualified Language.GraphQL.Draft.Syntax as G
|
|
|
|
import Hasura.GraphQL.Resolve.Types
|
|
import Hasura.GraphQL.Schema.BoolExp
|
|
import Hasura.GraphQL.Schema.Common
|
|
import Hasura.GraphQL.Schema.Mutation.Common
|
|
import Hasura.GraphQL.Validate.Types
|
|
import Hasura.Prelude
|
|
import Hasura.RQL.Types
|
|
import Hasura.SQL.Types
|
|
|
|
-- table_insert_input
|
|
mkInsInpTy :: QualifiedTable -> G.NamedType
|
|
mkInsInpTy tn =
|
|
G.NamedType $ qualObjectToName tn <> "_insert_input"
|
|
|
|
-- table_obj_rel_insert_input
|
|
mkObjInsInpTy :: QualifiedTable -> G.NamedType
|
|
mkObjInsInpTy tn =
|
|
G.NamedType $ qualObjectToName tn <> "_obj_rel_insert_input"
|
|
|
|
-- table_arr_rel_insert_input
|
|
mkArrInsInpTy :: QualifiedTable -> G.NamedType
|
|
mkArrInsInpTy tn =
|
|
G.NamedType $ qualObjectToName tn <> "_arr_rel_insert_input"
|
|
|
|
|
|
-- table_on_conflict
|
|
mkOnConflictInpTy :: QualifiedTable -> G.NamedType
|
|
mkOnConflictInpTy tn =
|
|
G.NamedType $ qualObjectToName tn <> "_on_conflict"
|
|
|
|
-- table_constraint
|
|
mkConstraintInpTy :: QualifiedTable -> G.NamedType
|
|
mkConstraintInpTy tn =
|
|
G.NamedType $ qualObjectToName tn <> "_constraint"
|
|
|
|
-- table_update_column
|
|
mkUpdColumnInpTy :: QualifiedTable -> G.NamedType
|
|
mkUpdColumnInpTy tn =
|
|
G.NamedType $ qualObjectToName tn <> "_update_column"
|
|
|
|
{-
|
|
input table_obj_rel_insert_input {
|
|
data: table_insert_input!
|
|
on_conflict: table_on_conflict
|
|
}
|
|
|
|
-}
|
|
|
|
{-
|
|
input table_arr_rel_insert_input {
|
|
data: [table_insert_input!]!
|
|
on_conflict: table_on_conflict
|
|
}
|
|
|
|
-}
|
|
|
|
mkRelInsInps
|
|
:: QualifiedTable -> Bool -> [InpObjTyInfo]
|
|
mkRelInsInps tn upsertAllowed = [objRelInsInp, arrRelInsInp]
|
|
where
|
|
onConflictInpVal =
|
|
InpValInfo Nothing "on_conflict" Nothing $ G.toGT $ mkOnConflictInpTy tn
|
|
|
|
onConflictInp = bool [] [onConflictInpVal] upsertAllowed
|
|
|
|
objRelDesc = G.Description $
|
|
"input type for inserting object relation for remote table " <>> tn
|
|
|
|
objRelDataInp = InpValInfo Nothing "data" Nothing $ G.toGT $
|
|
G.toNT $ mkInsInpTy tn
|
|
objRelInsInp = mkHsraInpTyInfo (Just objRelDesc) (mkObjInsInpTy tn)
|
|
$ fromInpValL $ objRelDataInp : onConflictInp
|
|
|
|
arrRelDesc = G.Description $
|
|
"input type for inserting array relation for remote table " <>> tn
|
|
|
|
arrRelDataInp = InpValInfo Nothing "data" Nothing $ G.toGT $
|
|
G.toNT $ G.toLT $ G.toNT $ mkInsInpTy tn
|
|
arrRelInsInp = mkHsraInpTyInfo (Just arrRelDesc) (mkArrInsInpTy tn)
|
|
$ fromInpValL $ arrRelDataInp : onConflictInp
|
|
|
|
{-
|
|
|
|
input table_insert_input {
|
|
col1: colty1
|
|
.
|
|
.
|
|
coln: coltyn
|
|
}
|
|
|
|
-}
|
|
|
|
mkInsInp
|
|
:: QualifiedTable -> [PGColumnInfo] -> RelationInfoMap -> InpObjTyInfo
|
|
mkInsInp tn insCols relInfoMap =
|
|
mkHsraInpTyInfo (Just desc) (mkInsInpTy tn) $ fromInpValL $
|
|
map mkPGColInp insCols <> relInps
|
|
where
|
|
desc = G.Description $
|
|
"input type for inserting data into table " <>> tn
|
|
|
|
relInps = flip map (Map.toList relInfoMap) $
|
|
\(relName, relInfo) ->
|
|
let remoteQT = riRTable relInfo
|
|
tyMaker = case riType relInfo of
|
|
ObjRel -> mkObjInsInpTy
|
|
ArrRel -> mkArrInsInpTy
|
|
in InpValInfo Nothing (mkRelName relName) Nothing $
|
|
G.toGT $ tyMaker remoteQT
|
|
|
|
|
|
{-
|
|
|
|
input table_on_conflict {
|
|
constraint: table_constraint!
|
|
update_columns: [table_column!]
|
|
where: table_bool_exp
|
|
}
|
|
|
|
-}
|
|
|
|
mkOnConflictInp :: QualifiedTable -> InpObjTyInfo
|
|
mkOnConflictInp tn =
|
|
mkHsraInpTyInfo (Just desc) (mkOnConflictInpTy tn) $ fromInpValL
|
|
[constraintInpVal, updateColumnsInpVal, whereInpVal]
|
|
where
|
|
desc = G.Description $
|
|
"on conflict condition type for table " <>> tn
|
|
|
|
constraintInpVal = InpValInfo Nothing (G.Name "constraint") Nothing $
|
|
G.toGT $ G.toNT $ mkConstraintInpTy tn
|
|
|
|
updateColumnsInpVal = InpValInfo Nothing (G.Name "update_columns") Nothing $
|
|
G.toGT $ G.toNT $ G.toLT $ G.toNT $ mkUpdColumnInpTy tn
|
|
|
|
whereInpVal = InpValInfo Nothing (G.Name "where") Nothing $
|
|
G.toGT $ mkBoolExpTy tn
|
|
{-
|
|
|
|
insert_table(
|
|
objects: [table_insert_input!]!
|
|
on_conflict: table_on_conflict
|
|
): table_mutation_response!
|
|
-}
|
|
|
|
mkInsMutFld :: Maybe G.Name -> QualifiedTable -> Bool -> ObjFldInfo
|
|
mkInsMutFld mCustomName tn isUpsertable =
|
|
mkHsraObjFldInfo (Just desc) fldName (fromInpValL inputVals) $
|
|
G.toGT $ mkMutRespTy tn
|
|
where
|
|
inputVals = catMaybes [Just objectsArg , mkOnConflictInputVal tn isUpsertable]
|
|
desc = G.Description $
|
|
"insert data into the table: " <>> tn
|
|
|
|
defFldName = "insert_" <> qualObjectToName tn
|
|
fldName = fromMaybe defFldName mCustomName
|
|
|
|
objsArgDesc = "the rows to be inserted"
|
|
objectsArg =
|
|
InpValInfo (Just objsArgDesc) "objects" Nothing $ G.toGT $
|
|
G.toNT $ G.toLT $ G.toNT $ mkInsInpTy tn
|
|
|
|
mkConstraintTy :: QualifiedTable -> [ConstraintName] -> EnumTyInfo
|
|
mkConstraintTy tn cons = enumTyInfo
|
|
where
|
|
enumTyInfo = mkHsraEnumTyInfo (Just desc) (mkConstraintInpTy tn) $
|
|
EnumValuesSynthetic . mapFromL _eviVal $ map mkConstraintEnumVal cons
|
|
|
|
desc = G.Description $
|
|
"unique or primary key constraints on table " <>> tn
|
|
|
|
mkConstraintEnumVal (ConstraintName n) =
|
|
EnumValInfo (Just "unique or primary key constraint")
|
|
(G.EnumValue $ G.Name n) False
|
|
|
|
mkUpdColumnTy :: QualifiedTable -> [G.Name] -> EnumTyInfo
|
|
mkUpdColumnTy tn cols = enumTyInfo
|
|
where
|
|
enumTyInfo = mkHsraEnumTyInfo (Just desc) (mkUpdColumnInpTy tn) $
|
|
EnumValuesSynthetic . mapFromL _eviVal $ map mkColumnEnumVal cols
|
|
|
|
desc = G.Description $
|
|
"update columns of table " <>> tn
|
|
|
|
mkOnConflictTypes
|
|
:: QualifiedTable -> [ConstraintName] -> [G.Name] -> Bool -> [TypeInfo]
|
|
mkOnConflictTypes tn uniqueOrPrimaryCons cols =
|
|
bool [] tyInfos
|
|
where
|
|
tyInfos = [ TIEnum $ mkConstraintTy tn uniqueOrPrimaryCons
|
|
, TIEnum $ mkUpdColumnTy tn cols
|
|
, TIInpObj $ mkOnConflictInp tn
|
|
]
|
|
|
|
mkOnConflictInputVal :: QualifiedTable -> Bool -> Maybe InpValInfo
|
|
mkOnConflictInputVal qt =
|
|
bool Nothing (Just onConflictArg)
|
|
where
|
|
onConflictDesc = "on conflict condition"
|
|
onConflictArg = InpValInfo (Just onConflictDesc) "on_conflict"
|
|
Nothing $ G.toGT $ mkOnConflictInpTy qt
|
|
|
|
|
|
{-
|
|
insert_table_one(
|
|
object: table_insert_input!
|
|
on_conflict: table_on_conflict
|
|
): table
|
|
-}
|
|
|
|
mkInsertOneMutationField :: Maybe G.Name -> QualifiedTable -> Bool -> ObjFldInfo
|
|
mkInsertOneMutationField mCustomName qt isUpsertable =
|
|
mkHsraObjFldInfo (Just description) fieldName (fromInpValL inputVals) $
|
|
G.toGT $ mkTableTy qt
|
|
where
|
|
description = G.Description $ "insert a single row into the table: " <>> qt
|
|
|
|
fieldName = flip fromMaybe mCustomName $ "insert_" <> qualObjectToName qt <> "_one"
|
|
|
|
inputVals = catMaybes [Just objectArg, mkOnConflictInputVal qt isUpsertable]
|
|
|
|
objectArgDesc = "the row to be inserted"
|
|
objectArg = InpValInfo (Just objectArgDesc) "object" Nothing $ G.toGT $
|
|
G.toNT $ mkInsInpTy qt
|