mirror of
https://github.com/zhigang1992/graphql-engine.git
synced 2026-06-02 06:30:28 +08:00
* add types to represent unparsed http gql requests
This will help when we add caching of frequently used ASTs
* query plan caching
* move livequery to execute
* add multiplexed module
* session variable can be customised depending on the context
Previously the value was always "current_setting('hasura.user')"
* get rid of typemap requirement in reusable plan
* subscriptions are multiplexed when possible
* use lazytx for introspection to avoid acquiring a pg connection
* refactor to make execute a completely decoupled module
* don't issue a transaction for a query
* don't use current setting for explained sql
* move postgres related types to a different module
* validate variableValues on postgres before multiplexing subs
* don't user current_setting for queries over ws
* plan_cache is only visible when developer flag is enabled
* introduce 'batch size' when multiplexing subscriptions
* bump stackage to 13.16
* fix schema_stitching test case error code
* store hashes instead of actual responses for subscriptions
* internal api to dump subscriptions state
* remove PlanCache from SchemaCacheRef
* allow live query options to be configured on server startup
* capture metrics for multiplexed subscriptions
* more metrics captured for multiplexed subs
* switch to tvar based hashmap for faster snapshotting
* livequery modules do not expose internal details
* fix typo in live query env vars
* switch to hasura's pg-client-hs
138 lines
4.1 KiB
Haskell
138 lines
4.1 KiB
Haskell
module Hasura.GraphQL.Resolve
|
|
( mutFldToTx
|
|
, queryFldToPGAST
|
|
, RS.traverseQueryRootFldAST
|
|
, RS.toPGQuery
|
|
, UnresolvedVal(..)
|
|
, AnnPGVal(..)
|
|
, RS.QueryRootFldUnresolved
|
|
, resolveValPrep
|
|
, queryFldToSQL
|
|
, schemaR
|
|
, typeR
|
|
) where
|
|
|
|
import Data.Has
|
|
|
|
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.Context
|
|
import Hasura.GraphQL.Resolve.Context
|
|
import Hasura.GraphQL.Resolve.Introspect
|
|
import Hasura.GraphQL.Validate.Field
|
|
import Hasura.Prelude
|
|
import Hasura.RQL.DML.Internal (sessVarFromCurrentSetting)
|
|
import Hasura.RQL.Types
|
|
import Hasura.SQL.Types
|
|
|
|
import qualified Hasura.GraphQL.Resolve.Insert as RI
|
|
import qualified Hasura.GraphQL.Resolve.Mutation as RM
|
|
import qualified Hasura.GraphQL.Resolve.Select as RS
|
|
|
|
validateHdrs
|
|
:: (Foldable t, QErrM m) => UserInfo -> t Text -> m ()
|
|
validateHdrs userInfo hdrs = do
|
|
let receivedVars = userVars userInfo
|
|
forM_ hdrs $ \hdr ->
|
|
unless (isJust $ getVarVal hdr receivedVars) $
|
|
throw400 NotFound $ hdr <<> " header is expected but not found"
|
|
|
|
queryFldToPGAST
|
|
:: ( MonadError QErr m, MonadReader r m, Has FieldMap r
|
|
, Has OrdByCtx r, Has SQLGenCtx r, Has UserInfo r
|
|
, Has OpCtxMap r
|
|
)
|
|
=> Field
|
|
-> m RS.QueryRootFldUnresolved
|
|
queryFldToPGAST fld = do
|
|
opCtx <- getOpCtx $ _fName fld
|
|
userInfo <- asks getter
|
|
case opCtx of
|
|
OCSelect ctx -> do
|
|
validateHdrs userInfo (_socHeaders ctx)
|
|
RS.convertSelect ctx fld
|
|
OCSelectPkey ctx -> do
|
|
validateHdrs userInfo (_spocHeaders ctx)
|
|
RS.convertSelectByPKey ctx fld
|
|
OCSelectAgg ctx -> do
|
|
validateHdrs userInfo (_socHeaders ctx)
|
|
RS.convertAggSelect ctx fld
|
|
OCFuncQuery ctx -> do
|
|
validateHdrs userInfo (_fqocHeaders ctx)
|
|
RS.convertFuncQuerySimple ctx fld
|
|
OCFuncAggQuery ctx -> do
|
|
validateHdrs userInfo (_fqocHeaders ctx)
|
|
RS.convertFuncQueryAgg ctx fld
|
|
OCInsert _ ->
|
|
throw500 "unexpected OCInsert for query field context"
|
|
OCUpdate _ ->
|
|
throw500 "unexpected OCUpdate for query field context"
|
|
OCDelete _ ->
|
|
throw500 "unexpected OCDelete for query field context"
|
|
|
|
queryFldToSQL
|
|
:: ( MonadError QErr m, MonadReader r m, Has FieldMap r
|
|
, Has OrdByCtx r, Has SQLGenCtx r, Has UserInfo r
|
|
, Has OpCtxMap r
|
|
)
|
|
=> PrepFn m
|
|
-> Field
|
|
-> m Q.Query
|
|
queryFldToSQL fn fld = do
|
|
pgAST <- queryFldToPGAST fld
|
|
resolvedAST <- flip RS.traverseQueryRootFldAST pgAST $ \case
|
|
UVPG annPGVal -> fn annPGVal
|
|
UVSQL sqlExp -> return sqlExp
|
|
UVSessVar colTy sessVar -> sessVarFromCurrentSetting colTy sessVar
|
|
return $ RS.toPGQuery resolvedAST
|
|
|
|
mutFldToTx
|
|
:: ( MonadError QErr m
|
|
, MonadReader r m
|
|
, Has UserInfo r
|
|
, Has OpCtxMap r
|
|
, Has FieldMap r
|
|
, Has OrdByCtx r
|
|
, Has SQLGenCtx r
|
|
, Has InsCtxMap r
|
|
)
|
|
=> Field
|
|
-> m RespTx
|
|
mutFldToTx fld = do
|
|
userInfo <- asks getter
|
|
opCtx <- getOpCtx $ _fName fld
|
|
case opCtx of
|
|
OCInsert ctx -> do
|
|
let roleName = userRole userInfo
|
|
validateHdrs userInfo (_iocHeaders ctx)
|
|
RI.convertInsert roleName (_iocTable ctx) fld
|
|
OCUpdate ctx -> do
|
|
validateHdrs userInfo (_uocHeaders ctx)
|
|
RM.convertUpdate ctx fld
|
|
OCDelete ctx -> do
|
|
validateHdrs userInfo (_docHeaders ctx)
|
|
RM.convertDelete ctx fld
|
|
OCSelect _ ->
|
|
throw500 "unexpected query field context for a mutation field"
|
|
OCSelectPkey _ ->
|
|
throw500 "unexpected query field context for a mutation field"
|
|
OCSelectAgg _ ->
|
|
throw500 "unexpected query field context for a mutation field"
|
|
OCFuncQuery _ ->
|
|
throw500 "unexpected query field context for a mutation field"
|
|
OCFuncAggQuery _ ->
|
|
throw500 "unexpected query field context for a mutation field"
|
|
|
|
getOpCtx
|
|
:: ( MonadError QErr m
|
|
, MonadReader r m
|
|
, Has OpCtxMap r
|
|
)
|
|
=> G.Name -> m OpCtx
|
|
getOpCtx f = do
|
|
opCtxMap <- asks getter
|
|
onNothing (Map.lookup f opCtxMap) $ throw500 $
|
|
"lookup failed: opctx: " <> showName f
|