mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-11-10 10:29:12 +03:00
server/postgres: Support computed fields in permission check/filter
https://github.com/hasura/graphql-engine-mono/pull/1697 GitOrigin-RevId: 6cdf8acc90d3fd97d20a3ee68c84306c3f589370
This commit is contained in:
parent
ca567bf8cb
commit
a63fa18d9c
@ -3,6 +3,7 @@
|
|||||||
## Next release
|
## Next release
|
||||||
(Add entries below in the order of server, console, cli, docs, others)
|
(Add entries below in the order of server, console, cli, docs, others)
|
||||||
|
|
||||||
|
- server: Support computed fields in permission check/filter (close #7102)
|
||||||
- server: support computed fields in query 'order_by' (close #7103)
|
- server: support computed fields in query 'order_by' (close #7103)
|
||||||
- server: log warning if there are errors while executing clean up actions after "drop source" (previously it would throw an error)
|
- server: log warning if there are errors while executing clean up actions after "drop source" (previously it would throw an error)
|
||||||
- server: Fixed a bug where MSSQL and BigQuery would ignore environment variables set from the console
|
- server: Fixed a bug where MSSQL and BigQuery would ignore environment variables set from the console
|
||||||
|
@ -5,6 +5,8 @@ import Hasura.Prelude
|
|||||||
import qualified Data.Aeson as J
|
import qualified Data.Aeson as J
|
||||||
import qualified Data.HashMap.Strict as Map
|
import qualified Data.HashMap.Strict as Map
|
||||||
|
|
||||||
|
import Data.Text.Extended
|
||||||
|
|
||||||
import Hasura.Backends.BigQuery.Types
|
import Hasura.Backends.BigQuery.Types
|
||||||
import Hasura.Base.Error
|
import Hasura.Base.Error
|
||||||
import Hasura.RQL.IR.BoolExp
|
import Hasura.RQL.IR.BoolExp
|
||||||
@ -20,12 +22,11 @@ parseBoolExpOperations
|
|||||||
=> ValueParser 'BigQuery m v
|
=> ValueParser 'BigQuery m v
|
||||||
-> TableName
|
-> TableName
|
||||||
-> FieldInfoMap (FieldInfo 'BigQuery)
|
-> FieldInfoMap (FieldInfo 'BigQuery)
|
||||||
-> ColumnInfo 'BigQuery
|
-> ColumnReference 'BigQuery
|
||||||
-> J.Value
|
-> J.Value
|
||||||
-> m [OpExpG 'BigQuery v]
|
-> m [OpExpG 'BigQuery v]
|
||||||
parseBoolExpOperations rhsParser _table _fields columnInfo value =
|
parseBoolExpOperations rhsParser _table _fields columnRef value =
|
||||||
withPathK (columnName $ pgiColumn columnInfo) $
|
withPathK (toTxt columnRef) $ parseOperations (columnReferenceType columnRef) value
|
||||||
parseOperations (pgiType columnInfo) value
|
|
||||||
where
|
where
|
||||||
parseWithTy ty = rhsParser (CollectableTypeScalar ty)
|
parseWithTy ty = rhsParser (CollectableTypeScalar ty)
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import qualified Data.Aeson as J
|
|||||||
import qualified Data.HashMap.Strict as Map
|
import qualified Data.HashMap.Strict as Map
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
|
|
||||||
import Data.Text.Extended (dquote, (<<>))
|
import Data.Text.Extended (dquote, toTxt, (<<>))
|
||||||
|
|
||||||
import Hasura.Backends.MSSQL.Types hiding (ColumnType)
|
import Hasura.Backends.MSSQL.Types hiding (ColumnType)
|
||||||
import Hasura.Base.Error
|
import Hasura.Base.Error
|
||||||
@ -22,12 +22,11 @@ parseBoolExpOperations
|
|||||||
=> ValueParser 'MSSQL m v
|
=> ValueParser 'MSSQL m v
|
||||||
-> TableName
|
-> TableName
|
||||||
-> FieldInfoMap (FieldInfo 'MSSQL)
|
-> FieldInfoMap (FieldInfo 'MSSQL)
|
||||||
-> ColumnInfo 'MSSQL
|
-> ColumnReference 'MSSQL
|
||||||
-> J.Value
|
-> J.Value
|
||||||
-> m [OpExpG 'MSSQL v]
|
-> m [OpExpG 'MSSQL v]
|
||||||
parseBoolExpOperations rhsParser _table _fields columnInfo value =
|
parseBoolExpOperations rhsParser _table _fields columnRef value =
|
||||||
withPathK (columnNameText $ pgiColumn columnInfo) $
|
withPathK (toTxt columnRef) $ parseOperations (columnReferenceType columnRef) value
|
||||||
parseOperations (pgiType columnInfo) value
|
|
||||||
where
|
where
|
||||||
parseWithTy ty = rhsParser (CollectableTypeScalar ty)
|
parseWithTy ty = rhsParser (CollectableTypeScalar ty)
|
||||||
|
|
||||||
@ -88,7 +87,7 @@ parseBoolExpOperations rhsParser _table _fields columnInfo value =
|
|||||||
x -> throw400 UnexpectedPayload $ "Unknown operator : " <> x
|
x -> throw400 UnexpectedPayload $ "Unknown operator : " <> x
|
||||||
|
|
||||||
where
|
where
|
||||||
colTy = pgiType columnInfo
|
colTy = columnReferenceType columnRef
|
||||||
|
|
||||||
parseOne = parseWithTy columnType val
|
parseOne = parseWithTy columnType val
|
||||||
parseManyWithType ty = rhsParser (CollectableTypeArray ty) val
|
parseManyWithType ty = rhsParser (CollectableTypeArray ty) val
|
||||||
|
@ -22,23 +22,6 @@ import Hasura.SQL.Backend
|
|||||||
import Hasura.SQL.Types
|
import Hasura.SQL.Types
|
||||||
|
|
||||||
|
|
||||||
-- | Represents a reference to a Postgres column, possibly casted an arbitrary
|
|
||||||
-- number of times. Used within 'parseOperationsExpression' for bookkeeping.
|
|
||||||
data ColumnReference (b :: BackendType)
|
|
||||||
= ColumnReferenceColumn !(ColumnInfo b)
|
|
||||||
| ColumnReferenceCast !(ColumnReference b) !(ColumnType b)
|
|
||||||
|
|
||||||
columnReferenceType :: ColumnReference backend -> ColumnType backend
|
|
||||||
columnReferenceType = \case
|
|
||||||
ColumnReferenceColumn column -> pgiType column
|
|
||||||
ColumnReferenceCast _ targetType -> targetType
|
|
||||||
|
|
||||||
instance Backend b => ToTxt (ColumnReference b) where
|
|
||||||
toTxt = \case
|
|
||||||
ColumnReferenceColumn column -> toTxt $ pgiColumn column
|
|
||||||
ColumnReferenceCast reference targetType ->
|
|
||||||
toTxt reference <> "::" <> toTxt targetType
|
|
||||||
|
|
||||||
parseBoolExpOperations
|
parseBoolExpOperations
|
||||||
:: forall pgKind m v
|
:: forall pgKind m v
|
||||||
. ( Backend ('Postgres pgKind)
|
. ( Backend ('Postgres pgKind)
|
||||||
@ -48,19 +31,18 @@ parseBoolExpOperations
|
|||||||
=> ValueParser ('Postgres pgKind) m v
|
=> ValueParser ('Postgres pgKind) m v
|
||||||
-> QualifiedTable
|
-> QualifiedTable
|
||||||
-> FieldInfoMap (FieldInfo ('Postgres pgKind))
|
-> FieldInfoMap (FieldInfo ('Postgres pgKind))
|
||||||
-> ColumnInfo ('Postgres pgKind)
|
-> ColumnReference ('Postgres pgKind)
|
||||||
-> Value
|
-> Value
|
||||||
-> m [OpExpG ('Postgres pgKind) v]
|
-> m [OpExpG ('Postgres pgKind) v]
|
||||||
parseBoolExpOperations rhsParser rootTable fim columnInfo value = do
|
parseBoolExpOperations rhsParser rootTable fim columnRef value = do
|
||||||
restrictJSONColumn
|
restrictJSONColumn
|
||||||
withPathK (getPGColTxt $ pgiColumn columnInfo) $
|
withPathK (toTxt columnRef) $ parseOperations columnRef value
|
||||||
parseOperations (ColumnReferenceColumn columnInfo) value
|
|
||||||
where
|
where
|
||||||
restrictJSONColumn :: m ()
|
restrictJSONColumn :: m ()
|
||||||
restrictJSONColumn = case columnInfo of
|
restrictJSONColumn = case columnReferenceType columnRef of
|
||||||
ColumnInfo _ _ _ (ColumnScalar PGJSON) _ _ ->
|
ColumnScalar PGJSON ->
|
||||||
throwError (err400 UnexpectedPayload "JSON column can not be part of boolean expression")
|
throwError (err400 UnexpectedPayload "JSON column can not be part of boolean expression")
|
||||||
_ -> pure ()
|
_ -> pure ()
|
||||||
|
|
||||||
parseOperations :: ColumnReference ('Postgres pgKind) -> Value -> m [OpExpG ('Postgres pgKind) v]
|
parseOperations :: ColumnReference ('Postgres pgKind) -> Value -> m [OpExpG ('Postgres pgKind) v]
|
||||||
parseOperations column = \case
|
parseOperations column = \case
|
||||||
|
@ -3,6 +3,7 @@ module Hasura.Backends.Postgres.Translate.BoolExp
|
|||||||
( toSQLBoolExp
|
( toSQLBoolExp
|
||||||
, getBoolExpDeps
|
, getBoolExpDeps
|
||||||
, annBoolExp
|
, annBoolExp
|
||||||
|
, BoolExpRHSParser(..)
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Hasura.Prelude
|
import Hasura.Prelude
|
||||||
@ -18,6 +19,13 @@ import Hasura.RQL.Types
|
|||||||
import Hasura.SQL.Types
|
import Hasura.SQL.Types
|
||||||
|
|
||||||
|
|
||||||
|
-- | Context to parse a RHS value in a boolean expression
|
||||||
|
data BoolExpRHSParser (b :: BackendType) m v
|
||||||
|
= BoolExpRHSParser
|
||||||
|
{ _berpValueParser :: !(ValueParser b m v) -- ^ Parse a JSON value with enforcing a column type
|
||||||
|
, _berpSessionValue :: !v -- ^ Required for a computed field SQL function with session argument
|
||||||
|
}
|
||||||
|
|
||||||
-- This convoluted expression instead of col = val
|
-- This convoluted expression instead of col = val
|
||||||
-- to handle the case of col : null
|
-- to handle the case of col : null
|
||||||
equalsBoolExpBuilder :: SQLExpression ('Postgres pgKind) -> SQLExpression ('Postgres pgKind) -> S.BoolExp
|
equalsBoolExpBuilder :: SQLExpression ('Postgres pgKind) -> SQLExpression ('Postgres pgKind) -> S.BoolExp
|
||||||
@ -36,7 +44,7 @@ notEqualsBoolExpBuilder qualColExp rhsExp =
|
|||||||
|
|
||||||
annBoolExp
|
annBoolExp
|
||||||
:: (QErrM m, TableCoreInfoRM b m, BackendMetadata b)
|
:: (QErrM m, TableCoreInfoRM b m, BackendMetadata b)
|
||||||
=> ValueParser b m v
|
=> BoolExpRHSParser b m v
|
||||||
-> TableName b
|
-> TableName b
|
||||||
-> FieldInfoMap (FieldInfo b)
|
-> FieldInfoMap (FieldInfo b)
|
||||||
-> GBoolExp b ColExp
|
-> GBoolExp b ColExp
|
||||||
@ -49,8 +57,7 @@ annBoolExp rhsParser rootTable fim boolExp =
|
|||||||
BoolExists (GExists refqt whereExp) ->
|
BoolExists (GExists refqt whereExp) ->
|
||||||
withPathK "_exists" $ do
|
withPathK "_exists" $ do
|
||||||
refFields <- withPathK "_table" $ askFieldInfoMapSource refqt
|
refFields <- withPathK "_table" $ askFieldInfoMapSource refqt
|
||||||
annWhereExp <- withPathK "_where" $
|
annWhereExp <- withPathK "_where" $ annBoolExp rhsParser rootTable refFields whereExp
|
||||||
annBoolExp rhsParser rootTable refFields whereExp
|
|
||||||
return $ BoolExists $ GExists refqt annWhereExp
|
return $ BoolExists $ GExists refqt annWhereExp
|
||||||
BoolFld fld -> BoolFld <$> annColExp rhsParser rootTable fim fld
|
BoolFld fld -> BoolFld <$> annColExp rhsParser rootTable fim fld
|
||||||
where
|
where
|
||||||
@ -58,7 +65,7 @@ annBoolExp rhsParser rootTable fim boolExp =
|
|||||||
|
|
||||||
annColExp
|
annColExp
|
||||||
:: (QErrM m, TableCoreInfoRM b m, BackendMetadata b)
|
:: (QErrM m, TableCoreInfoRM b m, BackendMetadata b)
|
||||||
=> ValueParser b m v
|
=> BoolExpRHSParser b m v
|
||||||
-> TableName b
|
-> TableName b
|
||||||
-> FieldInfoMap (FieldInfo b)
|
-> FieldInfoMap (FieldInfo b)
|
||||||
-> ColExp
|
-> ColExp
|
||||||
@ -66,15 +73,33 @@ annColExp
|
|||||||
annColExp rhsParser rootTable colInfoMap (ColExp fieldName colVal) = do
|
annColExp rhsParser rootTable colInfoMap (ColExp fieldName colVal) = do
|
||||||
colInfo <- askFieldInfo colInfoMap fieldName
|
colInfo <- askFieldInfo colInfoMap fieldName
|
||||||
case colInfo of
|
case colInfo of
|
||||||
FIColumn pgi -> AVColumn pgi <$> parseBoolExpOperations rhsParser rootTable colInfoMap pgi colVal
|
FIColumn pgi -> AVColumn pgi <$> parseBoolExpOperations (_berpValueParser rhsParser) rootTable colInfoMap (ColumnReferenceColumn pgi) colVal
|
||||||
|
|
||||||
FIRelationship relInfo -> do
|
FIRelationship relInfo -> do
|
||||||
relBoolExp <- decodeValue colVal
|
relBoolExp <- decodeValue colVal
|
||||||
relFieldInfoMap <- askFieldInfoMapSource $ riRTable relInfo
|
relFieldInfoMap <- askFieldInfoMapSource $ riRTable relInfo
|
||||||
annRelBoolExp <- annBoolExp rhsParser rootTable relFieldInfoMap $
|
annRelBoolExp <- annBoolExp rhsParser rootTable relFieldInfoMap $ unBoolExp relBoolExp
|
||||||
unBoolExp relBoolExp
|
|
||||||
return $ AVRelationship relInfo annRelBoolExp
|
return $ AVRelationship relInfo annRelBoolExp
|
||||||
FIComputedField _ ->
|
|
||||||
throw400 UnexpectedPayload "Computed columns can not be part of the where clause"
|
FIComputedField ComputedFieldInfo{..} -> do
|
||||||
|
let ComputedFieldFunction{..} = _cfiFunction
|
||||||
|
case toList _cffInputArgs of
|
||||||
|
[] -> do
|
||||||
|
let hasuraSession = _berpSessionValue rhsParser
|
||||||
|
sessionArgPresence = mkSessionArgumentPresence hasuraSession _cffSessionArgument _cffTableArgument
|
||||||
|
AVComputedField . AnnComputedFieldBoolExp _cfiXComputedFieldInfo _cfiName _cffName sessionArgPresence
|
||||||
|
<$> case _cfiReturnType of
|
||||||
|
CFRScalar scalarType -> CFBEScalar
|
||||||
|
<$> parseBoolExpOperations (_berpValueParser rhsParser) rootTable colInfoMap (ColumnReferenceComputedField _cfiName scalarType) colVal
|
||||||
|
CFRSetofTable table -> do
|
||||||
|
tableBoolExp <- decodeValue colVal
|
||||||
|
tableFieldInfoMap <- askFieldInfoMapSource table
|
||||||
|
annTableBoolExp <- annBoolExp rhsParser table tableFieldInfoMap $ unBoolExp tableBoolExp
|
||||||
|
pure $ CFBETable table annTableBoolExp
|
||||||
|
|
||||||
|
_ -> throw400 UnexpectedPayload
|
||||||
|
"Computed columns with input arguments can not be part of the where clause"
|
||||||
|
|
||||||
-- TODO Rakesh (from master)
|
-- TODO Rakesh (from master)
|
||||||
FIRemoteRelationship{} ->
|
FIRemoteRelationship{} ->
|
||||||
throw400 UnexpectedPayload "remote field unsupported"
|
throw400 UnexpectedPayload "remote field unsupported"
|
||||||
|
@ -86,13 +86,8 @@ boolExp sourceName tableInfo selectPermissions = memoizeOn 'boolExp (sourceName,
|
|||||||
-- For a computed field to qualify in boolean expression it shouldn't have any input arguments
|
-- For a computed field to qualify in boolean expression it shouldn't have any input arguments
|
||||||
case toList _cffInputArgs of
|
case toList _cffInputArgs of
|
||||||
[] -> do
|
[] -> do
|
||||||
let sessionArgPresence = case _cffSessionArgument of
|
let sessionArgPresence =
|
||||||
Nothing -> SAPNotPresent
|
mkSessionArgumentPresence P.UVSession _cffSessionArgument _cffTableArgument
|
||||||
Just _ -> case _cffTableArgument of
|
|
||||||
FTAFirst -> SAPSecond P.UVSession -- If table argument is first, then session argument will be second
|
|
||||||
FTANamed _ 0 -> SAPSecond P.UVSession -- Index 0 => table argument is first
|
|
||||||
FTANamed{} -> SAPFirst P.UVSession -- If table argument is second, then session argument will be firest
|
|
||||||
|
|
||||||
fmap (AVComputedField . AnnComputedFieldBoolExp _cfiXComputedFieldInfo _cfiName _cffName sessionArgPresence)
|
fmap (AVComputedField . AnnComputedFieldBoolExp _cfiXComputedFieldInfo _cfiName _cffName sessionArgPresence)
|
||||||
<$> case _cfiReturnType of
|
<$> case _cfiReturnType of
|
||||||
CFRScalar scalarType -> lift $ fmap CFBEScalar <$> comparisonExps @b (ColumnScalar scalarType)
|
CFRScalar scalarType -> lift $ fmap CFBEScalar <$> comparisonExps @b (ColumnScalar scalarType)
|
||||||
|
@ -47,6 +47,7 @@ textToName textName = G.mkName textName `onNothing` throw400 ValidationFailed
|
|||||||
|
|
||||||
partialSQLExpToUnpreparedValue :: PartialSQLExp b -> P.UnpreparedValue b
|
partialSQLExpToUnpreparedValue :: PartialSQLExp b -> P.UnpreparedValue b
|
||||||
partialSQLExpToUnpreparedValue (PSESessVar pftype var) = P.UVSessionVar pftype var
|
partialSQLExpToUnpreparedValue (PSESessVar pftype var) = P.UVSessionVar pftype var
|
||||||
|
partialSQLExpToUnpreparedValue PSESession = P.UVSession
|
||||||
partialSQLExpToUnpreparedValue (PSESQLExp sqlExp) = P.UVLiteral sqlExp
|
partialSQLExpToUnpreparedValue (PSESQLExp sqlExp) = P.UVLiteral sqlExp
|
||||||
|
|
||||||
mapField
|
mapField
|
||||||
|
@ -79,7 +79,8 @@ procBoolExp
|
|||||||
-> BoolExp b
|
-> BoolExp b
|
||||||
-> m (AnnBoolExpPartialSQL b, [SchemaDependency])
|
-> m (AnnBoolExpPartialSQL b, [SchemaDependency])
|
||||||
procBoolExp source tn fieldInfoMap be = do
|
procBoolExp source tn fieldInfoMap be = do
|
||||||
abe <- annBoolExp parseCollectableType tn fieldInfoMap $ unBoolExp be
|
let rhsParser = BoolExpRHSParser parseCollectableType PSESession
|
||||||
|
abe <- annBoolExp rhsParser tn fieldInfoMap $ unBoolExp be
|
||||||
let deps = getBoolExpDeps source tn abe
|
let deps = getBoolExpDeps source tn abe
|
||||||
return (abe, deps)
|
return (abe, deps)
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ mkSQLCount (CountQueryP1 tn (permFltr, mWc) mDistCols) =
|
|||||||
-- SELECT count(*) FROM (SELECT * FROM .. WHERE ..) r;
|
-- SELECT count(*) FROM (SELECT * FROM .. WHERE ..) r;
|
||||||
validateCountQWith
|
validateCountQWith
|
||||||
:: (UserInfoM m, QErrM m, TableInfoRM ('Postgres 'Vanilla) m)
|
:: (UserInfoM m, QErrM m, TableInfoRM ('Postgres 'Vanilla) m)
|
||||||
=> SessVarBldr ('Postgres 'Vanilla) m
|
=> SessionVariableBuilder ('Postgres 'Vanilla) m
|
||||||
-> (ColumnType ('Postgres 'Vanilla) -> Value -> m S.SQLExp)
|
-> (ColumnType ('Postgres 'Vanilla) -> Value -> m S.SQLExp)
|
||||||
-> CountQuery
|
-> CountQuery
|
||||||
-> m CountQueryP1
|
-> m CountQueryP1
|
||||||
|
@ -34,7 +34,7 @@ import Hasura.Session
|
|||||||
|
|
||||||
validateDeleteQWith
|
validateDeleteQWith
|
||||||
:: (UserInfoM m, QErrM m, TableInfoRM ('Postgres 'Vanilla) m)
|
:: (UserInfoM m, QErrM m, TableInfoRM ('Postgres 'Vanilla) m)
|
||||||
=> SessVarBldr ('Postgres 'Vanilla) m
|
=> SessionVariableBuilder ('Postgres 'Vanilla) m
|
||||||
-> (ColumnType ('Postgres 'Vanilla) -> Value -> m S.SQLExp)
|
-> (ColumnType ('Postgres 'Vanilla) -> Value -> m S.SQLExp)
|
||||||
-> DeleteQuery
|
-> DeleteQuery
|
||||||
-> m (AnnDel ('Postgres 'Vanilla))
|
-> m (AnnDel ('Postgres 'Vanilla))
|
||||||
|
@ -68,7 +68,7 @@ validateInpCols inpCols updColsPerm = forM_ inpCols $ \inpCol ->
|
|||||||
|
|
||||||
buildConflictClause
|
buildConflictClause
|
||||||
:: (UserInfoM m, QErrM m)
|
:: (UserInfoM m, QErrM m)
|
||||||
=> SessVarBldr ('Postgres 'Vanilla) m
|
=> SessionVariableBuilder ('Postgres 'Vanilla) m
|
||||||
-> TableInfo ('Postgres 'Vanilla)
|
-> TableInfo ('Postgres 'Vanilla)
|
||||||
-> [PGCol]
|
-> [PGCol]
|
||||||
-> OnConflict
|
-> OnConflict
|
||||||
@ -129,7 +129,7 @@ buildConflictClause sessVarBldr tableInfo inpCols (OnConflict mTCol mTCons act)
|
|||||||
convInsertQuery
|
convInsertQuery
|
||||||
:: (UserInfoM m, QErrM m, TableInfoRM ('Postgres 'Vanilla) m)
|
:: (UserInfoM m, QErrM m, TableInfoRM ('Postgres 'Vanilla) m)
|
||||||
=> (Value -> m [InsObj ('Postgres 'Vanilla)])
|
=> (Value -> m [InsObj ('Postgres 'Vanilla)])
|
||||||
-> SessVarBldr ('Postgres 'Vanilla) m
|
-> SessionVariableBuilder ('Postgres 'Vanilla) m
|
||||||
-> (ColumnType ('Postgres 'Vanilla) -> Value -> m S.SQLExp)
|
-> (ColumnType ('Postgres 'Vanilla) -> Value -> m S.SQLExp)
|
||||||
-> InsertQuery
|
-> InsertQuery
|
||||||
-> m (InsertQueryP1 ('Postgres 'Vanilla))
|
-> m (InsertQueryP1 ('Postgres 'Vanilla))
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
module Hasura.RQL.DML.Internal where
|
module Hasura.RQL.DML.Internal where
|
||||||
-- ( mkAdminRolePermInfo
|
|
||||||
-- , SessVarBldr
|
|
||||||
-- ) where
|
|
||||||
|
|
||||||
import Hasura.Prelude
|
import Hasura.Prelude
|
||||||
|
|
||||||
@ -207,7 +204,11 @@ fetchRelTabInfo refTabName =
|
|||||||
modifyErrAndSet500 ("foreign " <> ) $
|
modifyErrAndSet500 ("foreign " <> ) $
|
||||||
askTabInfoSource refTabName
|
askTabInfoSource refTabName
|
||||||
|
|
||||||
type SessVarBldr b m = SessionVarType b -> SessionVariable -> m (SQLExpression b)
|
data SessionVariableBuilder b m
|
||||||
|
= SessionVariableBuilder
|
||||||
|
{ _svbCurrentSession :: !(SQLExpression b)
|
||||||
|
, _svbVariableParser :: !(SessionVarType b -> SessionVariable -> m (SQLExpression b))
|
||||||
|
}
|
||||||
|
|
||||||
fetchRelDet
|
fetchRelDet
|
||||||
:: (UserInfoM m, QErrM m, TableInfoRM b m, Backend b)
|
:: (UserInfoM m, QErrM m, TableInfoRM b m, Backend b)
|
||||||
@ -234,7 +235,7 @@ fetchRelDet relName refTabName = do
|
|||||||
checkOnColExp
|
checkOnColExp
|
||||||
:: (UserInfoM m, QErrM m, TableInfoRM b m, Backend b)
|
:: (UserInfoM m, QErrM m, TableInfoRM b m, Backend b)
|
||||||
=> SelPermInfo b
|
=> SelPermInfo b
|
||||||
-> SessVarBldr b m
|
-> SessionVariableBuilder b m
|
||||||
-> AnnBoolExpFldSQL b
|
-> AnnBoolExpFldSQL b
|
||||||
-> m (AnnBoolExpFldSQL b)
|
-> m (AnnBoolExpFldSQL b)
|
||||||
checkOnColExp spi sessVarBldr annFld = case annFld of
|
checkOnColExp spi sessVarBldr annFld = case annFld of
|
||||||
@ -267,7 +268,7 @@ checkOnColExp spi sessVarBldr annFld = case annFld of
|
|||||||
|
|
||||||
convAnnBoolExpPartialSQL
|
convAnnBoolExpPartialSQL
|
||||||
:: (Applicative f, Backend backend)
|
:: (Applicative f, Backend backend)
|
||||||
=> SessVarBldr backend f
|
=> SessionVariableBuilder backend f
|
||||||
-> AnnBoolExpPartialSQL backend
|
-> AnnBoolExpPartialSQL backend
|
||||||
-> f (AnnBoolExpSQL backend)
|
-> f (AnnBoolExpSQL backend)
|
||||||
convAnnBoolExpPartialSQL f =
|
convAnnBoolExpPartialSQL f =
|
||||||
@ -275,7 +276,7 @@ convAnnBoolExpPartialSQL f =
|
|||||||
|
|
||||||
convAnnColumnCaseBoolExpPartialSQL
|
convAnnColumnCaseBoolExpPartialSQL
|
||||||
:: (Applicative f, Backend backend)
|
:: (Applicative f, Backend backend)
|
||||||
=> SessVarBldr backend f
|
=> SessionVariableBuilder backend f
|
||||||
-> AnnColumnCaseBoolExpPartialSQL backend
|
-> AnnColumnCaseBoolExpPartialSQL backend
|
||||||
-> f (AnnColumnCaseBoolExp backend (SQLExpression backend))
|
-> f (AnnColumnCaseBoolExp backend (SQLExpression backend))
|
||||||
convAnnColumnCaseBoolExpPartialSQL f =
|
convAnnColumnCaseBoolExpPartialSQL f =
|
||||||
@ -283,17 +284,18 @@ convAnnColumnCaseBoolExpPartialSQL f =
|
|||||||
|
|
||||||
convPartialSQLExp
|
convPartialSQLExp
|
||||||
:: (Applicative f)
|
:: (Applicative f)
|
||||||
=> SessVarBldr backend f
|
=> SessionVariableBuilder backend f
|
||||||
-> PartialSQLExp backend
|
-> PartialSQLExp backend
|
||||||
-> f (SQLExpression backend)
|
-> f (SQLExpression backend)
|
||||||
convPartialSQLExp f = \case
|
convPartialSQLExp sessVarBldr = \case
|
||||||
PSESQLExp sqlExp -> pure sqlExp
|
PSESQLExp sqlExp -> pure sqlExp
|
||||||
PSESessVar colTy sessionVariable -> f colTy sessionVariable
|
PSESession -> pure $ _svbCurrentSession sessVarBldr
|
||||||
|
PSESessVar colTy sessionVariable -> (_svbVariableParser sessVarBldr) colTy sessionVariable
|
||||||
|
|
||||||
sessVarFromCurrentSetting
|
sessVarFromCurrentSetting
|
||||||
:: (Applicative f) => CollectableType PGScalarType -> SessionVariable -> f S.SQLExp
|
:: (Applicative f) => SessionVariableBuilder ('Postgres pgKind) f
|
||||||
sessVarFromCurrentSetting pgType sessVar =
|
sessVarFromCurrentSetting =
|
||||||
pure $ sessVarFromCurrentSetting' pgType sessVar
|
SessionVariableBuilder currentSession $ \ty var -> pure $ sessVarFromCurrentSetting' ty var
|
||||||
|
|
||||||
sessVarFromCurrentSetting' :: CollectableType PGScalarType -> SessionVariable -> S.SQLExp
|
sessVarFromCurrentSetting' :: CollectableType PGScalarType -> SessionVariable -> S.SQLExp
|
||||||
sessVarFromCurrentSetting' ty sessVar =
|
sessVarFromCurrentSetting' ty sessVar =
|
||||||
@ -329,7 +331,7 @@ currentSession = S.SEUnsafe "current_setting('hasura.user')::json"
|
|||||||
checkSelPerm
|
checkSelPerm
|
||||||
:: (UserInfoM m, QErrM m, TableInfoRM b m, Backend b)
|
:: (UserInfoM m, QErrM m, TableInfoRM b m, Backend b)
|
||||||
=> SelPermInfo b
|
=> SelPermInfo b
|
||||||
-> SessVarBldr b m
|
-> SessionVariableBuilder b m
|
||||||
-> AnnBoolExpSQL b
|
-> AnnBoolExpSQL b
|
||||||
-> m (AnnBoolExpSQL b)
|
-> m (AnnBoolExpSQL b)
|
||||||
checkSelPerm spi sessVarBldr =
|
checkSelPerm spi sessVarBldr =
|
||||||
@ -340,12 +342,13 @@ convBoolExp
|
|||||||
=> FieldInfoMap (FieldInfo b)
|
=> FieldInfoMap (FieldInfo b)
|
||||||
-> SelPermInfo b
|
-> SelPermInfo b
|
||||||
-> BoolExp b
|
-> BoolExp b
|
||||||
-> SessVarBldr b m
|
-> SessionVariableBuilder b m
|
||||||
-> TableName b
|
-> TableName b
|
||||||
-> ValueParser b m (SQLExpression b)
|
-> ValueParser b m (SQLExpression b)
|
||||||
-> m (AnnBoolExpSQL b)
|
-> m (AnnBoolExpSQL b)
|
||||||
convBoolExp cim spi be sessVarBldr rootTable rhsParser = do
|
convBoolExp cim spi be sessVarBldr rootTable rhsParser = do
|
||||||
abe <- annBoolExp rhsParser rootTable cim $ unBoolExp be
|
let boolExpRHSParser = BoolExpRHSParser rhsParser $ _svbCurrentSession sessVarBldr
|
||||||
|
abe <- annBoolExp boolExpRHSParser rootTable cim $ unBoolExp be
|
||||||
checkSelPerm spi sessVarBldr abe
|
checkSelPerm spi sessVarBldr abe
|
||||||
|
|
||||||
dmlTxErrorHandler :: Q.PGTxErr -> QErr
|
dmlTxErrorHandler :: Q.PGTxErr -> QErr
|
||||||
|
@ -118,7 +118,7 @@ resolveStar fim selPermInfo (SelectG selCols mWh mOb mLt mOf) = do
|
|||||||
|
|
||||||
convOrderByElem
|
convOrderByElem
|
||||||
:: (UserInfoM m, QErrM m, TableInfoRM ('Postgres 'Vanilla) m)
|
:: (UserInfoM m, QErrM m, TableInfoRM ('Postgres 'Vanilla) m)
|
||||||
=> SessVarBldr ('Postgres 'Vanilla) m
|
=> SessionVariableBuilder ('Postgres 'Vanilla) m
|
||||||
-> (FieldInfoMap (FieldInfo ('Postgres 'Vanilla)), SelPermInfo ('Postgres 'Vanilla))
|
-> (FieldInfoMap (FieldInfo ('Postgres 'Vanilla)), SelPermInfo ('Postgres 'Vanilla))
|
||||||
-> OrderByCol
|
-> OrderByCol
|
||||||
-> m (AnnotatedOrderByElement ('Postgres 'Vanilla) S.SQLExp)
|
-> m (AnnotatedOrderByElement ('Postgres 'Vanilla) S.SQLExp)
|
||||||
@ -179,7 +179,7 @@ convSelectQ
|
|||||||
-> FieldInfoMap (FieldInfo ('Postgres 'Vanilla)) -- Table information of current table
|
-> FieldInfoMap (FieldInfo ('Postgres 'Vanilla)) -- Table information of current table
|
||||||
-> SelPermInfo ('Postgres 'Vanilla) -- Additional select permission info
|
-> SelPermInfo ('Postgres 'Vanilla) -- Additional select permission info
|
||||||
-> SelectQExt ('Postgres 'Vanilla) -- Given Select Query
|
-> SelectQExt ('Postgres 'Vanilla) -- Given Select Query
|
||||||
-> SessVarBldr ('Postgres 'Vanilla) m
|
-> SessionVariableBuilder ('Postgres 'Vanilla) m
|
||||||
-> ValueParser ('Postgres 'Vanilla) m S.SQLExp
|
-> ValueParser ('Postgres 'Vanilla) m S.SQLExp
|
||||||
-> m (AnnSimpleSelect ('Postgres 'Vanilla))
|
-> m (AnnSimpleSelect ('Postgres 'Vanilla))
|
||||||
convSelectQ table fieldInfoMap selPermInfo selQ sessVarBldr prepValBldr = do
|
convSelectQ table fieldInfoMap selPermInfo selQ sessVarBldr prepValBldr = do
|
||||||
@ -250,7 +250,7 @@ convExtRel
|
|||||||
-> RelName
|
-> RelName
|
||||||
-> Maybe RelName
|
-> Maybe RelName
|
||||||
-> SelectQExt ('Postgres 'Vanilla)
|
-> SelectQExt ('Postgres 'Vanilla)
|
||||||
-> SessVarBldr ('Postgres 'Vanilla) m
|
-> SessionVariableBuilder ('Postgres 'Vanilla) m
|
||||||
-> ValueParser ('Postgres 'Vanilla) m S.SQLExp
|
-> ValueParser ('Postgres 'Vanilla) m S.SQLExp
|
||||||
-> m (Either (ObjectRelationSelect ('Postgres 'Vanilla)) (ArraySelect ('Postgres 'Vanilla)))
|
-> m (Either (ObjectRelationSelect ('Postgres 'Vanilla)) (ArraySelect ('Postgres 'Vanilla)))
|
||||||
convExtRel fieldInfoMap relName mAlias selQ sessVarBldr prepValBldr = do
|
convExtRel fieldInfoMap relName mAlias selQ sessVarBldr prepValBldr = do
|
||||||
@ -288,7 +288,7 @@ convSelectQuery
|
|||||||
, TableInfoRM ('Postgres 'Vanilla) m
|
, TableInfoRM ('Postgres 'Vanilla) m
|
||||||
, HasServerConfigCtx m
|
, HasServerConfigCtx m
|
||||||
)
|
)
|
||||||
=> SessVarBldr ('Postgres 'Vanilla) m
|
=> SessionVariableBuilder ('Postgres 'Vanilla) m
|
||||||
-> ValueParser ('Postgres 'Vanilla) m S.SQLExp
|
-> ValueParser ('Postgres 'Vanilla) m S.SQLExp
|
||||||
-> SelectQuery
|
-> SelectQuery
|
||||||
-> m (AnnSimpleSelect ('Postgres 'Vanilla))
|
-> m (AnnSimpleSelect ('Postgres 'Vanilla))
|
||||||
|
@ -95,7 +95,7 @@ convOp fieldInfoMap preSetCols updPerm objs conv =
|
|||||||
|
|
||||||
validateUpdateQueryWith
|
validateUpdateQueryWith
|
||||||
:: (UserInfoM m, QErrM m, TableInfoRM ('Postgres 'Vanilla) m)
|
:: (UserInfoM m, QErrM m, TableInfoRM ('Postgres 'Vanilla) m)
|
||||||
=> SessVarBldr ('Postgres 'Vanilla) m
|
=> SessionVariableBuilder ('Postgres 'Vanilla) m
|
||||||
-> ValueParser ('Postgres 'Vanilla) m S.SQLExp
|
-> ValueParser ('Postgres 'Vanilla) m S.SQLExp
|
||||||
-> UpdateQuery
|
-> UpdateQuery
|
||||||
-> m (AnnUpd ('Postgres 'Vanilla))
|
-> m (AnnUpd ('Postgres 'Vanilla))
|
||||||
|
@ -20,6 +20,7 @@ module Hasura.RQL.IR.BoolExp
|
|||||||
, STIntersectsGeomminNband(..)
|
, STIntersectsGeomminNband(..)
|
||||||
|
|
||||||
, SessionArgumentPresence(..)
|
, SessionArgumentPresence(..)
|
||||||
|
, mkSessionArgumentPresence
|
||||||
, ComputedFieldBoolExp(..)
|
, ComputedFieldBoolExp(..)
|
||||||
, AnnComputedFieldBoolExp(..)
|
, AnnComputedFieldBoolExp(..)
|
||||||
, AnnBoolExpFld(..)
|
, AnnBoolExpFld(..)
|
||||||
@ -186,6 +187,7 @@ makePrisms ''GBoolExp
|
|||||||
-- inline the session variables.
|
-- inline the session variables.
|
||||||
data PartialSQLExp (b :: BackendType)
|
data PartialSQLExp (b :: BackendType)
|
||||||
= PSESessVar !(SessionVarType b) !SessionVariable
|
= PSESessVar !(SessionVarType b) !SessionVariable
|
||||||
|
| PSESession
|
||||||
| PSESQLExp !(SQLExpression b)
|
| PSESQLExp !(SQLExpression b)
|
||||||
deriving (Generic)
|
deriving (Generic)
|
||||||
deriving instance (Backend b) => Eq (PartialSQLExp b)
|
deriving instance (Backend b) => Eq (PartialSQLExp b)
|
||||||
@ -196,11 +198,13 @@ instance (Backend b, Hashable (BooleanOperators b (PartialSQLExp b))) => Cachea
|
|||||||
instance Backend b => ToJSON (PartialSQLExp b) where
|
instance Backend b => ToJSON (PartialSQLExp b) where
|
||||||
toJSON = \case
|
toJSON = \case
|
||||||
PSESessVar colTy sessVar -> toJSON (colTy, sessVar)
|
PSESessVar colTy sessVar -> toJSON (colTy, sessVar)
|
||||||
|
PSESession -> String "hasura_session"
|
||||||
PSESQLExp e -> toJSON e
|
PSESQLExp e -> toJSON e
|
||||||
|
|
||||||
isStaticValue :: PartialSQLExp backend -> Bool
|
isStaticValue :: PartialSQLExp backend -> Bool
|
||||||
isStaticValue = \case
|
isStaticValue = \case
|
||||||
PSESessVar _ _ -> False
|
PSESessVar _ _ -> False
|
||||||
|
PSESession -> False
|
||||||
PSESQLExp _ -> True
|
PSESQLExp _ -> True
|
||||||
|
|
||||||
hasStaticExp :: Backend b => OpExpG b (PartialSQLExp b) -> Bool
|
hasStaticExp :: Backend b => OpExpG b (PartialSQLExp b) -> Bool
|
||||||
@ -297,8 +301,8 @@ opExpDepCol = \case
|
|||||||
_ -> Nothing
|
_ -> Nothing
|
||||||
|
|
||||||
-- | The presence of session argument in the SQL function of a computed field.
|
-- | The presence of session argument in the SQL function of a computed field.
|
||||||
-- Since we only support maximum of 2 arguments in boolean expression, the position
|
-- Since we only support computed fields with SQL functions having maximum of 2 arguments in boolean expression,
|
||||||
-- (if present) is either first or second. The other mandatory argument is table row input.
|
-- the position (if present) is either first or second. The other mandatory argument is table row input.
|
||||||
data SessionArgumentPresence a
|
data SessionArgumentPresence a
|
||||||
= SAPNotPresent
|
= SAPNotPresent
|
||||||
| SAPFirst a
|
| SAPFirst a
|
||||||
@ -308,6 +312,18 @@ instance (NFData a) => NFData (SessionArgumentPresence a)
|
|||||||
instance (Cacheable a) => Cacheable (SessionArgumentPresence a)
|
instance (Cacheable a) => Cacheable (SessionArgumentPresence a)
|
||||||
instance (Hashable a) => Hashable (SessionArgumentPresence a)
|
instance (Hashable a) => Hashable (SessionArgumentPresence a)
|
||||||
|
|
||||||
|
-- | Determine the position of session argument
|
||||||
|
mkSessionArgumentPresence :: forall v a. v -> Maybe a -> FunctionTableArgument -> SessionArgumentPresence v
|
||||||
|
mkSessionArgumentPresence sessionValue = \case
|
||||||
|
Nothing -> const $ SAPNotPresent
|
||||||
|
Just _ -> \case
|
||||||
|
-- If table argument is first, then session argument will be second
|
||||||
|
FTAFirst -> SAPSecond sessionValue
|
||||||
|
-- Argument index 0 implies it is first
|
||||||
|
FTANamed _ 0 -> SAPSecond sessionValue
|
||||||
|
-- If table argument is second, then session argument will be first
|
||||||
|
FTANamed{} -> SAPFirst sessionValue
|
||||||
|
|
||||||
-- | This type is used to represent the kinds of boolean expression used for compouted fields
|
-- | This type is used to represent the kinds of boolean expression used for compouted fields
|
||||||
-- based on the return type of the SQL function
|
-- based on the return type of the SQL function
|
||||||
data ComputedFieldBoolExp (b :: BackendType) a
|
data ComputedFieldBoolExp (b :: BackendType) a
|
||||||
@ -336,7 +352,7 @@ instance (Backend b, Hashable (BooleanOperators b a), Hashable a) => Hashable
|
|||||||
data AnnComputedFieldBoolExp (b :: BackendType) a
|
data AnnComputedFieldBoolExp (b :: BackendType) a
|
||||||
= AnnComputedFieldBoolExp
|
= AnnComputedFieldBoolExp
|
||||||
{ _acfbXFieldInfo :: !(XComputedField b)
|
{ _acfbXFieldInfo :: !(XComputedField b)
|
||||||
, _acfbName :: !(ComputedFieldName)
|
, _acfbName :: !ComputedFieldName
|
||||||
, _acfbFunction :: !(FunctionName b)
|
, _acfbFunction :: !(FunctionName b)
|
||||||
, _acfbSessionArgumentPresence :: !(SessionArgumentPresence a)
|
, _acfbSessionArgumentPresence :: !(SessionArgumentPresence a)
|
||||||
, _acfbBoolExp :: !(ComputedFieldBoolExp b a)
|
, _acfbBoolExp :: !(ComputedFieldBoolExp b a)
|
||||||
|
@ -25,12 +25,15 @@ module Hasura.RQL.Types.Column
|
|||||||
|
|
||||||
, fromCol
|
, fromCol
|
||||||
, ColumnValues
|
, ColumnValues
|
||||||
|
|
||||||
|
, ColumnReference(..)
|
||||||
|
, columnReferenceType
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Hasura.Prelude
|
import Hasura.Prelude
|
||||||
|
|
||||||
import qualified Data.HashMap.Strict as M
|
import qualified Data.HashMap.Strict as M
|
||||||
import qualified Language.GraphQL.Draft.Syntax as G
|
import qualified Language.GraphQL.Draft.Syntax as G
|
||||||
|
|
||||||
import Control.Lens.TH
|
import Control.Lens.TH
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
@ -38,9 +41,10 @@ import Data.Aeson.TH
|
|||||||
import Data.Text.Extended
|
import Data.Text.Extended
|
||||||
|
|
||||||
import Hasura.Base.Error
|
import Hasura.Base.Error
|
||||||
import Hasura.Incremental (Cacheable)
|
import Hasura.Incremental (Cacheable)
|
||||||
import Hasura.RQL.Types.Backend
|
import Hasura.RQL.Types.Backend
|
||||||
import Hasura.RQL.Types.Common
|
import Hasura.RQL.Types.Common
|
||||||
|
import Hasura.RQL.Types.ComputedField
|
||||||
import Hasura.SQL.Backend
|
import Hasura.SQL.Backend
|
||||||
import Hasura.SQL.Types
|
import Hasura.SQL.Types
|
||||||
|
|
||||||
@ -201,3 +205,23 @@ fromCol :: Backend b => Column b -> FieldName
|
|||||||
fromCol = FieldName . toTxt
|
fromCol = FieldName . toTxt
|
||||||
|
|
||||||
type ColumnValues b a = HashMap (Column b) a
|
type ColumnValues b a = HashMap (Column b) a
|
||||||
|
|
||||||
|
-- | Represents a reference to a source column, possibly casted an arbitrary
|
||||||
|
-- number of times. Used within 'parseBoolExpOperations' for bookkeeping.
|
||||||
|
data ColumnReference (b :: BackendType)
|
||||||
|
= ColumnReferenceColumn !(ColumnInfo b)
|
||||||
|
| ColumnReferenceComputedField !ComputedFieldName !(ScalarType b)
|
||||||
|
| ColumnReferenceCast !(ColumnReference b) !(ColumnType b)
|
||||||
|
|
||||||
|
columnReferenceType :: ColumnReference backend -> ColumnType backend
|
||||||
|
columnReferenceType = \case
|
||||||
|
ColumnReferenceColumn column -> pgiType column
|
||||||
|
ColumnReferenceComputedField _ scalarType -> ColumnScalar scalarType
|
||||||
|
ColumnReferenceCast _ targetType -> targetType
|
||||||
|
|
||||||
|
instance Backend b => ToTxt (ColumnReference b) where
|
||||||
|
toTxt = \case
|
||||||
|
ColumnReferenceColumn column -> toTxt $ pgiColumn column
|
||||||
|
ColumnReferenceComputedField name _ -> toTxt name
|
||||||
|
ColumnReferenceCast reference targetType ->
|
||||||
|
toTxt reference <> "::" <> toTxt targetType
|
||||||
|
@ -82,7 +82,7 @@ class (Backend b) => BackendMetadata (b :: BackendType) where
|
|||||||
=> ValueParser b m v
|
=> ValueParser b m v
|
||||||
-> TableName b
|
-> TableName b
|
||||||
-> FieldInfoMap (FieldInfo b)
|
-> FieldInfoMap (FieldInfo b)
|
||||||
-> ColumnInfo b
|
-> ColumnReference b
|
||||||
-> Value
|
-> Value
|
||||||
-> m [OpExpG b v]
|
-> m [OpExpG b v]
|
||||||
|
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
description: A reader fetch authors with atleast one published article
|
||||||
|
url: /v1/graphql
|
||||||
|
status: 200
|
||||||
|
headers:
|
||||||
|
X-Hasura-Role: reader
|
||||||
|
query:
|
||||||
|
query: |
|
||||||
|
query {
|
||||||
|
author{
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response:
|
||||||
|
data:
|
||||||
|
author:
|
||||||
|
- name: Author 1
|
||||||
|
- name: Author 2
|
@ -26,6 +26,11 @@ args:
|
|||||||
published_on TIMESTAMP
|
published_on TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE FUNCTION get_articles(author_row author)
|
||||||
|
RETURNS SETOF article as $$
|
||||||
|
SELECT * FROM article WHERE author_id = author_row.id
|
||||||
|
$$ LANGUAGE SQL STABLE;
|
||||||
|
|
||||||
INSERT INTO article (title, content, author_id, is_published)
|
INSERT INTO article (title, content, author_id, is_published)
|
||||||
VALUES
|
VALUES
|
||||||
('Article 1', 'Sample article content 1', 1, false),
|
('Article 1', 'Sample article content 1', 1, false),
|
||||||
@ -126,6 +131,7 @@ args:
|
|||||||
SELECT * FROM gpa WHERE
|
SELECT * FROM gpa WHERE
|
||||||
gpa_score >= pass_gpa
|
gpa_score >= pass_gpa
|
||||||
$$ language SQL STABLE;
|
$$ language SQL STABLE;
|
||||||
|
|
||||||
CREATE TABLE auction (
|
CREATE TABLE auction (
|
||||||
id serial primary key,
|
id serial primary key,
|
||||||
price integer not null DEFAULT 250,
|
price integer not null DEFAULT 250,
|
||||||
@ -138,6 +144,28 @@ args:
|
|||||||
(100), (120), (300), (260)
|
(100), (120), (300), (260)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
CREATE TABLE student_marks (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
name TEXT UNIQUE NOT NULL,
|
||||||
|
physics INTEGER,
|
||||||
|
chemistry INTEGER,
|
||||||
|
mathematics INTEGER
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO student_marks (name, physics, chemistry, mathematics) VALUES
|
||||||
|
('clarke', 84, 67, 70), ('george', 56, 79, 70),
|
||||||
|
('blake', 66, 89, 78), ('leonel', 90, 93, 85);
|
||||||
|
|
||||||
|
CREATE FUNCTION student_total_marks (student_row student_marks)
|
||||||
|
RETURNS INTEGER AS $$
|
||||||
|
SELECT student_row.physics + student_row.chemistry + student_row.mathematics
|
||||||
|
$$ LANGUAGE SQL STABLE;
|
||||||
|
|
||||||
|
CREATE FUNCTION student_total_marks_offset (hasura_session json, student_row student_marks)
|
||||||
|
RETURNS INTEGER AS $$
|
||||||
|
SELECT student_row.physics + student_row.chemistry + student_row.mathematics - (hasura_session ->> 'x-hasura-offset-marks')::integer
|
||||||
|
$$ LANGUAGE SQL STABLE;
|
||||||
|
|
||||||
- type: track_table
|
- type: track_table
|
||||||
args:
|
args:
|
||||||
schema: public
|
schema: public
|
||||||
@ -149,6 +177,16 @@ args:
|
|||||||
schema: public
|
schema: public
|
||||||
name: article
|
name: article
|
||||||
|
|
||||||
|
# Add computed field to author table
|
||||||
|
- type: add_computed_field
|
||||||
|
args:
|
||||||
|
table: author
|
||||||
|
name: get_articles
|
||||||
|
definition:
|
||||||
|
function: get_articles
|
||||||
|
table_argument: author_row
|
||||||
|
|
||||||
|
|
||||||
#Object relationship
|
#Object relationship
|
||||||
- type: create_object_relationship
|
- type: create_object_relationship
|
||||||
args:
|
args:
|
||||||
@ -224,6 +262,18 @@ args:
|
|||||||
_eq: true
|
_eq: true
|
||||||
limit: 10
|
limit: 10
|
||||||
|
|
||||||
|
#Author select permission for reader
|
||||||
|
- type: create_select_permission
|
||||||
|
args:
|
||||||
|
table: author
|
||||||
|
role: reader
|
||||||
|
permission:
|
||||||
|
columns:
|
||||||
|
- name
|
||||||
|
filter:
|
||||||
|
get_articles:
|
||||||
|
is_published: true
|
||||||
|
|
||||||
#Author select permission for anonymous users
|
#Author select permission for anonymous users
|
||||||
#Only authors with atleast one article will be shown
|
#Only authors with atleast one article will be shown
|
||||||
- type: create_select_permission
|
- type: create_select_permission
|
||||||
@ -495,3 +545,50 @@ args:
|
|||||||
permission:
|
permission:
|
||||||
columns: [name]
|
columns: [name]
|
||||||
filter: {}
|
filter: {}
|
||||||
|
|
||||||
|
# Track student_marks table
|
||||||
|
- type: track_table
|
||||||
|
args:
|
||||||
|
table: student_marks
|
||||||
|
|
||||||
|
- type: add_computed_field
|
||||||
|
args:
|
||||||
|
table: student_marks
|
||||||
|
name: total_marks
|
||||||
|
definition:
|
||||||
|
function: student_total_marks
|
||||||
|
table_argument: student_row
|
||||||
|
|
||||||
|
- type: add_computed_field
|
||||||
|
args:
|
||||||
|
table: student_marks
|
||||||
|
name: total_marks_offset
|
||||||
|
definition:
|
||||||
|
function: student_total_marks_offset
|
||||||
|
table_argument: student_row
|
||||||
|
session_argument: hasura_session
|
||||||
|
|
||||||
|
- type: create_select_permission
|
||||||
|
args:
|
||||||
|
table: student_marks
|
||||||
|
role: tutor
|
||||||
|
permission:
|
||||||
|
columns:
|
||||||
|
- name
|
||||||
|
filter:
|
||||||
|
total_marks:
|
||||||
|
_gte: 220
|
||||||
|
|
||||||
|
- type: create_select_permission
|
||||||
|
args:
|
||||||
|
table: student_marks
|
||||||
|
role: tutor_session
|
||||||
|
permission:
|
||||||
|
columns:
|
||||||
|
- name
|
||||||
|
computed_fields:
|
||||||
|
- total_marks
|
||||||
|
- total_marks_offset
|
||||||
|
filter:
|
||||||
|
total_marks_offset:
|
||||||
|
_gte: 220
|
||||||
|
@ -3,6 +3,7 @@ args:
|
|||||||
- type: run_sql
|
- type: run_sql
|
||||||
args:
|
args:
|
||||||
sql: |
|
sql: |
|
||||||
|
DROP FUNCTION get_articles(author);
|
||||||
DROP TABLE article;
|
DROP TABLE article;
|
||||||
DROP TABLE author;
|
DROP TABLE author;
|
||||||
DROP TABLE "Track" cascade;
|
DROP TABLE "Track" cascade;
|
||||||
@ -12,4 +13,7 @@ args:
|
|||||||
DROP TABLE jsonb_table;
|
DROP TABLE jsonb_table;
|
||||||
DROP TABLE gpa cascade;
|
DROP TABLE gpa cascade;
|
||||||
DROP TABLE auction;
|
DROP TABLE auction;
|
||||||
|
DROP FUNCTION student_total_marks(student_marks);
|
||||||
|
DROP FUNCTION student_total_marks_offset(json, student_marks);
|
||||||
|
DROP TABLE student_marks;
|
||||||
cascade: true
|
cascade: true
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
description: Fetch student names with tutor role
|
||||||
|
url: /v1/graphql
|
||||||
|
status: 200
|
||||||
|
headers:
|
||||||
|
X-Hasura-Role: tutor
|
||||||
|
query:
|
||||||
|
query: |
|
||||||
|
query {
|
||||||
|
student_marks{
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response:
|
||||||
|
data:
|
||||||
|
student_marks:
|
||||||
|
- name: clarke
|
||||||
|
- name: blake
|
||||||
|
- name: leonel
|
@ -0,0 +1,24 @@
|
|||||||
|
description: Fetch student names with tutor role with an offset given via hasura session
|
||||||
|
url: /v1/graphql
|
||||||
|
status: 200
|
||||||
|
headers:
|
||||||
|
X-Hasura-Role: tutor_session
|
||||||
|
X-Hasura-Offset-Marks: '10'
|
||||||
|
query:
|
||||||
|
query: |
|
||||||
|
query {
|
||||||
|
student_marks{
|
||||||
|
name
|
||||||
|
total_marks
|
||||||
|
total_marks_offset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response:
|
||||||
|
data:
|
||||||
|
student_marks:
|
||||||
|
- name: blake
|
||||||
|
total_marks: 233
|
||||||
|
total_marks_offset: 223
|
||||||
|
- name: leonel
|
||||||
|
total_marks: 268
|
||||||
|
total_marks_offset: 258
|
@ -602,6 +602,15 @@ class TestGraphqlQueryPermissions:
|
|||||||
def test_author_articles_without_required_headers_set(self, hge_ctx, transport):
|
def test_author_articles_without_required_headers_set(self, hge_ctx, transport):
|
||||||
check_query_f(hge_ctx, self.dir() + '/select_articles_without_required_headers.yaml', transport)
|
check_query_f(hge_ctx, self.dir() + '/select_articles_without_required_headers.yaml', transport)
|
||||||
|
|
||||||
|
def test_reader_author(self, hge_ctx, transport):
|
||||||
|
check_query_f(hge_ctx, self.dir() + '/reader_author.yaml', transport)
|
||||||
|
|
||||||
|
def test_tutor_get_students(self, hge_ctx, transport):
|
||||||
|
check_query_f(hge_ctx, self.dir() + '/tutor_get_students.yaml', transport)
|
||||||
|
|
||||||
|
def test_tutor_get_students_session(self, hge_ctx, transport):
|
||||||
|
check_query_f(hge_ctx, self.dir() + '/tutor_get_students_session.yaml', transport)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def dir(cls):
|
def dir(cls):
|
||||||
return 'queries/graphql_query/permissions'
|
return 'queries/graphql_query/permissions'
|
||||||
|
Loading…
Reference in New Issue
Block a user