2018-07-20 10:22:46 +03:00
|
|
|
{-# LANGUAGE FlexibleContexts #-}
|
|
|
|
{-# LANGUAGE LambdaCase #-}
|
|
|
|
{-# LANGUAGE NoImplicitPrelude #-}
|
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
|
|
|
|
|
|
module Hasura.GraphQL.Resolve
|
|
|
|
( resolveSelSet
|
|
|
|
) where
|
|
|
|
|
|
|
|
import Hasura.Prelude
|
|
|
|
|
|
|
|
import qualified Data.Aeson as J
|
|
|
|
import qualified Data.ByteString.Lazy as BL
|
|
|
|
import qualified Data.HashMap.Strict as Map
|
|
|
|
import qualified Database.PG.Query as Q
|
|
|
|
import qualified Language.GraphQL.Draft.Syntax as G
|
|
|
|
|
|
|
|
import Hasura.GraphQL.Resolve.Context
|
|
|
|
import Hasura.GraphQL.Resolve.Introspect
|
|
|
|
import Hasura.GraphQL.Schema
|
|
|
|
import Hasura.GraphQL.Transport.HTTP.Protocol
|
|
|
|
import Hasura.GraphQL.Validate.Field
|
|
|
|
import Hasura.RQL.Types
|
|
|
|
import Hasura.SQL.Types
|
|
|
|
|
|
|
|
import qualified Hasura.GraphQL.Resolve.Mutation as RM
|
|
|
|
import qualified Hasura.GraphQL.Resolve.Select as RS
|
|
|
|
|
|
|
|
-- {-# SCC buildTx #-}
|
|
|
|
buildTx :: UserInfo -> GCtx -> Field -> Q.TxE QErr BL.ByteString
|
|
|
|
buildTx userInfo gCtx fld = do
|
|
|
|
opCxt <- getOpCtx $ _fName fld
|
|
|
|
join $ fmap fst $ runConvert (fldMap, orderByCtx) $ case opCxt of
|
|
|
|
|
2018-08-06 15:15:08 +03:00
|
|
|
OCSelect tn permFilter permLimit hdrs ->
|
|
|
|
validateHdrs hdrs >> RS.convertSelect tn permFilter permLimit fld
|
2018-07-20 10:22:46 +03:00
|
|
|
-- RS.convertSelect tn permFilter fld
|
|
|
|
OCInsert tn vn cols hdrs ->
|
2018-08-17 17:44:43 +03:00
|
|
|
validateHdrs hdrs >> RM.convertInsert roleName (tn, vn) cols fld
|
2018-07-20 10:22:46 +03:00
|
|
|
-- RM.convertInsert (tn, vn) cols fld
|
|
|
|
OCUpdate tn permFilter hdrs ->
|
|
|
|
validateHdrs hdrs >> RM.convertUpdate tn permFilter fld
|
|
|
|
-- RM.convertUpdate tn permFilter fld
|
|
|
|
OCDelete tn permFilter hdrs ->
|
|
|
|
validateHdrs hdrs >> RM.convertDelete tn permFilter fld
|
|
|
|
-- RM.convertDelete tn permFilter fld
|
|
|
|
where
|
2018-08-17 17:44:43 +03:00
|
|
|
roleName = userRole userInfo
|
2018-07-20 10:22:46 +03:00
|
|
|
opCtxMap = _gOpCtxMap gCtx
|
|
|
|
fldMap = _gFields gCtx
|
|
|
|
orderByCtx = _gOrdByEnums gCtx
|
|
|
|
|
|
|
|
getOpCtx f =
|
|
|
|
onNothing (Map.lookup f opCtxMap) $ throw500 $
|
|
|
|
"lookup failed: opctx: " <> showName f
|
|
|
|
|
|
|
|
validateHdrs hdrs = do
|
|
|
|
let receivedHdrs = userHeaders userInfo
|
|
|
|
forM_ hdrs $ \hdr ->
|
|
|
|
unless (Map.member hdr receivedHdrs) $
|
|
|
|
throw400 NotFound $ hdr <<> " header is expected but not found"
|
|
|
|
|
|
|
|
-- {-# SCC resolveFld #-}
|
|
|
|
resolveFld
|
|
|
|
:: UserInfo -> GCtx
|
|
|
|
-> G.OperationType
|
|
|
|
-> Field
|
|
|
|
-> Q.TxE QErr BL.ByteString
|
|
|
|
resolveFld userInfo gCtx opTy fld =
|
|
|
|
case _fName fld of
|
|
|
|
"__type" -> J.encode <$> runReaderT (typeR fld) gCtx
|
|
|
|
"__schema" -> J.encode <$> runReaderT (schemaR fld) gCtx
|
|
|
|
"__typename" -> return $ J.encode $ mkRootTypeName opTy
|
|
|
|
_ -> buildTx userInfo gCtx fld
|
|
|
|
where
|
|
|
|
mkRootTypeName :: G.OperationType -> Text
|
|
|
|
mkRootTypeName = \case
|
|
|
|
G.OperationTypeQuery -> "query_root"
|
|
|
|
G.OperationTypeMutation -> "mutation_root"
|
|
|
|
G.OperationTypeSubscription -> "subscription_root"
|
|
|
|
|
|
|
|
resolveSelSet
|
|
|
|
:: UserInfo -> GCtx
|
|
|
|
-> G.OperationType
|
|
|
|
-> SelSet
|
|
|
|
-> Q.TxE QErr BL.ByteString
|
|
|
|
resolveSelSet userInfo gCtx opTy fields =
|
|
|
|
fmap mkJSONObj $ forM (toList fields) $ \fld -> do
|
|
|
|
fldResp <- resolveFld userInfo gCtx opTy fld
|
|
|
|
return (G.unName $ G.unAlias $ _fAlias fld, fldResp)
|