2018-06-27 16:11:32 +03:00
|
|
|
|
module Hasura.GraphQL.Schema
|
|
|
|
|
( mkGCtxMap
|
|
|
|
|
, GCtxMap
|
|
|
|
|
, getGCtx
|
|
|
|
|
, GCtx(..)
|
2019-07-23 14:12:59 +03:00
|
|
|
|
, QueryCtx(..)
|
|
|
|
|
, MutationCtx(..)
|
2018-10-05 18:13:51 +03:00
|
|
|
|
, InsCtx(..)
|
|
|
|
|
, InsCtxMap
|
|
|
|
|
, RelationInfoMap
|
2018-11-14 15:59:59 +03:00
|
|
|
|
, isAggFld
|
2019-01-25 06:31:54 +03:00
|
|
|
|
, qualObjectToName
|
2018-11-23 16:02:46 +03:00
|
|
|
|
, ppGCtx
|
2019-08-09 12:19:17 +03:00
|
|
|
|
, checkConflictingNode
|
|
|
|
|
, checkSchemaConflicts
|
|
|
|
|
) where
|
2018-11-23 16:02:46 +03:00
|
|
|
|
|
2019-08-28 22:27:15 +03:00
|
|
|
|
import Control.Lens.Extended hiding (op)
|
2020-05-27 18:02:58 +03:00
|
|
|
|
import Data.List.Extended (duplicates)
|
2018-06-27 16:11:32 +03:00
|
|
|
|
|
2019-08-09 12:19:17 +03:00
|
|
|
|
import qualified Data.HashMap.Strict as Map
|
|
|
|
|
import qualified Data.HashSet as Set
|
|
|
|
|
import qualified Data.Sequence as Seq
|
|
|
|
|
import qualified Data.Text as T
|
|
|
|
|
import qualified Language.GraphQL.Draft.Syntax as G
|
2018-06-27 16:11:32 +03:00
|
|
|
|
|
2018-11-23 16:02:46 +03:00
|
|
|
|
import Hasura.GraphQL.Context
|
2020-05-27 18:02:58 +03:00
|
|
|
|
import Hasura.GraphQL.Resolve.Context
|
2018-06-27 16:11:32 +03:00
|
|
|
|
import Hasura.GraphQL.Validate.Types
|
2018-07-12 17:03:02 +03:00
|
|
|
|
import Hasura.Prelude
|
2019-08-09 12:19:17 +03:00
|
|
|
|
import Hasura.RQL.DML.Internal (mkAdminRolePermInfo)
|
2018-06-27 16:11:32 +03:00
|
|
|
|
import Hasura.RQL.Types
|
2020-04-24 12:10:53 +03:00
|
|
|
|
import Hasura.Session
|
2018-06-27 16:11:32 +03:00
|
|
|
|
import Hasura.SQL.Types
|
|
|
|
|
|
2020-02-13 20:38:23 +03:00
|
|
|
|
import Hasura.GraphQL.Schema.Action
|
2019-08-09 12:19:17 +03:00
|
|
|
|
import Hasura.GraphQL.Schema.BoolExp
|
2020-02-13 20:38:23 +03:00
|
|
|
|
import Hasura.GraphQL.Schema.Builder
|
2019-08-09 12:19:17 +03:00
|
|
|
|
import Hasura.GraphQL.Schema.Common
|
|
|
|
|
import Hasura.GraphQL.Schema.Function
|
2019-08-28 22:27:15 +03:00
|
|
|
|
import Hasura.GraphQL.Schema.Merge
|
2019-08-09 12:19:17 +03:00
|
|
|
|
import Hasura.GraphQL.Schema.Mutation.Common
|
|
|
|
|
import Hasura.GraphQL.Schema.Mutation.Delete
|
|
|
|
|
import Hasura.GraphQL.Schema.Mutation.Insert
|
|
|
|
|
import Hasura.GraphQL.Schema.Mutation.Update
|
|
|
|
|
import Hasura.GraphQL.Schema.OrderBy
|
|
|
|
|
import Hasura.GraphQL.Schema.Select
|
2018-11-23 16:02:46 +03:00
|
|
|
|
|
2020-04-24 12:10:53 +03:00
|
|
|
|
type TableSchemaCtx = RoleContext (TyAgg, RootFields, InsCtxMap)
|
|
|
|
|
|
2019-11-20 21:21:30 +03:00
|
|
|
|
getInsPerm :: TableInfo -> RoleName -> Maybe InsPermInfo
|
2020-04-24 12:10:53 +03:00
|
|
|
|
getInsPerm tabInfo roleName
|
|
|
|
|
| roleName == adminRoleName = _permIns $ mkAdminRolePermInfo (_tiCoreInfo tabInfo)
|
|
|
|
|
| otherwise = Map.lookup roleName rolePermInfoMap >>= _permIns
|
2018-10-05 18:13:51 +03:00
|
|
|
|
where
|
2019-07-22 15:47:13 +03:00
|
|
|
|
rolePermInfoMap = _tiRolePermInfoMap tabInfo
|
2018-10-05 18:13:51 +03:00
|
|
|
|
|
|
|
|
|
getTabInfo
|
|
|
|
|
:: MonadError QErr m
|
2019-11-20 21:21:30 +03:00
|
|
|
|
=> TableCache -> QualifiedTable -> m TableInfo
|
2018-10-05 18:13:51 +03:00
|
|
|
|
getTabInfo tc t =
|
|
|
|
|
onNothing (Map.lookup t tc) $
|
|
|
|
|
throw500 $ "table not found: " <>> t
|
|
|
|
|
|
2019-01-25 06:31:54 +03:00
|
|
|
|
isValidObjectName :: (ToTxt a) => QualifiedObject a -> Bool
|
2019-09-19 07:47:36 +03:00
|
|
|
|
isValidObjectName = G.isValidName . qualObjectToName
|
2018-07-27 12:50:12 +03:00
|
|
|
|
|
2019-09-19 07:47:36 +03:00
|
|
|
|
isValidCol :: PGColumnInfo -> Bool
|
|
|
|
|
isValidCol = G.isValidName . pgiName
|
2019-04-15 10:04:30 +03:00
|
|
|
|
|
|
|
|
|
isValidRel :: ToTxt a => RelName -> QualifiedObject a -> Bool
|
2019-09-19 07:47:36 +03:00
|
|
|
|
isValidRel rn rt = G.isValidName (mkRelName rn) && isValidObjectName rt
|
2018-07-27 12:50:12 +03:00
|
|
|
|
|
2020-05-27 18:02:58 +03:00
|
|
|
|
isValidRemoteRel :: RemoteFieldInfo -> Bool
|
|
|
|
|
isValidRemoteRel =
|
|
|
|
|
G.isValidName . mkRemoteRelationshipName . _rfiName
|
|
|
|
|
|
|
|
|
|
isValidField :: FieldInfo -> Bool
|
|
|
|
|
isValidField = \case
|
|
|
|
|
FIColumn colInfo -> isValidCol colInfo
|
|
|
|
|
FIRelationship (RelInfo rn _ _ remTab _) -> isValidRel rn remTab
|
|
|
|
|
FIComputedField info -> G.isValidName $ mkComputedFieldName $ _cfiName info
|
|
|
|
|
FIRemoteRelationship remoteField -> isValidRemoteRel remoteField
|
|
|
|
|
|
2019-01-03 06:58:12 +03:00
|
|
|
|
upsertable :: [ConstraintName] -> Bool -> Bool -> Bool
|
2019-07-22 15:47:13 +03:00
|
|
|
|
upsertable uniqueOrPrimaryCons isUpsertAllowed isAView =
|
|
|
|
|
not (null uniqueOrPrimaryCons) && isUpsertAllowed && not isAView
|
2018-10-12 15:06:12 +03:00
|
|
|
|
|
2019-09-19 07:47:36 +03:00
|
|
|
|
getValidCols
|
2019-11-20 21:21:30 +03:00
|
|
|
|
:: FieldInfoMap FieldInfo -> [PGColumnInfo]
|
2019-10-18 11:29:47 +03:00
|
|
|
|
getValidCols = filter isValidCol . getCols
|
2018-10-26 14:57:33 +03:00
|
|
|
|
|
2019-11-20 21:21:30 +03:00
|
|
|
|
getValidRels :: FieldInfoMap FieldInfo -> [RelInfo]
|
2019-10-18 11:29:47 +03:00
|
|
|
|
getValidRels = filter isValidRel' . getRels
|
2019-09-19 07:47:36 +03:00
|
|
|
|
where
|
|
|
|
|
isValidRel' (RelInfo rn _ _ remTab _) = isValidRel rn remTab
|
2018-10-26 14:57:33 +03:00
|
|
|
|
|
2019-03-22 10:08:42 +03:00
|
|
|
|
mkValidConstraints :: [ConstraintName] -> [ConstraintName]
|
2019-01-03 06:58:12 +03:00
|
|
|
|
mkValidConstraints =
|
2019-09-19 07:47:36 +03:00
|
|
|
|
filter (G.isValidName . G.Name . getConstraintTxt)
|
2018-07-27 12:50:12 +03:00
|
|
|
|
|
2019-09-19 07:47:36 +03:00
|
|
|
|
isRelNullable
|
2019-11-20 21:21:30 +03:00
|
|
|
|
:: FieldInfoMap FieldInfo -> RelInfo -> Bool
|
2018-08-10 15:44:44 +03:00
|
|
|
|
isRelNullable fim ri = isNullable
|
|
|
|
|
where
|
2019-12-13 00:46:33 +03:00
|
|
|
|
lCols = Map.keys $ riMapping ri
|
2018-10-26 14:57:33 +03:00
|
|
|
|
allCols = getValidCols fim
|
2018-08-27 17:17:03 +03:00
|
|
|
|
lColInfos = getColInfos lCols allCols
|
2018-08-10 15:44:44 +03:00
|
|
|
|
isNullable = any pgiIsNullable lColInfos
|
|
|
|
|
|
2019-09-19 07:47:36 +03:00
|
|
|
|
mkPGColGNameMap :: [PGColumnInfo] -> PGColGNameMap
|
|
|
|
|
mkPGColGNameMap cols = Map.fromList $
|
|
|
|
|
flip map cols $ \ci -> (pgiName ci, ci)
|
|
|
|
|
|
2018-11-14 15:59:59 +03:00
|
|
|
|
numAggOps :: [G.Name]
|
|
|
|
|
numAggOps = [ "sum", "avg", "stddev", "stddev_samp", "stddev_pop"
|
|
|
|
|
, "variance", "var_samp", "var_pop"
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
compAggOps :: [G.Name]
|
|
|
|
|
compAggOps = ["max", "min"]
|
|
|
|
|
|
|
|
|
|
isAggFld :: G.Name -> Bool
|
|
|
|
|
isAggFld = flip elem (numAggOps <> compAggOps)
|
|
|
|
|
|
2019-11-20 09:47:06 +03:00
|
|
|
|
mkComputedFieldFunctionArgSeq :: Seq.Seq FunctionArg -> ComputedFieldFunctionArgSeq
|
|
|
|
|
mkComputedFieldFunctionArgSeq inputArgs =
|
|
|
|
|
Seq.fromList $ procFuncArgs inputArgs faName $
|
|
|
|
|
\fa t -> FunctionArgItem (G.Name t) (faName fa) (faHasDefault fa)
|
2019-10-18 11:29:47 +03:00
|
|
|
|
|
2020-04-24 12:10:53 +03:00
|
|
|
|
-- see Note [Split schema generation (TODO)]
|
2018-06-27 16:11:32 +03:00
|
|
|
|
mkGCtxRole'
|
|
|
|
|
:: QualifiedTable
|
2019-09-17 04:51:11 +03:00
|
|
|
|
-> Maybe PGDescription
|
2019-10-11 05:22:16 +03:00
|
|
|
|
-- ^ Postgres description
|
2019-08-11 18:34:38 +03:00
|
|
|
|
-> Maybe ([PGColumnInfo], RelationInfoMap)
|
2019-10-11 05:22:16 +03:00
|
|
|
|
-- ^ insert permission
|
2018-10-26 12:02:44 +03:00
|
|
|
|
-> Maybe (Bool, [SelField])
|
2019-10-11 05:22:16 +03:00
|
|
|
|
-- ^ select permission
|
2019-08-11 18:34:38 +03:00
|
|
|
|
-> Maybe [PGColumnInfo]
|
2019-10-11 05:22:16 +03:00
|
|
|
|
-- ^ update cols
|
2018-06-27 16:11:32 +03:00
|
|
|
|
-> Maybe ()
|
2019-07-22 15:47:13 +03:00
|
|
|
|
-- ^ delete cols
|
2019-12-09 07:18:53 +03:00
|
|
|
|
-> Maybe (PrimaryKey PGColumnInfo)
|
2019-03-22 10:08:42 +03:00
|
|
|
|
-> [ConstraintName]
|
2019-07-22 15:47:13 +03:00
|
|
|
|
-- ^ constraints
|
2018-10-12 15:06:12 +03:00
|
|
|
|
-> Maybe ViewInfo
|
2019-01-25 06:31:54 +03:00
|
|
|
|
-> [FunctionInfo]
|
2019-07-22 15:47:13 +03:00
|
|
|
|
-- ^ all functions
|
2018-06-27 16:11:32 +03:00
|
|
|
|
-> TyAgg
|
2019-10-11 05:22:16 +03:00
|
|
|
|
mkGCtxRole' tn descM insPermM selPermM updColsM delPermM pkeyCols constraints viM funcs =
|
2019-03-07 13:24:07 +03:00
|
|
|
|
TyAgg (mkTyInfoMap allTypes) fieldMap scalars ordByCtx
|
2018-06-27 16:11:32 +03:00
|
|
|
|
where
|
|
|
|
|
|
2018-10-26 14:57:33 +03:00
|
|
|
|
ordByCtx = fromMaybe Map.empty ordByCtxM
|
2019-04-15 10:04:30 +03:00
|
|
|
|
upsertPerm = isJust updColsM
|
2019-03-22 10:08:42 +03:00
|
|
|
|
isUpsertable = upsertable constraints upsertPerm $ isJust viM
|
2018-12-15 19:10:29 +03:00
|
|
|
|
updatableCols = maybe [] (map pgiName) updColsM
|
2019-03-22 10:08:42 +03:00
|
|
|
|
onConflictTypes = mkOnConflictTypes tn constraints updatableCols isUpsertable
|
2018-07-20 13:51:20 +03:00
|
|
|
|
jsonOpTys = fromMaybe [] updJSONOpInpObjTysM
|
2018-10-12 15:06:12 +03:00
|
|
|
|
relInsInpObjTys = maybe [] (map TIInpObj) $
|
|
|
|
|
mutHelper viIsInsertable relInsInpObjsM
|
2018-06-27 16:11:32 +03:00
|
|
|
|
|
2019-01-25 06:31:54 +03:00
|
|
|
|
funcInpArgTys = bool [] (map TIInpObj funcArgInpObjs) $ isJust selFldsM
|
|
|
|
|
|
2018-10-12 15:06:12 +03:00
|
|
|
|
allTypes = relInsInpObjTys <> onConflictTypes <> jsonOpTys
|
2018-10-26 12:02:44 +03:00
|
|
|
|
<> queryTypes <> aggQueryTypes <> mutationTypes
|
2019-11-07 17:39:48 +03:00
|
|
|
|
<> funcInpArgTys <> referencedEnumTypes <> computedFieldFuncArgsInps
|
2018-10-12 15:06:12 +03:00
|
|
|
|
|
|
|
|
|
queryTypes = catMaybes
|
|
|
|
|
[ TIInpObj <$> boolExpInpObjM
|
2018-10-26 14:57:33 +03:00
|
|
|
|
, TIInpObj <$> ordByInpObjM
|
2018-06-27 16:11:32 +03:00
|
|
|
|
, TIObj <$> selObjM
|
|
|
|
|
]
|
2018-12-12 15:58:39 +03:00
|
|
|
|
aggQueryTypes = map TIObj aggObjs <> map TIInpObj aggOrdByInps
|
2018-06-27 16:11:32 +03:00
|
|
|
|
|
2018-10-12 15:06:12 +03:00
|
|
|
|
mutationTypes = catMaybes
|
|
|
|
|
[ TIInpObj <$> mutHelper viIsInsertable insInpObjM
|
|
|
|
|
, TIInpObj <$> mutHelper viIsUpdatable updSetInpObjM
|
|
|
|
|
, TIInpObj <$> mutHelper viIsUpdatable updIncInpObjM
|
2020-02-13 20:38:23 +03:00
|
|
|
|
, TIInpObj <$> mutHelper viIsUpdatable primaryKeysInpObjM
|
2018-10-12 15:06:12 +03:00
|
|
|
|
, TIObj <$> mutRespObjM
|
2018-11-14 15:59:59 +03:00
|
|
|
|
, TIEnum <$> selColInpTyM
|
2018-10-12 15:06:12 +03:00
|
|
|
|
]
|
2018-12-13 10:26:15 +03:00
|
|
|
|
|
|
|
|
|
mutHelper :: (ViewInfo -> Bool) -> Maybe a -> Maybe a
|
2018-10-12 15:06:12 +03:00
|
|
|
|
mutHelper f objM = bool Nothing objM $ isMutable f viM
|
|
|
|
|
|
2018-06-27 16:11:32 +03:00
|
|
|
|
fieldMap = Map.unions $ catMaybes
|
2019-02-22 13:27:38 +03:00
|
|
|
|
[ insInpObjFldsM, updSetInpObjFldsM
|
|
|
|
|
, boolExpInpObjFldsM , selObjFldsM
|
2018-06-27 16:11:32 +03:00
|
|
|
|
]
|
2019-11-07 17:39:48 +03:00
|
|
|
|
scalars = selByPkScalarSet <> funcArgScalarSet <> computedFieldFuncArgScalars
|
2018-06-27 16:11:32 +03:00
|
|
|
|
|
|
|
|
|
-- helper
|
2018-10-26 12:02:44 +03:00
|
|
|
|
mkColFldMap ty cols = Map.fromList $ flip map cols $
|
2019-10-18 11:29:47 +03:00
|
|
|
|
\ci -> ((ty, pgiName ci), RFPGColumn ci)
|
2018-06-27 16:11:32 +03:00
|
|
|
|
|
|
|
|
|
-- insert input type
|
2019-04-15 10:04:30 +03:00
|
|
|
|
insInpObjM = uncurry (mkInsInp tn) <$> insPermM
|
2018-10-05 18:13:51 +03:00
|
|
|
|
-- column fields used in insert input object
|
2019-04-15 10:04:30 +03:00
|
|
|
|
insInpObjFldsM = (mkColFldMap (mkInsInpTy tn) . fst) <$> insPermM
|
2018-10-05 18:13:51 +03:00
|
|
|
|
-- relationship input objects
|
2019-04-15 10:04:30 +03:00
|
|
|
|
relInsInpObjsM = const (mkRelInsInps tn isUpsertable) <$> insPermM
|
2018-06-27 16:11:32 +03:00
|
|
|
|
-- update set input type
|
2018-07-20 13:51:20 +03:00
|
|
|
|
updSetInpObjM = mkUpdSetInp tn <$> updColsM
|
|
|
|
|
-- update increment input type
|
|
|
|
|
updIncInpObjM = mkUpdIncInp tn updColsM
|
|
|
|
|
-- update json operator input type
|
|
|
|
|
updJSONOpInpObjsM = mkUpdJSONOpInp tn <$> updColsM
|
|
|
|
|
updJSONOpInpObjTysM = map TIInpObj <$> updJSONOpInpObjsM
|
2018-06-27 16:11:32 +03:00
|
|
|
|
-- fields used in set input object
|
|
|
|
|
updSetInpObjFldsM = mkColFldMap (mkUpdSetTy tn) <$> updColsM
|
|
|
|
|
|
2020-02-13 20:38:23 +03:00
|
|
|
|
-- primary key columns input object for update_by_pk
|
|
|
|
|
primaryKeysInpObjM = guard (isJust selPermM) *> (mkPKeyColumnsInpObj tn <$> pkeyCols)
|
|
|
|
|
|
2018-10-26 12:02:44 +03:00
|
|
|
|
selFldsM = snd <$> selPermM
|
2019-10-18 11:29:47 +03:00
|
|
|
|
selColNamesM = (map pgiName . getPGColumnFields) <$> selFldsM
|
2019-09-19 07:47:36 +03:00
|
|
|
|
selColInpTyM = mkSelColumnTy tn <$> selColNamesM
|
2020-05-27 18:02:58 +03:00
|
|
|
|
|
2018-06-27 16:11:32 +03:00
|
|
|
|
-- boolexp input type
|
|
|
|
|
boolExpInpObjM = case selFldsM of
|
2018-10-26 14:57:33 +03:00
|
|
|
|
Just selFlds -> Just $ mkBoolExpInp tn selFlds
|
2018-06-27 16:11:32 +03:00
|
|
|
|
-- no select permission
|
|
|
|
|
Nothing ->
|
|
|
|
|
-- but update/delete is defined
|
|
|
|
|
if isJust updColsM || isJust delPermM
|
|
|
|
|
then Just $ mkBoolExpInp tn []
|
|
|
|
|
else Nothing
|
|
|
|
|
|
2019-01-25 06:31:54 +03:00
|
|
|
|
-- funcargs input type
|
2019-10-18 11:29:47 +03:00
|
|
|
|
funcArgInpObjs = flip mapMaybe funcs $ \func ->
|
2019-11-20 09:47:06 +03:00
|
|
|
|
mkFuncArgsInp (fiName func) (getInputArgs func)
|
2019-02-22 13:27:38 +03:00
|
|
|
|
-- funcArgCtx = Map.unions funcArgCtxs
|
2019-11-20 09:47:06 +03:00
|
|
|
|
funcArgScalarSet = funcs ^.. folded.to getInputArgs.folded.to (_qptName.faType)
|
2019-01-25 06:31:54 +03:00
|
|
|
|
|
2018-06-27 16:11:32 +03:00
|
|
|
|
-- helper
|
2018-10-26 12:02:44 +03:00
|
|
|
|
mkFldMap ty = Map.fromList . concatMap (mkFld ty)
|
|
|
|
|
mkFld ty = \case
|
2019-10-18 11:29:47 +03:00
|
|
|
|
SFPGColumn ci -> [((ty, pgiName ci), RFPGColumn ci)]
|
|
|
|
|
SFRelationship (RelationshipFieldInfo relInfo allowAgg cols permFilter permLimit _) ->
|
2019-09-19 07:47:36 +03:00
|
|
|
|
let relationshipName = riName relInfo
|
|
|
|
|
relFld = ( (ty, mkRelName relationshipName)
|
2019-10-18 11:29:47 +03:00
|
|
|
|
, RFRelationship $ RelationshipField relInfo False cols permFilter permLimit
|
2018-10-26 12:02:44 +03:00
|
|
|
|
)
|
2019-09-19 07:47:36 +03:00
|
|
|
|
aggRelFld = ( (ty, mkAggRelName relationshipName)
|
2019-10-18 11:29:47 +03:00
|
|
|
|
, RFRelationship $ RelationshipField relInfo True cols permFilter permLimit
|
2018-10-26 12:02:44 +03:00
|
|
|
|
)
|
2019-09-19 07:47:36 +03:00
|
|
|
|
in case riType relInfo of
|
2018-10-26 12:02:44 +03:00
|
|
|
|
ObjRel -> [relFld]
|
|
|
|
|
ArrRel -> bool [relFld] [relFld, aggRelFld] allowAgg
|
2019-10-18 11:29:47 +03:00
|
|
|
|
SFComputedField cf -> pure
|
|
|
|
|
( (ty, mkComputedFieldName $ _cfName cf)
|
|
|
|
|
, RFComputedField cf
|
|
|
|
|
)
|
2020-05-27 18:02:58 +03:00
|
|
|
|
SFRemoteRelationship remoteField -> pure
|
|
|
|
|
( (ty, G.Name (remoteRelationshipNameToText (_rfiName remoteField)))
|
|
|
|
|
, RFRemoteRelationship remoteField
|
|
|
|
|
)
|
2018-10-26 12:02:44 +03:00
|
|
|
|
|
2018-06-27 16:11:32 +03:00
|
|
|
|
-- the fields used in bool exp
|
|
|
|
|
boolExpInpObjFldsM = mkFldMap (mkBoolExpTy tn) <$> selFldsM
|
|
|
|
|
|
2018-08-30 12:49:21 +03:00
|
|
|
|
-- mut resp obj
|
|
|
|
|
mutRespObjM =
|
2018-10-12 15:06:12 +03:00
|
|
|
|
if isMut
|
2019-03-22 10:08:42 +03:00
|
|
|
|
then Just $ mkMutRespObj tn $ isJust selFldsM
|
2018-06-27 16:11:32 +03:00
|
|
|
|
else Nothing
|
|
|
|
|
|
2019-04-15 10:04:30 +03:00
|
|
|
|
isMut = (isJust insPermM || isJust updColsM || isJust delPermM)
|
2018-10-12 15:06:12 +03:00
|
|
|
|
&& any (`isMutable` viM) [viIsInsertable, viIsUpdatable, viIsDeletable]
|
|
|
|
|
|
2018-06-27 16:11:32 +03:00
|
|
|
|
-- table obj
|
2019-09-17 04:51:11 +03:00
|
|
|
|
selObjM = mkTableObj tn descM <$> selFldsM
|
2019-03-07 13:24:07 +03:00
|
|
|
|
|
2018-12-12 15:58:39 +03:00
|
|
|
|
-- aggregate objs and order by inputs
|
|
|
|
|
(aggObjs, aggOrdByInps) = case selPermM of
|
2018-10-26 12:02:44 +03:00
|
|
|
|
Just (True, selFlds) ->
|
2019-10-18 11:29:47 +03:00
|
|
|
|
let cols = getPGColumnFields selFlds
|
2019-09-19 07:47:36 +03:00
|
|
|
|
numCols = onlyNumCols cols
|
|
|
|
|
compCols = onlyComparableCols cols
|
2018-12-12 15:58:39 +03:00
|
|
|
|
objs = [ mkTableAggObj tn
|
2019-08-09 12:19:17 +03:00
|
|
|
|
, mkTableAggFldsObj tn (numCols, numAggOps) (compCols, compAggOps)
|
2018-12-12 15:58:39 +03:00
|
|
|
|
] <> mkColAggFldsObjs selFlds
|
2019-08-09 12:19:17 +03:00
|
|
|
|
ordByInps = mkTabAggOrdByInpObj tn (numCols, numAggOps) (compCols, compAggOps)
|
|
|
|
|
: mkTabAggOpOrdByInpObjs tn (numCols, numAggOps) (compCols, compAggOps)
|
2018-12-12 15:58:39 +03:00
|
|
|
|
in (objs, ordByInps)
|
|
|
|
|
_ -> ([], [])
|
|
|
|
|
|
2019-10-18 11:29:47 +03:00
|
|
|
|
getNumericCols = onlyNumCols . getPGColumnFields
|
|
|
|
|
getComparableCols = onlyComparableCols . getPGColumnFields
|
2018-11-14 15:59:59 +03:00
|
|
|
|
onlyFloat = const $ mkScalarTy PGFloat
|
|
|
|
|
|
2019-07-22 15:47:13 +03:00
|
|
|
|
mkTypeMaker "sum" = mkColumnType
|
2018-11-14 15:59:59 +03:00
|
|
|
|
mkTypeMaker _ = onlyFloat
|
|
|
|
|
|
2018-10-26 12:02:44 +03:00
|
|
|
|
mkColAggFldsObjs flds =
|
2019-10-18 11:29:47 +03:00
|
|
|
|
let numCols = getNumericCols flds
|
|
|
|
|
compCols = getComparableCols flds
|
2018-11-14 15:59:59 +03:00
|
|
|
|
mkNumObjFld n = mkTableColAggFldsObj tn n (mkTypeMaker n) numCols
|
2019-07-22 15:47:13 +03:00
|
|
|
|
mkCompObjFld n = mkTableColAggFldsObj tn n mkColumnType compCols
|
2018-11-14 15:59:59 +03:00
|
|
|
|
numFldsObjs = bool (map mkNumObjFld numAggOps) [] $ null numCols
|
|
|
|
|
compFldsObjs = bool (map mkCompObjFld compAggOps) [] $ null compCols
|
2018-10-26 12:02:44 +03:00
|
|
|
|
in numFldsObjs <> compFldsObjs
|
2018-06-27 16:11:32 +03:00
|
|
|
|
-- the fields used in table object
|
|
|
|
|
selObjFldsM = mkFldMap (mkTableTy tn) <$> selFldsM
|
2019-02-22 13:27:38 +03:00
|
|
|
|
-- the scalar set for table_by_pk arguments
|
2019-12-09 07:18:53 +03:00
|
|
|
|
selByPkScalarSet = pkeyCols ^.. folded.to _pkColumns.folded.to pgiType._PGColumnScalar
|
2018-06-27 16:11:32 +03:00
|
|
|
|
|
2018-10-26 14:57:33 +03:00
|
|
|
|
ordByInpCtxM = mkOrdByInpObj tn <$> selFldsM
|
|
|
|
|
(ordByInpObjM, ordByCtxM) = case ordByInpCtxM of
|
|
|
|
|
Just (a, b) -> (Just a, Just b)
|
|
|
|
|
Nothing -> (Nothing, Nothing)
|
2018-06-27 16:11:32 +03:00
|
|
|
|
|
2019-10-11 05:22:16 +03:00
|
|
|
|
-- the types for all enums that are /referenced/ by this table (not /defined/ by this table;
|
|
|
|
|
-- there isn’t actually any need to generate a GraphQL enum type for an enum table if it’s
|
|
|
|
|
-- never referenced anywhere else)
|
|
|
|
|
referencedEnumTypes =
|
|
|
|
|
let allColumnInfos =
|
2019-10-18 11:29:47 +03:00
|
|
|
|
(selPermM ^.. _Just._2.traverse._SFPGColumn)
|
2019-10-11 05:22:16 +03:00
|
|
|
|
<> (insPermM ^. _Just._1)
|
|
|
|
|
<> (updColsM ^. _Just)
|
|
|
|
|
allEnumReferences = allColumnInfos ^.. traverse.to pgiType._PGColumnEnumReference
|
|
|
|
|
in flip map allEnumReferences $ \enumReference@(EnumReference referencedTableName _) ->
|
|
|
|
|
let typeName = mkTableEnumType referencedTableName
|
|
|
|
|
in TIEnum $ mkHsraEnumTyInfo Nothing typeName (EnumValuesReference enumReference)
|
|
|
|
|
|
2019-07-22 15:47:13 +03:00
|
|
|
|
|
2019-11-07 17:39:48 +03:00
|
|
|
|
-- computed fields' function args input objects and scalar types
|
|
|
|
|
mkComputedFieldRequiredTypes computedFieldInfo =
|
2020-04-27 18:07:03 +03:00
|
|
|
|
let ComputedFieldFunction qf inputArgs _ _ _ = _cfFunction computedFieldInfo
|
2019-11-07 17:39:48 +03:00
|
|
|
|
scalarArgs = map (_qptName . faType) $ toList inputArgs
|
|
|
|
|
in (, scalarArgs) <$> mkFuncArgsInp qf inputArgs
|
2019-10-18 11:29:47 +03:00
|
|
|
|
|
2019-11-07 17:39:48 +03:00
|
|
|
|
computedFieldReqTypes = catMaybes $
|
|
|
|
|
maybe [] (map mkComputedFieldRequiredTypes . getComputedFields) selFldsM
|
|
|
|
|
|
|
|
|
|
computedFieldFuncArgsInps = map (TIInpObj . fst) computedFieldReqTypes
|
|
|
|
|
computedFieldFuncArgScalars = Set.fromList $ concatMap snd computedFieldReqTypes
|
2019-10-18 11:29:47 +03:00
|
|
|
|
|
2020-04-24 12:10:53 +03:00
|
|
|
|
-- see Note [Split schema generation (TODO)]
|
2018-06-27 16:11:32 +03:00
|
|
|
|
getRootFldsRole'
|
|
|
|
|
:: QualifiedTable
|
2019-12-09 07:18:53 +03:00
|
|
|
|
-> Maybe (PrimaryKey PGColumnInfo)
|
2019-03-22 10:08:42 +03:00
|
|
|
|
-> [ConstraintName]
|
2019-11-20 21:21:30 +03:00
|
|
|
|
-> FieldInfoMap FieldInfo
|
2019-01-25 06:31:54 +03:00
|
|
|
|
-> [FunctionInfo]
|
2018-10-05 18:13:51 +03:00
|
|
|
|
-> Maybe ([T.Text], Bool) -- insert perm
|
2019-04-17 12:48:41 +03:00
|
|
|
|
-> Maybe (AnnBoolExpPartialSQL, Maybe Int, [T.Text], Bool) -- select filter
|
2020-02-13 10:38:49 +03:00
|
|
|
|
-> Maybe ([PGColumnInfo], PreSetColsPartial, AnnBoolExpPartialSQL, Maybe AnnBoolExpPartialSQL, [T.Text]) -- update filter
|
2019-04-17 12:48:41 +03:00
|
|
|
|
-> Maybe (AnnBoolExpPartialSQL, [T.Text]) -- delete filter
|
2018-10-12 15:06:12 +03:00
|
|
|
|
-> Maybe ViewInfo
|
2019-09-19 07:47:36 +03:00
|
|
|
|
-> TableConfig -- custom config
|
2019-07-23 14:12:59 +03:00
|
|
|
|
-> RootFields
|
2019-12-09 07:18:53 +03:00
|
|
|
|
getRootFldsRole' tn primaryKey constraints fields funcs insM
|
2019-09-19 07:47:36 +03:00
|
|
|
|
selM updM delM viM tableConfig =
|
2019-07-23 14:12:59 +03:00
|
|
|
|
RootFields
|
2020-02-13 20:38:23 +03:00
|
|
|
|
{ _rootQueryFields = makeFieldMap $
|
2019-11-20 15:40:56 +03:00
|
|
|
|
funcQueries
|
2019-07-23 14:12:59 +03:00
|
|
|
|
<> funcAggQueries
|
|
|
|
|
<> catMaybes
|
|
|
|
|
[ getSelDet <$> selM
|
|
|
|
|
, getSelAggDet selM
|
2019-12-09 07:18:53 +03:00
|
|
|
|
, getPKeySelDet <$> selM <*> primaryKey
|
2019-07-23 14:12:59 +03:00
|
|
|
|
]
|
2020-02-13 20:38:23 +03:00
|
|
|
|
, _rootMutationFields = makeFieldMap $ catMaybes
|
2019-07-23 14:12:59 +03:00
|
|
|
|
[ mutHelper viIsInsertable getInsDet insM
|
2020-02-13 20:38:23 +03:00
|
|
|
|
, onlyIfSelectPermExist $ mutHelper viIsInsertable getInsOneDet insM
|
2019-07-23 14:12:59 +03:00
|
|
|
|
, mutHelper viIsUpdatable getUpdDet updM
|
2020-02-13 20:38:23 +03:00
|
|
|
|
, onlyIfSelectPermExist $ mutHelper viIsUpdatable getUpdByPkDet $ (,) <$> updM <*> primaryKey
|
2019-07-23 14:12:59 +03:00
|
|
|
|
, mutHelper viIsDeletable getDelDet delM
|
2020-02-13 20:38:23 +03:00
|
|
|
|
, onlyIfSelectPermExist $ mutHelper viIsDeletable getDelByPkDet $ (,) <$> delM <*> primaryKey
|
2019-07-23 14:12:59 +03:00
|
|
|
|
]
|
|
|
|
|
}
|
2018-06-27 16:11:32 +03:00
|
|
|
|
where
|
2019-11-20 15:40:56 +03:00
|
|
|
|
makeFieldMap = mapFromL (_fiName . snd)
|
2019-09-19 07:47:36 +03:00
|
|
|
|
customRootFields = _tcCustomRootFields tableConfig
|
2020-02-13 20:38:23 +03:00
|
|
|
|
colGNameMap = mkPGColGNameMap $ getCols fields
|
2019-09-19 07:47:36 +03:00
|
|
|
|
|
2019-01-25 06:31:54 +03:00
|
|
|
|
funcQueries = maybe [] getFuncQueryFlds selM
|
|
|
|
|
funcAggQueries = maybe [] getFuncAggQueryFlds selM
|
|
|
|
|
|
2018-12-13 10:26:15 +03:00
|
|
|
|
mutHelper :: (ViewInfo -> Bool) -> (a -> b) -> Maybe a -> Maybe b
|
2018-10-12 15:06:12 +03:00
|
|
|
|
mutHelper f getDet mutM =
|
|
|
|
|
bool Nothing (getDet <$> mutM) $ isMutable f viM
|
2018-12-13 10:26:15 +03:00
|
|
|
|
|
2020-02-13 20:38:23 +03:00
|
|
|
|
onlyIfSelectPermExist v = guard (isJust selM) *> v
|
|
|
|
|
|
2019-09-19 07:47:36 +03:00
|
|
|
|
getCustomNameWith f = f customRootFields
|
|
|
|
|
|
|
|
|
|
insCustName = getCustomNameWith _tcrfInsert
|
2018-10-05 18:13:51 +03:00
|
|
|
|
getInsDet (hdrs, upsertPerm) =
|
2019-03-22 10:08:42 +03:00
|
|
|
|
let isUpsertable = upsertable constraints upsertPerm $ isJust viM
|
2020-02-13 20:38:23 +03:00
|
|
|
|
in ( MCInsert $ InsOpCtx tn $ hdrs `union` maybe [] (^. _5) updM
|
2019-09-19 07:47:36 +03:00
|
|
|
|
, mkInsMutFld insCustName tn isUpsertable
|
2018-10-05 18:13:51 +03:00
|
|
|
|
)
|
2018-12-13 10:26:15 +03:00
|
|
|
|
|
2020-02-13 20:38:23 +03:00
|
|
|
|
insOneCustName = getCustomNameWith _tcrfInsertOne
|
|
|
|
|
getInsOneDet (hdrs, upsertPerm) =
|
|
|
|
|
let isUpsertable = upsertable constraints upsertPerm $ isJust viM
|
|
|
|
|
in ( MCInsertOne $ InsOpCtx tn $ hdrs `union` maybe [] (^. _5) updM
|
|
|
|
|
, mkInsertOneMutationField insOneCustName tn isUpsertable
|
|
|
|
|
)
|
|
|
|
|
|
2019-09-19 07:47:36 +03:00
|
|
|
|
updCustName = getCustomNameWith _tcrfUpdate
|
2020-02-13 10:38:49 +03:00
|
|
|
|
getUpdDet (updCols, preSetCols, updFltr, updCheck, hdrs) =
|
|
|
|
|
( MCUpdate $ UpdOpCtx tn hdrs colGNameMap updFltr updCheck preSetCols
|
2019-09-19 07:47:36 +03:00
|
|
|
|
, mkUpdMutFld updCustName tn updCols
|
2018-07-20 13:51:20 +03:00
|
|
|
|
)
|
2019-02-11 15:45:30 +03:00
|
|
|
|
|
2020-02-13 20:38:23 +03:00
|
|
|
|
updByPkCustName = getCustomNameWith _tcrfUpdateByPk
|
|
|
|
|
getUpdByPkDet ((updCols, preSetCols, updFltr, updCheck, hdrs), pKey) =
|
|
|
|
|
( MCUpdateByPk $ UpdOpCtx tn hdrs colGNameMap updFltr updCheck preSetCols
|
|
|
|
|
, mkUpdateByPkMutationField updByPkCustName tn updCols pKey
|
|
|
|
|
)
|
|
|
|
|
|
2019-09-19 07:47:36 +03:00
|
|
|
|
delCustName = getCustomNameWith _tcrfDelete
|
2018-06-27 16:11:32 +03:00
|
|
|
|
getDelDet (delFltr, hdrs) =
|
2020-02-13 20:38:23 +03:00
|
|
|
|
( MCDelete $ DelOpCtx tn hdrs colGNameMap delFltr
|
2019-09-19 07:47:36 +03:00
|
|
|
|
, mkDelMutFld delCustName tn
|
2019-02-22 13:27:38 +03:00
|
|
|
|
)
|
2020-02-13 20:38:23 +03:00
|
|
|
|
delByPkCustName = getCustomNameWith _tcrfDeleteByPk
|
|
|
|
|
getDelByPkDet ((delFltr, hdrs), pKey) =
|
|
|
|
|
( MCDeleteByPk $ DelOpCtx tn hdrs colGNameMap delFltr
|
|
|
|
|
, mkDeleteByPkMutationField delByPkCustName tn pKey
|
|
|
|
|
)
|
2019-09-19 07:47:36 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
selCustName = getCustomNameWith _tcrfSelect
|
2018-10-26 12:02:44 +03:00
|
|
|
|
getSelDet (selFltr, pLimit, hdrs, _) =
|
2019-09-19 07:47:36 +03:00
|
|
|
|
selFldHelper QCSelect (mkSelFld selCustName) selFltr pLimit hdrs
|
2018-06-27 16:11:32 +03:00
|
|
|
|
|
2019-09-19 07:47:36 +03:00
|
|
|
|
selAggCustName = getCustomNameWith _tcrfSelectAggregate
|
2019-02-22 13:27:38 +03:00
|
|
|
|
getSelAggDet (Just (selFltr, pLimit, hdrs, True)) =
|
2019-09-19 07:47:36 +03:00
|
|
|
|
Just $ selFldHelper QCSelectAgg (mkAggSelFld selAggCustName)
|
|
|
|
|
selFltr pLimit hdrs
|
2019-02-22 13:27:38 +03:00
|
|
|
|
getSelAggDet _ = Nothing
|
|
|
|
|
|
|
|
|
|
selFldHelper f g pFltr pLimit hdrs =
|
2019-09-19 07:47:36 +03:00
|
|
|
|
( f $ SelOpCtx tn hdrs colGNameMap pFltr pLimit
|
2019-07-23 14:12:59 +03:00
|
|
|
|
, g tn
|
2019-02-22 13:27:38 +03:00
|
|
|
|
)
|
2018-10-26 12:02:44 +03:00
|
|
|
|
|
2019-09-19 07:47:36 +03:00
|
|
|
|
selByPkCustName = getCustomNameWith _tcrfSelectByPk
|
2019-12-09 07:18:53 +03:00
|
|
|
|
getPKeySelDet (selFltr, _, hdrs, _) key =
|
|
|
|
|
let keyColumns = toList $ _pkColumns key
|
|
|
|
|
in ( QCSelectPkey . SelPkOpCtx tn hdrs selFltr $ mkPGColGNameMap keyColumns
|
|
|
|
|
, mkSelFldPKey selByPkCustName tn keyColumns
|
|
|
|
|
)
|
2018-08-27 17:17:03 +03:00
|
|
|
|
|
2019-01-25 06:31:54 +03:00
|
|
|
|
getFuncQueryFlds (selFltr, pLimit, hdrs, _) =
|
2019-07-23 14:12:59 +03:00
|
|
|
|
funcFldHelper QCFuncQuery mkFuncQueryFld selFltr pLimit hdrs
|
2019-01-25 06:31:54 +03:00
|
|
|
|
|
|
|
|
|
getFuncAggQueryFlds (selFltr, pLimit, hdrs, True) =
|
2019-07-23 14:12:59 +03:00
|
|
|
|
funcFldHelper QCFuncAggQuery mkFuncAggQueryFld selFltr pLimit hdrs
|
2019-02-22 13:27:38 +03:00
|
|
|
|
getFuncAggQueryFlds _ = []
|
|
|
|
|
|
|
|
|
|
funcFldHelper f g pFltr pLimit hdrs =
|
2019-01-25 06:31:54 +03:00
|
|
|
|
flip map funcs $ \fi ->
|
2019-12-10 05:27:44 +03:00
|
|
|
|
( f $ FuncQOpCtx (fiName fi) (mkFuncArgItemSeq fi) hdrs colGNameMap pFltr pLimit
|
2019-09-17 04:51:11 +03:00
|
|
|
|
, g fi $ fiDescription fi
|
2019-02-22 13:27:38 +03:00
|
|
|
|
)
|
|
|
|
|
|
2019-11-20 09:47:06 +03:00
|
|
|
|
mkFuncArgItemSeq functionInfo =
|
|
|
|
|
let inputArgs = fiInputArgs functionInfo
|
|
|
|
|
in Seq.fromList $ procFuncArgs inputArgs nameFn resultFn
|
|
|
|
|
where
|
|
|
|
|
nameFn = \case
|
|
|
|
|
IAUserProvided fa -> faName fa
|
|
|
|
|
IASessionVariables name -> Just name
|
|
|
|
|
resultFn arg gName = flip fmap arg $
|
|
|
|
|
\fa -> FunctionArgItem (G.Name gName) (faName fa) (faHasDefault fa)
|
2019-01-25 06:31:54 +03:00
|
|
|
|
|
|
|
|
|
|
2019-11-20 21:21:30 +03:00
|
|
|
|
getSelPermission :: TableInfo -> RoleName -> Maybe SelPermInfo
|
2020-04-24 12:10:53 +03:00
|
|
|
|
getSelPermission tabInfo roleName =
|
|
|
|
|
Map.lookup roleName (_tiRolePermInfoMap tabInfo) >>= _permSel
|
2018-10-26 14:57:33 +03:00
|
|
|
|
|
2018-10-26 12:02:44 +03:00
|
|
|
|
getSelPerm
|
2018-06-27 16:11:32 +03:00
|
|
|
|
:: (MonadError QErr m)
|
2019-11-20 21:21:30 +03:00
|
|
|
|
=> TableCache
|
2018-06-27 16:11:32 +03:00
|
|
|
|
-- all the fields of a table
|
2019-11-20 21:21:30 +03:00
|
|
|
|
-> FieldInfoMap FieldInfo
|
2018-06-27 16:11:32 +03:00
|
|
|
|
-- role and its permission
|
|
|
|
|
-> RoleName -> SelPermInfo
|
2018-10-26 12:02:44 +03:00
|
|
|
|
-> m (Bool, [SelField])
|
2020-04-24 12:10:53 +03:00
|
|
|
|
getSelPerm tableCache fields roleName selPermInfo = do
|
2020-05-27 18:02:58 +03:00
|
|
|
|
selFlds <- fmap catMaybes $ forM (filter isValidField $ Map.elems fields) $ \case
|
|
|
|
|
FIColumn pgColInfo ->
|
|
|
|
|
return $ fmap SFPGColumn $ bool Nothing (Just pgColInfo) $
|
|
|
|
|
Set.member (pgiColumn pgColInfo) $ spiCols selPermInfo
|
|
|
|
|
FIRelationship relInfo -> do
|
2018-10-05 18:13:51 +03:00
|
|
|
|
remTableInfo <- getTabInfo tableCache $ riRTable relInfo
|
2020-04-24 12:10:53 +03:00
|
|
|
|
let remTableSelPermM = getSelPermission remTableInfo roleName
|
2019-11-20 21:21:30 +03:00
|
|
|
|
remTableFlds = _tciFieldInfoMap $ _tiCoreInfo remTableInfo
|
2019-09-19 07:47:36 +03:00
|
|
|
|
remTableColGNameMap =
|
|
|
|
|
mkPGColGNameMap $ getValidCols remTableFlds
|
2018-08-06 15:15:08 +03:00
|
|
|
|
return $ flip fmap remTableSelPermM $
|
2019-10-18 11:29:47 +03:00
|
|
|
|
\rmSelPermM -> SFRelationship RelationshipFieldInfo
|
2019-09-19 07:47:36 +03:00
|
|
|
|
{ _rfiInfo = relInfo
|
|
|
|
|
, _rfiAllowAgg = spiAllowAgg rmSelPermM
|
|
|
|
|
, _rfiColumns = remTableColGNameMap
|
|
|
|
|
, _rfiPermFilter = spiFilter rmSelPermM
|
|
|
|
|
, _rfiPermLimit = spiLimit rmSelPermM
|
|
|
|
|
, _rfiIsNullable = isRelNullable fields relInfo
|
|
|
|
|
}
|
2020-05-27 18:02:58 +03:00
|
|
|
|
FIComputedField info -> do
|
|
|
|
|
let ComputedFieldInfo name function returnTy _ = info
|
|
|
|
|
inputArgSeq = mkComputedFieldFunctionArgSeq $ _cffInputArgs function
|
|
|
|
|
fmap (SFComputedField . ComputedField name function inputArgSeq) <$>
|
|
|
|
|
case returnTy of
|
|
|
|
|
CFRScalar scalarTy -> pure $ Just $ CFTScalar scalarTy
|
|
|
|
|
CFRSetofTable retTable -> do
|
|
|
|
|
retTableInfo <- getTabInfo tableCache retTable
|
|
|
|
|
let retTableSelPermM = getSelPermission retTableInfo roleName
|
|
|
|
|
retTableFlds = _tciFieldInfoMap $ _tiCoreInfo retTableInfo
|
|
|
|
|
retTableColGNameMap =
|
|
|
|
|
mkPGColGNameMap $ getValidCols retTableFlds
|
|
|
|
|
pure $ flip fmap retTableSelPermM $
|
|
|
|
|
\selPerm -> CFTTable ComputedFieldTable
|
|
|
|
|
{ _cftTable = retTable
|
|
|
|
|
, _cftCols = retTableColGNameMap
|
|
|
|
|
, _cftPermFilter = spiFilter selPerm
|
|
|
|
|
, _cftPermLimit = spiLimit selPerm
|
|
|
|
|
}
|
|
|
|
|
-- TODO: Derive permissions for remote relationships
|
|
|
|
|
FIRemoteRelationship remoteField -> pure $ Just (SFRemoteRelationship remoteField)
|
|
|
|
|
|
|
|
|
|
return (spiAllowAgg selPermInfo, selFlds)
|
2018-10-05 18:13:51 +03:00
|
|
|
|
|
|
|
|
|
mkInsCtx
|
|
|
|
|
:: MonadError QErr m
|
|
|
|
|
=> RoleName
|
2019-11-20 21:21:30 +03:00
|
|
|
|
-> TableCache
|
|
|
|
|
-> FieldInfoMap FieldInfo
|
2019-03-07 13:24:07 +03:00
|
|
|
|
-> InsPermInfo
|
|
|
|
|
-> Maybe UpdPermInfo
|
|
|
|
|
-> m InsCtx
|
2019-03-22 10:08:42 +03:00
|
|
|
|
mkInsCtx role tableCache fields insPermInfo updPermM = do
|
2018-10-05 18:13:51 +03:00
|
|
|
|
relTupsM <- forM rels $ \relInfo -> do
|
|
|
|
|
let remoteTable = riRTable relInfo
|
|
|
|
|
relName = riName relInfo
|
|
|
|
|
remoteTableInfo <- getTabInfo tableCache remoteTable
|
2018-10-16 13:25:41 +03:00
|
|
|
|
let insPermM = getInsPerm remoteTableInfo role
|
2019-11-20 21:21:30 +03:00
|
|
|
|
viewInfoM = _tciViewInfo $ _tiCoreInfo remoteTableInfo
|
2018-10-16 13:25:41 +03:00
|
|
|
|
return $ bool Nothing (Just (relName, relInfo)) $
|
2019-04-15 10:04:30 +03:00
|
|
|
|
isInsertable insPermM viewInfoM && isValidRel relName remoteTable
|
2018-10-05 18:13:51 +03:00
|
|
|
|
|
|
|
|
|
let relInfoMap = Map.fromList $ catMaybes relTupsM
|
2020-01-16 07:53:28 +03:00
|
|
|
|
return $ InsCtx gNamePGColMap checkCond setCols relInfoMap updPermForIns
|
2018-10-05 18:13:51 +03:00
|
|
|
|
where
|
2019-09-19 07:47:36 +03:00
|
|
|
|
gNamePGColMap = mkPGColGNameMap allCols
|
2019-04-15 10:04:30 +03:00
|
|
|
|
allCols = getCols fields
|
2018-10-26 14:57:33 +03:00
|
|
|
|
rels = getValidRels fields
|
2018-10-26 17:58:20 +03:00
|
|
|
|
setCols = ipiSet insPermInfo
|
2020-01-16 07:53:28 +03:00
|
|
|
|
checkCond = ipiCheck insPermInfo
|
2018-12-15 19:10:29 +03:00
|
|
|
|
updPermForIns = mkUpdPermForIns <$> updPermM
|
2020-02-13 10:38:49 +03:00
|
|
|
|
mkUpdPermForIns upi = UpdPermForIns (toList $ upiCols upi) (upiCheck upi)
|
2019-02-23 13:36:42 +03:00
|
|
|
|
(upiFilter upi) (upiSet upi)
|
2018-10-05 18:13:51 +03:00
|
|
|
|
|
2018-10-16 13:25:41 +03:00
|
|
|
|
isInsertable Nothing _ = False
|
|
|
|
|
isInsertable (Just _) viewInfoM = isMutable viIsInsertable viewInfoM
|
|
|
|
|
|
|
|
|
|
mkAdminInsCtx
|
|
|
|
|
:: MonadError QErr m
|
2020-01-16 07:53:28 +03:00
|
|
|
|
=> TableCache
|
2019-11-20 21:21:30 +03:00
|
|
|
|
-> FieldInfoMap FieldInfo
|
2019-03-07 13:24:07 +03:00
|
|
|
|
-> m InsCtx
|
2020-01-16 07:53:28 +03:00
|
|
|
|
mkAdminInsCtx tc fields = do
|
2018-10-16 13:25:41 +03:00
|
|
|
|
relTupsM <- forM rels $ \relInfo -> do
|
|
|
|
|
let remoteTable = riRTable relInfo
|
|
|
|
|
relName = riName relInfo
|
|
|
|
|
remoteTableInfo <- getTabInfo tc remoteTable
|
2019-11-20 21:21:30 +03:00
|
|
|
|
let viewInfoM = _tciViewInfo $ _tiCoreInfo remoteTableInfo
|
2018-10-16 13:25:41 +03:00
|
|
|
|
return $ bool Nothing (Just (relName, relInfo)) $
|
2019-04-15 10:04:30 +03:00
|
|
|
|
isMutable viIsInsertable viewInfoM && isValidRel relName remoteTable
|
2018-10-16 13:25:41 +03:00
|
|
|
|
|
2018-12-15 19:10:29 +03:00
|
|
|
|
let relInfoMap = Map.fromList $ catMaybes relTupsM
|
2020-02-13 10:38:49 +03:00
|
|
|
|
updPerm = UpdPermForIns updCols Nothing noFilter Map.empty
|
2018-12-15 19:10:29 +03:00
|
|
|
|
|
2020-01-16 07:53:28 +03:00
|
|
|
|
return $ InsCtx colGNameMap noFilter Map.empty relInfoMap (Just updPerm)
|
2018-10-05 18:13:51 +03:00
|
|
|
|
where
|
2019-04-15 10:04:30 +03:00
|
|
|
|
allCols = getCols fields
|
2019-09-19 07:47:36 +03:00
|
|
|
|
colGNameMap = mkPGColGNameMap allCols
|
|
|
|
|
updCols = map pgiColumn allCols
|
2018-10-26 14:57:33 +03:00
|
|
|
|
rels = getValidRels fields
|
2018-06-27 16:11:32 +03:00
|
|
|
|
|
2019-09-19 07:47:36 +03:00
|
|
|
|
mkAdminSelFlds
|
|
|
|
|
:: MonadError QErr m
|
2019-11-20 21:21:30 +03:00
|
|
|
|
=> FieldInfoMap FieldInfo
|
|
|
|
|
-> TableCache
|
2019-09-19 07:47:36 +03:00
|
|
|
|
-> m [SelField]
|
2020-05-27 18:02:58 +03:00
|
|
|
|
mkAdminSelFlds fields tableCache =
|
|
|
|
|
forM (filter isValidField $ Map.elems fields) $ \case
|
|
|
|
|
FIColumn info -> pure $ SFPGColumn info
|
|
|
|
|
|
|
|
|
|
FIRelationship info -> do
|
|
|
|
|
let remoteTable = riRTable info
|
|
|
|
|
remoteTableInfo <- _tiCoreInfo <$> getTabInfo tableCache remoteTable
|
|
|
|
|
let remoteTableFlds = _tciFieldInfoMap remoteTableInfo
|
|
|
|
|
remoteTableColGNameMap =
|
|
|
|
|
mkPGColGNameMap $ getValidCols remoteTableFlds
|
|
|
|
|
return $ SFRelationship RelationshipFieldInfo
|
|
|
|
|
{ _rfiInfo = info
|
|
|
|
|
, _rfiAllowAgg = True
|
|
|
|
|
, _rfiColumns = remoteTableColGNameMap
|
|
|
|
|
, _rfiPermFilter = noFilter
|
|
|
|
|
, _rfiPermLimit = Nothing
|
|
|
|
|
, _rfiIsNullable = isRelNullable fields info
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FIComputedField info -> do
|
|
|
|
|
let ComputedFieldInfo name function returnTy _ = info
|
|
|
|
|
inputArgSeq = mkComputedFieldFunctionArgSeq $ _cffInputArgs function
|
|
|
|
|
(SFComputedField . ComputedField name function inputArgSeq) <$>
|
|
|
|
|
case returnTy of
|
|
|
|
|
CFRScalar scalarTy -> pure $ CFTScalar scalarTy
|
|
|
|
|
CFRSetofTable retTable -> do
|
|
|
|
|
retTableInfo <- _tiCoreInfo <$> getTabInfo tableCache retTable
|
|
|
|
|
let retTableFlds = _tciFieldInfoMap retTableInfo
|
|
|
|
|
retTableColGNameMap =
|
|
|
|
|
mkPGColGNameMap $ getValidCols retTableFlds
|
|
|
|
|
pure $ CFTTable ComputedFieldTable
|
|
|
|
|
{ _cftTable = retTable
|
|
|
|
|
, _cftCols = retTableColGNameMap
|
|
|
|
|
, _cftPermFilter = noFilter
|
|
|
|
|
, _cftPermLimit = Nothing
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FIRemoteRelationship info -> pure $ SFRemoteRelationship info
|
2019-09-19 07:47:36 +03:00
|
|
|
|
|
2018-06-27 16:11:32 +03:00
|
|
|
|
mkGCtxRole
|
|
|
|
|
:: (MonadError QErr m)
|
2019-11-20 21:21:30 +03:00
|
|
|
|
=> TableCache
|
2018-06-27 16:11:32 +03:00
|
|
|
|
-> QualifiedTable
|
2019-09-17 04:51:11 +03:00
|
|
|
|
-> Maybe PGDescription
|
2019-11-20 21:21:30 +03:00
|
|
|
|
-> FieldInfoMap FieldInfo
|
2019-12-09 07:18:53 +03:00
|
|
|
|
-> Maybe (PrimaryKey PGColumnInfo)
|
2019-03-22 10:08:42 +03:00
|
|
|
|
-> [ConstraintName]
|
2019-01-25 06:31:54 +03:00
|
|
|
|
-> [FunctionInfo]
|
2018-10-12 15:06:12 +03:00
|
|
|
|
-> Maybe ViewInfo
|
2019-09-19 07:47:36 +03:00
|
|
|
|
-> TableConfig
|
2018-06-27 16:11:32 +03:00
|
|
|
|
-> RoleName
|
|
|
|
|
-> RolePermInfo
|
2019-07-23 14:12:59 +03:00
|
|
|
|
-> m (TyAgg, RootFields, InsCtxMap)
|
2019-12-09 07:18:53 +03:00
|
|
|
|
mkGCtxRole tableCache tn descM fields primaryKey constraints funcs viM tabConfigM role permInfo = do
|
2018-10-26 12:02:44 +03:00
|
|
|
|
selPermM <- mapM (getSelPerm tableCache fields role) $ _permSel permInfo
|
2019-04-15 10:04:30 +03:00
|
|
|
|
tabInsInfoM <- forM (_permIns permInfo) $ \ipi -> do
|
|
|
|
|
ctx <- mkInsCtx role tableCache fields ipi $ _permUpd permInfo
|
2019-09-19 07:47:36 +03:00
|
|
|
|
let permCols = flip getColInfos allCols $ Set.toList $ ipiCols ipi
|
2019-04-15 10:04:30 +03:00
|
|
|
|
return (ctx, (permCols, icRelations ctx))
|
|
|
|
|
let insPermM = snd <$> tabInsInfoM
|
|
|
|
|
insCtxM = fst <$> tabInsInfoM
|
2019-09-19 07:47:36 +03:00
|
|
|
|
updColsM = filterColFlds . upiCols <$> _permUpd permInfo
|
2019-09-17 04:51:11 +03:00
|
|
|
|
tyAgg = mkGCtxRole' tn descM insPermM selPermM updColsM
|
2019-12-09 07:18:53 +03:00
|
|
|
|
(void $ _permDel permInfo) primaryKey constraints viM funcs
|
|
|
|
|
rootFlds = getRootFldsRole tn primaryKey constraints fields funcs
|
2019-09-19 07:47:36 +03:00
|
|
|
|
viM permInfo tabConfigM
|
2019-04-15 10:04:30 +03:00
|
|
|
|
insCtxMap = maybe Map.empty (Map.singleton tn) insCtxM
|
2018-10-05 18:13:51 +03:00
|
|
|
|
return (tyAgg, rootFlds, insCtxMap)
|
2018-06-27 16:11:32 +03:00
|
|
|
|
where
|
2019-03-07 13:24:07 +03:00
|
|
|
|
allCols = getCols fields
|
2019-09-19 07:47:36 +03:00
|
|
|
|
cols = getValidCols fields
|
|
|
|
|
filterColFlds allowedSet =
|
|
|
|
|
filter ((`Set.member` allowedSet) . pgiColumn) cols
|
2018-06-27 16:11:32 +03:00
|
|
|
|
|
|
|
|
|
getRootFldsRole
|
|
|
|
|
:: QualifiedTable
|
2019-12-09 07:18:53 +03:00
|
|
|
|
-> Maybe (PrimaryKey PGColumnInfo)
|
2019-03-22 10:08:42 +03:00
|
|
|
|
-> [ConstraintName]
|
2019-11-20 21:21:30 +03:00
|
|
|
|
-> FieldInfoMap FieldInfo
|
2019-01-25 06:31:54 +03:00
|
|
|
|
-> [FunctionInfo]
|
2018-10-12 15:06:12 +03:00
|
|
|
|
-> Maybe ViewInfo
|
2018-06-27 16:11:32 +03:00
|
|
|
|
-> RolePermInfo
|
2019-09-19 07:47:36 +03:00
|
|
|
|
-> TableConfig
|
2019-07-23 14:12:59 +03:00
|
|
|
|
-> RootFields
|
2019-09-19 07:47:36 +03:00
|
|
|
|
getRootFldsRole tn pCols constraints fields funcs viM (RolePermInfo insM selM updM delM)=
|
2019-01-25 06:31:54 +03:00
|
|
|
|
getRootFldsRole' tn pCols constraints fields funcs
|
2018-06-27 16:11:32 +03:00
|
|
|
|
(mkIns <$> insM) (mkSel <$> selM)
|
2019-09-19 07:47:36 +03:00
|
|
|
|
(mkUpd <$> updM) (mkDel <$> delM) viM
|
2018-06-27 16:11:32 +03:00
|
|
|
|
where
|
2018-12-15 19:10:29 +03:00
|
|
|
|
mkIns i = (ipiRequiredHeaders i, isJust updM)
|
2018-10-26 12:02:44 +03:00
|
|
|
|
mkSel s = ( spiFilter s, spiLimit s
|
|
|
|
|
, spiRequiredHeaders s, spiAllowAgg s
|
|
|
|
|
)
|
2019-09-19 07:47:36 +03:00
|
|
|
|
mkUpd u = ( flip getColInfos allCols $ Set.toList $ upiCols u
|
2019-02-11 15:45:30 +03:00
|
|
|
|
, upiSet u
|
2018-07-20 13:51:20 +03:00
|
|
|
|
, upiFilter u
|
2020-02-13 10:38:49 +03:00
|
|
|
|
, upiCheck u
|
2018-07-20 13:51:20 +03:00
|
|
|
|
, upiRequiredHeaders u
|
|
|
|
|
)
|
2018-06-27 16:11:32 +03:00
|
|
|
|
mkDel d = (dpiFilter d, dpiRequiredHeaders d)
|
|
|
|
|
|
2019-09-19 07:47:36 +03:00
|
|
|
|
allCols = getCols fields
|
|
|
|
|
|
2018-06-27 16:11:32 +03:00
|
|
|
|
mkGCtxMapTable
|
|
|
|
|
:: (MonadError QErr m)
|
2019-11-20 21:21:30 +03:00
|
|
|
|
=> TableCache
|
2019-01-25 06:31:54 +03:00
|
|
|
|
-> FunctionCache
|
2019-11-20 21:21:30 +03:00
|
|
|
|
-> TableInfo
|
2020-04-24 12:10:53 +03:00
|
|
|
|
-> m (Map.HashMap RoleName TableSchemaCtx)
|
2019-03-07 13:24:07 +03:00
|
|
|
|
mkGCtxMapTable tableCache funcCache tabInfo = do
|
2020-04-24 12:10:53 +03:00
|
|
|
|
m <- flip Map.traverseWithKey rolePermsMap $ \roleName rolePerm ->
|
|
|
|
|
for rolePerm $ mkGCtxRole tableCache tn descM fields primaryKey validConstraints
|
|
|
|
|
tabFuncs viewInfo customConfig roleName
|
2020-01-16 07:53:28 +03:00
|
|
|
|
adminInsCtx <- mkAdminInsCtx tableCache fields
|
2019-09-19 07:47:36 +03:00
|
|
|
|
adminSelFlds <- mkAdminSelFlds fields tableCache
|
|
|
|
|
let adminCtx = mkGCtxRole' tn descM (Just (cols, icRelations adminInsCtx))
|
|
|
|
|
(Just (True, adminSelFlds)) (Just cols) (Just ())
|
2019-12-09 07:18:53 +03:00
|
|
|
|
primaryKey validConstraints viewInfo tabFuncs
|
2018-10-05 18:13:51 +03:00
|
|
|
|
adminInsCtxMap = Map.singleton tn adminInsCtx
|
2020-04-24 12:10:53 +03:00
|
|
|
|
adminTableCtx = RoleContext (adminCtx, adminRootFlds, adminInsCtxMap) Nothing
|
|
|
|
|
pure $ Map.insert adminRoleName adminTableCtx m
|
2018-06-27 16:11:32 +03:00
|
|
|
|
where
|
2019-11-20 21:21:30 +03:00
|
|
|
|
TableInfo coreInfo rolePerms _ = tabInfo
|
2019-12-09 07:18:53 +03:00
|
|
|
|
TableCoreInfo tn descM _ fields primaryKey _ _ viewInfo _ customConfig = coreInfo
|
|
|
|
|
validConstraints = mkValidConstraints $ map _cName (tciUniqueOrPrimaryKeyConstraints coreInfo)
|
2019-09-19 07:47:36 +03:00
|
|
|
|
cols = getValidCols fields
|
2020-04-24 12:10:53 +03:00
|
|
|
|
tabFuncs = filter (isValidObjectName . fiName) $ getFuncsOfTable tn funcCache
|
|
|
|
|
|
2018-06-27 16:11:32 +03:00
|
|
|
|
adminRootFlds =
|
2019-12-09 07:18:53 +03:00
|
|
|
|
getRootFldsRole' tn primaryKey validConstraints fields tabFuncs
|
2018-10-26 12:02:44 +03:00
|
|
|
|
(Just ([], True)) (Just (noFilter, Nothing, [], True))
|
2020-02-13 10:38:49 +03:00
|
|
|
|
(Just (cols, mempty, noFilter, Nothing, [])) (Just (noFilter, []))
|
2019-09-19 07:47:36 +03:00
|
|
|
|
viewInfo customConfig
|
2018-06-27 16:11:32 +03:00
|
|
|
|
|
2020-04-24 12:10:53 +03:00
|
|
|
|
rolePermsMap :: Map.HashMap RoleName (RoleContext RolePermInfo)
|
|
|
|
|
rolePermsMap = flip Map.map rolePerms $ \permInfo ->
|
|
|
|
|
case _permIns permInfo of
|
|
|
|
|
Nothing -> RoleContext permInfo Nothing
|
|
|
|
|
Just insPerm ->
|
|
|
|
|
if ipiBackendOnly insPerm then
|
|
|
|
|
-- Remove insert permission from 'default' context and keep it in 'backend' context.
|
|
|
|
|
RoleContext { _rctxDefault = permInfo{_permIns = Nothing}
|
|
|
|
|
, _rctxBackend = Just permInfo
|
|
|
|
|
}
|
|
|
|
|
-- Remove insert permission from 'backend' context and keep it in 'default' context.
|
|
|
|
|
else RoleContext { _rctxDefault = permInfo
|
|
|
|
|
, _rctxBackend = Just permInfo{_permIns = Nothing}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-17 12:48:41 +03:00
|
|
|
|
noFilter :: AnnBoolExpPartialSQL
|
2018-11-16 15:40:23 +03:00
|
|
|
|
noFilter = annBoolExpTrue
|
2018-10-26 14:57:33 +03:00
|
|
|
|
|
2020-04-24 12:10:53 +03:00
|
|
|
|
{- Note [Split schema generation (TODO)]
|
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
As of writing this, the schema is generated per table per role and for all permissions.
|
|
|
|
|
See functions "mkGCtxRole'" and "getRootFldsRole'". This approach makes hard to
|
|
|
|
|
differentiate schema generation for each operation (select, insert, delete and update)
|
|
|
|
|
based on respective permission information and safe merging those schemas eventually.
|
|
|
|
|
For backend-only inserts (see https://github.com/hasura/graphql-engine/pull/4224)
|
|
|
|
|
we need to somehow defer the logic of merging schema for inserts with others based on its
|
|
|
|
|
backend-only credibility. This requires significant refactor of this module and
|
|
|
|
|
we can't afford to do it as of now since we're going to rewrite the entire GraphQL schema
|
|
|
|
|
generation (see https://github.com/hasura/graphql-engine/pull/4111). For aforementioned
|
|
|
|
|
backend-only inserts, we're following a hacky implementation of generating schema for
|
|
|
|
|
both default session and one with backend privilege -- the later differs with the former by
|
|
|
|
|
only having the schema related to insert operation.
|
|
|
|
|
-}
|
|
|
|
|
|
2018-06-27 16:11:32 +03:00
|
|
|
|
mkGCtxMap
|
2019-11-20 15:40:56 +03:00
|
|
|
|
:: forall m. (MonadError QErr m)
|
2020-04-15 15:03:13 +03:00
|
|
|
|
=> TableCache -> FunctionCache -> ActionCache -> m GCtxMap
|
|
|
|
|
mkGCtxMap tableCache functionCache actionCache = do
|
2019-01-25 06:31:54 +03:00
|
|
|
|
typesMapL <- mapM (mkGCtxMapTable tableCache functionCache) $
|
2019-11-20 21:21:30 +03:00
|
|
|
|
filter (tableFltr . _tiCoreInfo) $ Map.elems tableCache
|
2020-04-15 15:03:13 +03:00
|
|
|
|
let actionsSchema = mkActionsSchema actionCache
|
2020-02-13 20:38:23 +03:00
|
|
|
|
typesMap <- combineTypes actionsSchema typesMapL
|
|
|
|
|
let gCtxMap = flip Map.map typesMap $
|
2020-04-24 12:10:53 +03:00
|
|
|
|
fmap (\(ty, flds, insCtxMap) -> mkGCtx ty flds insCtxMap)
|
|
|
|
|
pure gCtxMap
|
2018-07-27 12:50:12 +03:00
|
|
|
|
where
|
2019-11-20 21:21:30 +03:00
|
|
|
|
tableFltr ti = not (isSystemDefined $ _tciSystemDefined ti) && isValidObjectName (_tciName ti)
|
2018-06-27 16:11:32 +03:00
|
|
|
|
|
2019-11-20 15:40:56 +03:00
|
|
|
|
combineTypes
|
2020-02-13 20:38:23 +03:00
|
|
|
|
:: Map.HashMap RoleName (RootFields, TyAgg)
|
2020-04-24 12:10:53 +03:00
|
|
|
|
-> [Map.HashMap RoleName TableSchemaCtx]
|
|
|
|
|
-> m (Map.HashMap RoleName TableSchemaCtx)
|
|
|
|
|
combineTypes actionsSchema tableCtxMaps = do
|
|
|
|
|
let tableCtxsMap =
|
|
|
|
|
foldr (Map.unionWith (++) . Map.map pure)
|
|
|
|
|
((\(rf, tyAgg) -> pure $ RoleContext (tyAgg, rf, mempty) Nothing) <$> actionsSchema)
|
|
|
|
|
tableCtxMaps
|
|
|
|
|
|
|
|
|
|
flip Map.traverseWithKey tableCtxsMap $ \_ tableSchemaCtxs -> do
|
|
|
|
|
let defaultTableSchemaCtxs = map _rctxDefault tableSchemaCtxs
|
|
|
|
|
backendGCtxTypesMaybe =
|
|
|
|
|
-- If no table has 'backend' schema context then
|
|
|
|
|
-- aggregated context should be Nothing
|
|
|
|
|
if all (isNothing . _rctxBackend) tableSchemaCtxs then Nothing
|
|
|
|
|
else Just $ flip map tableSchemaCtxs $
|
|
|
|
|
-- Consider 'default' if 'backend' doesn't exist for any table
|
|
|
|
|
-- see Note [Split schema generation (TODO)]
|
|
|
|
|
\(RoleContext def backend) -> fromMaybe def backend
|
|
|
|
|
|
|
|
|
|
RoleContext <$> combineTypes' defaultTableSchemaCtxs
|
|
|
|
|
<*> mapM combineTypes' backendGCtxTypesMaybe
|
|
|
|
|
where
|
|
|
|
|
combineTypes' :: [(TyAgg, RootFields, InsCtxMap)] -> m (TyAgg, RootFields, InsCtxMap)
|
|
|
|
|
combineTypes' typeList = do
|
|
|
|
|
let tyAgg = mconcat $ map (^. _1) typeList
|
|
|
|
|
insCtx = mconcat $ map (^. _3) typeList
|
|
|
|
|
rootFields <- combineRootFields $ map (^. _2) typeList
|
|
|
|
|
pure (tyAgg, rootFields, insCtx)
|
|
|
|
|
|
|
|
|
|
combineRootFields :: [RootFields] -> m RootFields
|
|
|
|
|
combineRootFields rootFields = do
|
|
|
|
|
let duplicateQueryFields = duplicates $
|
|
|
|
|
concatMap (Map.keys . _rootQueryFields) rootFields
|
|
|
|
|
duplicateMutationFields = duplicates $
|
|
|
|
|
concatMap (Map.keys . _rootMutationFields) rootFields
|
|
|
|
|
|
|
|
|
|
-- TODO: The following exception should result in inconsistency
|
|
|
|
|
when (not $ null duplicateQueryFields) $
|
|
|
|
|
throw400 Unexpected $ "following query root fields are duplicated: "
|
|
|
|
|
<> showNames duplicateQueryFields
|
|
|
|
|
|
|
|
|
|
when (not $ null duplicateMutationFields) $
|
|
|
|
|
throw400 Unexpected $ "following mutation root fields are duplicated: "
|
|
|
|
|
<> showNames duplicateMutationFields
|
|
|
|
|
|
|
|
|
|
pure $ mconcat rootFields
|
|
|
|
|
|
|
|
|
|
getGCtx :: BackendOnlyFieldAccess -> SchemaCache -> RoleName -> GCtx
|
|
|
|
|
getGCtx backendOnlyFieldAccess sc roleName =
|
|
|
|
|
case Map.lookup roleName (scGCtxMap sc) of
|
|
|
|
|
Nothing -> scDefaultRemoteGCtx sc
|
|
|
|
|
Just (RoleContext defaultGCtx maybeBackendGCtx) ->
|
|
|
|
|
case backendOnlyFieldAccess of
|
|
|
|
|
BOFAAllowed ->
|
|
|
|
|
-- When backend field access is allowed and if there's no 'backend_only'
|
|
|
|
|
-- permissions defined, we should allow access to non backend only fields
|
|
|
|
|
fromMaybe defaultGCtx maybeBackendGCtx
|
|
|
|
|
BOFADisallowed -> defaultGCtx
|
2018-11-23 16:02:46 +03:00
|
|
|
|
|
|
|
|
|
-- pretty print GCtx
|
2018-12-12 15:01:18 +03:00
|
|
|
|
ppGCtx :: GCtx -> String
|
|
|
|
|
ppGCtx gCtx =
|
|
|
|
|
"GCtx ["
|
|
|
|
|
<> "\n types = " <> show types
|
|
|
|
|
<> "\n query root = " <> show qRoot
|
|
|
|
|
<> "\n mutation root = " <> show mRoot
|
|
|
|
|
<> "\n subscription root = " <> show sRoot
|
|
|
|
|
<> "\n]"
|
|
|
|
|
|
|
|
|
|
where
|
|
|
|
|
types = map (G.unName . G.unNamedType) $ Map.keys $ _gTypes gCtx
|
|
|
|
|
qRoot = (,) (_otiName qRootO) $
|
|
|
|
|
map G.unName $ Map.keys $ _otiFields qRootO
|
|
|
|
|
mRoot = (,) (_otiName <$> mRootO) $
|
|
|
|
|
maybe [] (map G.unName . Map.keys . _otiFields) mRootO
|
|
|
|
|
sRoot = (,) (_otiName <$> sRootO) $
|
|
|
|
|
maybe [] (map G.unName . Map.keys . _otiFields) sRootO
|
|
|
|
|
qRootO = _gQueryRoot gCtx
|
|
|
|
|
mRootO = _gMutRoot gCtx
|
|
|
|
|
sRootO = _gSubRoot gCtx
|
2019-08-09 12:19:17 +03:00
|
|
|
|
|
2019-07-23 14:12:59 +03:00
|
|
|
|
mkGCtx :: TyAgg -> RootFields -> InsCtxMap -> GCtx
|
|
|
|
|
mkGCtx tyAgg (RootFields queryFields mutationFields) insCtxMap =
|
2019-08-09 12:19:17 +03:00
|
|
|
|
let queryRoot = mkQueryRootTyInfo qFlds
|
|
|
|
|
scalarTys = map (TIScalar . mkHsraScalarTyInfo) (Set.toList allScalarTypes)
|
|
|
|
|
compTys = map (TIInpObj . mkCompExpInp) (Set.toList allComparableTypes)
|
|
|
|
|
ordByEnumTyM = bool (Just ordByEnumTy) Nothing $ null qFlds
|
|
|
|
|
allTys = Map.union tyInfos $ mkTyInfoMap $
|
|
|
|
|
catMaybes [ Just $ TIObj queryRoot
|
|
|
|
|
, TIObj <$> mutRootM
|
|
|
|
|
, TIObj <$> subRootM
|
|
|
|
|
, TIEnum <$> ordByEnumTyM
|
|
|
|
|
] <>
|
|
|
|
|
scalarTys <> compTys <> defaultTypes <> wiredInGeoInputTypes
|
2019-08-29 16:07:05 +03:00
|
|
|
|
<> wiredInRastInputTypes
|
2019-08-09 12:19:17 +03:00
|
|
|
|
-- for now subscription root is query root
|
2019-07-23 14:12:59 +03:00
|
|
|
|
in GCtx allTys fldInfos queryRoot mutRootM subRootM ordByEnums
|
|
|
|
|
(Map.map fst queryFields) (Map.map fst mutationFields) insCtxMap
|
2019-08-09 12:19:17 +03:00
|
|
|
|
where
|
|
|
|
|
TyAgg tyInfos fldInfos scalars ordByEnums = tyAgg
|
2019-10-18 11:29:47 +03:00
|
|
|
|
colTys = Set.fromList $ map pgiType $ mapMaybe (^? _RFPGColumn) $
|
|
|
|
|
Map.elems fldInfos
|
2019-08-09 12:19:17 +03:00
|
|
|
|
mkMutRoot =
|
2020-04-24 12:10:53 +03:00
|
|
|
|
mkHsraObjTyInfo (Just "mutation root") mutationRootNamedType Set.empty .
|
2019-08-09 12:19:17 +03:00
|
|
|
|
mapFromL _fiName
|
|
|
|
|
mutRootM = bool (Just $ mkMutRoot mFlds) Nothing $ null mFlds
|
|
|
|
|
mkSubRoot =
|
|
|
|
|
mkHsraObjTyInfo (Just "subscription root")
|
2020-04-24 12:10:53 +03:00
|
|
|
|
subscriptionRootNamedType Set.empty . mapFromL _fiName
|
2019-08-09 12:19:17 +03:00
|
|
|
|
subRootM = bool (Just $ mkSubRoot qFlds) Nothing $ null qFlds
|
2019-07-23 14:12:59 +03:00
|
|
|
|
|
|
|
|
|
qFlds = rootFieldInfos queryFields
|
|
|
|
|
mFlds = rootFieldInfos mutationFields
|
|
|
|
|
rootFieldInfos = map snd . Map.elems
|
2019-08-09 12:19:17 +03:00
|
|
|
|
|
2019-07-22 15:47:13 +03:00
|
|
|
|
anyGeoTypes = any (isScalarColumnWhere isGeoType) colTys
|
2019-08-09 12:19:17 +03:00
|
|
|
|
allComparableTypes =
|
|
|
|
|
if anyGeoTypes
|
|
|
|
|
-- due to casting, we need to generate both geometry and geography
|
|
|
|
|
-- operations even if just one of the two appears in the schema
|
2019-07-22 15:47:13 +03:00
|
|
|
|
then Set.union (Set.fromList [PGColumnScalar PGGeometry, PGColumnScalar PGGeography]) colTys
|
2019-08-09 12:19:17 +03:00
|
|
|
|
else colTys
|
2019-08-29 16:07:05 +03:00
|
|
|
|
|
2020-01-11 07:05:07 +03:00
|
|
|
|
additionalScalars = Set.fromList $
|
2019-08-29 16:07:05 +03:00
|
|
|
|
-- raster comparison expression needs geometry input
|
|
|
|
|
(guard anyRasterTypes *> pure PGGeometry)
|
2020-01-11 07:05:07 +03:00
|
|
|
|
-- scalar computed field return types
|
|
|
|
|
<> mapMaybe (^? _RFComputedField.cfType._CFTScalar) (Map.elems fldInfos)
|
2019-08-29 16:07:05 +03:00
|
|
|
|
|
|
|
|
|
allScalarTypes = (allComparableTypes ^.. folded._PGColumnScalar)
|
|
|
|
|
<> additionalScalars <> scalars
|
2019-08-09 12:19:17 +03:00
|
|
|
|
|
|
|
|
|
wiredInGeoInputTypes = guard anyGeoTypes *> map TIInpObj geoInputTypes
|
2019-08-29 16:07:05 +03:00
|
|
|
|
|
|
|
|
|
anyRasterTypes = any (isScalarColumnWhere (== PGRaster)) colTys
|
|
|
|
|
wiredInRastInputTypes = guard anyRasterTypes *>
|
|
|
|
|
map TIInpObj rasterIntersectsInputTypes
|