2018-08-06 15:15:08 +03:00
|
|
|
{-# LANGUAGE FlexibleContexts #-}
|
|
|
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
|
|
|
{-# LANGUAGE MultiWayIf #-}
|
|
|
|
{-# LANGUAGE NoImplicitPrelude #-}
|
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
2018-10-05 11:56:47 +03:00
|
|
|
{-# LANGUAGE TupleSections #-}
|
2018-06-27 16:11:32 +03:00
|
|
|
|
|
|
|
module Hasura.GraphQL.Resolve.Select
|
|
|
|
( convertSelect
|
2018-08-27 17:17:03 +03:00
|
|
|
, convertSelectByPKey
|
2018-08-30 12:49:21 +03:00
|
|
|
, fromSelSet
|
2018-06-27 16:11:32 +03:00
|
|
|
) where
|
|
|
|
|
|
|
|
import Data.Has
|
|
|
|
import Hasura.Prelude
|
|
|
|
|
|
|
|
import qualified Data.HashMap.Strict as Map
|
|
|
|
import qualified Language.GraphQL.Draft.Syntax as G
|
|
|
|
|
|
|
|
import qualified Hasura.RQL.DML.Select as RS
|
|
|
|
|
|
|
|
import qualified Hasura.SQL.DML as S
|
|
|
|
|
|
|
|
import Hasura.GraphQL.Resolve.BoolExp
|
|
|
|
import Hasura.GraphQL.Resolve.Context
|
|
|
|
import Hasura.GraphQL.Resolve.InputValue
|
|
|
|
import Hasura.GraphQL.Validate.Field
|
|
|
|
import Hasura.GraphQL.Validate.Types
|
2018-08-06 15:15:08 +03:00
|
|
|
import Hasura.RQL.DML.Internal (onlyPositiveInt)
|
2018-06-27 16:11:32 +03:00
|
|
|
import Hasura.RQL.Types
|
|
|
|
import Hasura.SQL.Types
|
2018-08-06 15:15:08 +03:00
|
|
|
import Hasura.SQL.Value
|
2018-06-27 16:11:32 +03:00
|
|
|
|
|
|
|
fromSelSet
|
|
|
|
:: G.NamedType
|
|
|
|
-> SelSet
|
2018-10-05 11:56:47 +03:00
|
|
|
-> Convert [(FieldName, RS.AnnFld)]
|
2018-06-27 16:11:32 +03:00
|
|
|
fromSelSet fldTy flds =
|
2018-10-05 11:56:47 +03:00
|
|
|
forM (toList flds) $ \fld -> do
|
2018-06-27 16:11:32 +03:00
|
|
|
let fldName = _fName fld
|
|
|
|
let rqlFldName = FieldName $ G.unName $ G.unAlias $ _fAlias fld
|
2018-10-05 11:56:47 +03:00
|
|
|
(rqlFldName,) <$> case fldName of
|
|
|
|
"__typename" -> return $ RS.FExp $ G.unName $ G.unNamedType fldTy
|
2018-06-27 16:11:32 +03:00
|
|
|
_ -> do
|
|
|
|
fldInfo <- getFldInfo fldTy fldName
|
|
|
|
case fldInfo of
|
2018-10-05 11:56:47 +03:00
|
|
|
Left colInfo -> return $ RS.FCol colInfo
|
2018-08-10 15:44:44 +03:00
|
|
|
Right (relInfo, tableFilter, tableLimit, _) -> do
|
2018-06-27 16:11:32 +03:00
|
|
|
let relTN = riRTable relInfo
|
2018-08-06 15:15:08 +03:00
|
|
|
relSelData <- fromField relTN tableFilter tableLimit fld
|
2018-06-27 16:11:32 +03:00
|
|
|
let annRel = RS.AnnRel (riName relInfo) (riType relInfo)
|
|
|
|
(riMapping relInfo) relSelData
|
2018-10-05 11:56:47 +03:00
|
|
|
return $ RS.FRel annRel
|
2018-06-27 16:11:32 +03:00
|
|
|
|
2018-08-06 15:15:08 +03:00
|
|
|
fieldAsPath :: (MonadError QErr m) => Field -> m a -> m a
|
|
|
|
fieldAsPath fld = nameAsPath $ _fName fld
|
|
|
|
|
2018-10-05 11:56:47 +03:00
|
|
|
parseTableArgs
|
|
|
|
:: QualifiedTable -> ArgsMap -> Convert RS.TableArgs
|
|
|
|
parseTableArgs tn args = do
|
2018-06-27 16:11:32 +03:00
|
|
|
whereExpM <- withArgM args "where" $ convertBoolExp tn
|
|
|
|
ordByExpM <- withArgM args "order_by" parseOrderBy
|
2018-10-05 11:56:47 +03:00
|
|
|
limitExpM <- withArgM args "limit" parseLimit
|
2018-06-27 16:11:32 +03:00
|
|
|
offsetExpM <- withArgM args "offset" $ asPGColVal >=> prepare
|
2018-10-05 11:56:47 +03:00
|
|
|
return $ RS.TableArgs whereExpM ordByExpM limitExpM offsetExpM
|
|
|
|
|
|
|
|
fromField
|
|
|
|
:: QualifiedTable -> S.BoolExp -> Maybe Int -> Field -> Convert RS.AnnSel
|
|
|
|
fromField tn permFilter permLimitM fld = fieldAsPath fld $ do
|
|
|
|
tableArgs <- parseTableArgs tn args
|
|
|
|
annFlds <- fromSelSet (_fType fld) $ _fSelSet fld
|
|
|
|
return $ RS.AnnSel annFlds tn Nothing permFilter permLimitM tableArgs
|
2018-06-27 16:11:32 +03:00
|
|
|
where
|
|
|
|
args = _fArguments fld
|
|
|
|
|
|
|
|
getEnumInfo
|
|
|
|
:: ( MonadError QErr m
|
|
|
|
, MonadReader r m
|
|
|
|
, Has OrdByResolveCtx r
|
|
|
|
)
|
|
|
|
=> G.NamedType -> G.EnumValue -> m OrdByResolveCtxElem
|
|
|
|
getEnumInfo nt v = do
|
|
|
|
-- fldMap <- _gcFieldMap <$> ask
|
|
|
|
ordByCtx <- asks getter
|
|
|
|
onNothing (Map.lookup (nt,v) ordByCtx) $
|
|
|
|
throw500 $ "could not lookup " <> showName (G.unEnumValue v) <> " in " <>
|
|
|
|
showNamedTy nt
|
|
|
|
|
|
|
|
parseOrderBy
|
|
|
|
:: (MonadError QErr m
|
|
|
|
, MonadReader r m
|
|
|
|
, Has OrdByResolveCtx r
|
|
|
|
)
|
2018-10-05 11:56:47 +03:00
|
|
|
=> AnnGValue -> m [RS.AnnOrderByItem]
|
2018-06-27 16:11:32 +03:00
|
|
|
parseOrderBy v = do
|
|
|
|
enums <- withArray (const $ mapM asEnumVal) v
|
2018-10-05 11:56:47 +03:00
|
|
|
mapM (uncurry getEnumInfo) enums
|
2018-06-27 16:11:32 +03:00
|
|
|
|
2018-08-06 15:15:08 +03:00
|
|
|
parseLimit :: ( MonadError QErr m ) => AnnGValue -> m Int
|
|
|
|
parseLimit v = do
|
|
|
|
(_, pgColVal) <- asPGColVal v
|
|
|
|
limit <- maybe noIntErr return $ pgColValueToInt pgColVal
|
|
|
|
-- validate int value
|
|
|
|
onlyPositiveInt limit
|
|
|
|
return limit
|
|
|
|
where
|
|
|
|
noIntErr = throw400 Unexpected "expecting Integer value for \"limit\""
|
|
|
|
|
2018-10-05 11:56:47 +03:00
|
|
|
fromFieldByPKey
|
|
|
|
:: QualifiedTable -> S.BoolExp -> Field -> Convert RS.AnnSel
|
|
|
|
fromFieldByPKey tn permFilter fld = fieldAsPath fld $ do
|
|
|
|
boolExp <- pgColValToBoolExp tn $ _fArguments fld
|
|
|
|
annFlds <- fromSelSet (_fType fld) $ _fSelSet fld
|
|
|
|
return $ RS.AnnSel annFlds tn Nothing permFilter Nothing $
|
|
|
|
RS.noTableArgs { RS._taWhere = Just boolExp}
|
|
|
|
|
2018-06-27 16:11:32 +03:00
|
|
|
convertSelect
|
2018-08-06 15:15:08 +03:00
|
|
|
:: QualifiedTable -> S.BoolExp -> Maybe Int -> Field -> Convert RespTx
|
|
|
|
convertSelect qt permFilter permLimit fld = do
|
|
|
|
selData <- withPathK "selectionSet" $
|
|
|
|
fromField qt permFilter permLimit fld
|
2018-06-27 16:11:32 +03:00
|
|
|
prepArgs <- get
|
2018-10-05 11:56:47 +03:00
|
|
|
return $ RS.selectP2 False (selData, prepArgs)
|
2018-08-27 17:17:03 +03:00
|
|
|
|
|
|
|
convertSelectByPKey
|
|
|
|
:: QualifiedTable -> S.BoolExp -> Field -> Convert RespTx
|
|
|
|
convertSelectByPKey qt permFilter fld = do
|
|
|
|
selData <- withPathK "selectionSet" $
|
|
|
|
fromFieldByPKey qt permFilter fld
|
|
|
|
prepArgs <- get
|
2018-10-05 11:56:47 +03:00
|
|
|
return $ RS.selectP2 True (selData, prepArgs)
|