refactor: rename Proc module to Routine
Assuming that functions=procedures is wrong since pg11, which introduced real stored procedures.
This commit is contained in:
committed by
Steve Chavez
parent
ad7d80a430
commit
feadf59bb3
+1
-1
@@ -46,7 +46,7 @@ library
|
|||||||
PostgREST.Cors
|
PostgREST.Cors
|
||||||
PostgREST.SchemaCache
|
PostgREST.SchemaCache
|
||||||
PostgREST.SchemaCache.Identifiers
|
PostgREST.SchemaCache.Identifiers
|
||||||
PostgREST.SchemaCache.Proc
|
PostgREST.SchemaCache.Routine
|
||||||
PostgREST.SchemaCache.Relationship
|
PostgREST.SchemaCache.Relationship
|
||||||
PostgREST.SchemaCache.Table
|
PostgREST.SchemaCache.Table
|
||||||
PostgREST.Error
|
PostgREST.Error
|
||||||
|
|||||||
@@ -36,9 +36,9 @@ module PostgREST.ApiRequest.Types
|
|||||||
import PostgREST.MediaType (MediaType (..))
|
import PostgREST.MediaType (MediaType (..))
|
||||||
import PostgREST.SchemaCache.Identifiers (FieldName,
|
import PostgREST.SchemaCache.Identifiers (FieldName,
|
||||||
QualifiedIdentifier)
|
QualifiedIdentifier)
|
||||||
import PostgREST.SchemaCache.Proc (ProcDescription (..))
|
|
||||||
import PostgREST.SchemaCache.Relationship (Relationship,
|
import PostgREST.SchemaCache.Relationship (Relationship,
|
||||||
RelationshipsMap)
|
RelationshipsMap)
|
||||||
|
import PostgREST.SchemaCache.Routine (Routine (..))
|
||||||
|
|
||||||
import Protolude
|
import Protolude
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ data SelectItem
|
|||||||
|
|
||||||
data ApiRequestError
|
data ApiRequestError
|
||||||
= AmbiguousRelBetween Text Text [Relationship]
|
= AmbiguousRelBetween Text Text [Relationship]
|
||||||
| AmbiguousRpc [ProcDescription]
|
| AmbiguousRpc [Routine]
|
||||||
| BinaryFieldError MediaType
|
| BinaryFieldError MediaType
|
||||||
| MediaTypeError [ByteString]
|
| MediaTypeError [ByteString]
|
||||||
| InvalidBody ByteString
|
| InvalidBody ByteString
|
||||||
@@ -76,7 +76,7 @@ data ApiRequestError
|
|||||||
| LimitNoOrderError
|
| LimitNoOrderError
|
||||||
| NotFound
|
| NotFound
|
||||||
| NoRelBetween Text Text (Maybe Text) Text RelationshipsMap
|
| NoRelBetween Text Text (Maybe Text) Text RelationshipsMap
|
||||||
| NoRpc Text Text [Text] Bool MediaType Bool [QualifiedIdentifier] [ProcDescription]
|
| NoRpc Text Text [Text] Bool MediaType Bool [QualifiedIdentifier] [Routine]
|
||||||
| NotEmbedded Text
|
| NotEmbedded Text
|
||||||
| PutLimitNotAllowedError
|
| PutLimitNotAllowedError
|
||||||
| QueryParamError QPError
|
| QueryParamError QPError
|
||||||
|
|||||||
@@ -39,12 +39,12 @@ import qualified PostgREST.MediaType as MediaType
|
|||||||
|
|
||||||
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..),
|
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..),
|
||||||
Schema)
|
Schema)
|
||||||
import PostgREST.SchemaCache.Proc (ProcDescription (..),
|
|
||||||
ProcParam (..))
|
|
||||||
import PostgREST.SchemaCache.Relationship (Cardinality (..),
|
import PostgREST.SchemaCache.Relationship (Cardinality (..),
|
||||||
Junction (..),
|
Junction (..),
|
||||||
Relationship (..),
|
Relationship (..),
|
||||||
RelationshipsMap)
|
RelationshipsMap)
|
||||||
|
import PostgREST.SchemaCache.Routine (Routine (..),
|
||||||
|
RoutineParam (..))
|
||||||
import Protolude
|
import Protolude
|
||||||
|
|
||||||
|
|
||||||
@@ -283,7 +283,7 @@ noRelBetweenHint parent child schema allRels = ("Perhaps you meant '" <>) <$>
|
|||||||
-- to all the overloaded functions' params using the form "param1, param2, param3, ..."
|
-- to all the overloaded functions' params using the form "param1, param2, param3, ..."
|
||||||
-- and shows the best match as hint.
|
-- and shows the best match as hint.
|
||||||
--
|
--
|
||||||
-- >>> let procsDesc = [ProcDescription {pdParams = [ProcParam {ppName="val"}, ProcParam {ppName="param"}, ProcParam {ppName="name"}]}, ProcDescription {pdParams = [ProcParam {ppName="id"}, ProcParam {ppName="attr"}]}]
|
-- >>> let procsDesc = [Routine {pdParams = [RoutineParam {ppName="val"}, RoutineParam {ppName="param"}, RoutineParam {ppName="name"}]}, Routine {pdParams = [RoutineParam {ppName="id"}, RoutineParam {ppName="attr"}]}]
|
||||||
--
|
--
|
||||||
-- >>> noRpcHint "api" "test" ["vall", "pqaram", "nam"] procs procsDesc
|
-- >>> noRpcHint "api" "test" ["vall", "pqaram", "nam"] procs procsDesc
|
||||||
-- Just "Perhaps you meant to call the function api.test(name, param, val)"
|
-- Just "Perhaps you meant to call the function api.test(name, param, val)"
|
||||||
@@ -300,7 +300,7 @@ noRelBetweenHint parent child schema allRels = ("Perhaps you meant '" <>) <$>
|
|||||||
-- >>> noRpcHint "api" "test" ["noclosealternative"] procs procsDesc
|
-- >>> noRpcHint "api" "test" ["noclosealternative"] procs procsDesc
|
||||||
-- Nothing
|
-- Nothing
|
||||||
--
|
--
|
||||||
noRpcHint :: Text -> Text -> [Text] -> [QualifiedIdentifier] -> [ProcDescription] -> Maybe Text
|
noRpcHint :: Text -> Text -> [Text] -> [QualifiedIdentifier] -> [Routine] -> Maybe Text
|
||||||
noRpcHint schema procName params allProcs overloadedProcs =
|
noRpcHint schema procName params allProcs overloadedProcs =
|
||||||
fmap (("Perhaps you meant to call the function " <> schema <> ".") <>) possibleProcs
|
fmap (("Perhaps you meant to call the function " <> schema <> ".") <>) possibleProcs
|
||||||
where
|
where
|
||||||
|
|||||||
+28
-28
@@ -27,11 +27,11 @@ module PostgREST.Plan
|
|||||||
) where
|
) where
|
||||||
|
|
||||||
|
|
||||||
import qualified Data.ByteString.Lazy as LBS
|
import qualified Data.ByteString.Lazy as LBS
|
||||||
import qualified Data.HashMap.Strict as HM
|
import qualified Data.HashMap.Strict as HM
|
||||||
import qualified Data.List as L
|
import qualified Data.List as L
|
||||||
import qualified Data.Set as S
|
import qualified Data.Set as S
|
||||||
import qualified PostgREST.SchemaCache.Proc as Proc
|
import qualified PostgREST.SchemaCache.Routine as Routine
|
||||||
|
|
||||||
import Data.Either.Combinators (mapLeft, mapRight)
|
import Data.Either.Combinators (mapLeft, mapRight)
|
||||||
import Data.List (delete)
|
import Data.List (delete)
|
||||||
@@ -54,16 +54,16 @@ import PostgREST.SchemaCache (SchemaCache (..))
|
|||||||
import PostgREST.SchemaCache.Identifiers (FieldName,
|
import PostgREST.SchemaCache.Identifiers (FieldName,
|
||||||
QualifiedIdentifier (..),
|
QualifiedIdentifier (..),
|
||||||
Schema)
|
Schema)
|
||||||
import PostgREST.SchemaCache.Proc (ProcDescription (..),
|
|
||||||
ProcParam (..), ProcsMap,
|
|
||||||
procReturnsCompositeAlias,
|
|
||||||
procReturnsScalar,
|
|
||||||
procReturnsSetOfScalar)
|
|
||||||
import PostgREST.SchemaCache.Relationship (Cardinality (..),
|
import PostgREST.SchemaCache.Relationship (Cardinality (..),
|
||||||
Junction (..),
|
Junction (..),
|
||||||
Relationship (..),
|
Relationship (..),
|
||||||
RelationshipsMap,
|
RelationshipsMap,
|
||||||
relIsToOne)
|
relIsToOne)
|
||||||
|
import PostgREST.SchemaCache.Routine (Routine (..), RoutineMap,
|
||||||
|
RoutineParam (..),
|
||||||
|
funcReturnsCompositeAlias,
|
||||||
|
funcReturnsScalar,
|
||||||
|
funcReturnsSetOfScalar)
|
||||||
import PostgREST.SchemaCache.Table (Table (tableName),
|
import PostgREST.SchemaCache.Table (Table (tableName),
|
||||||
tablePKCols)
|
tablePKCols)
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ data CallReadPlan = CallReadPlan {
|
|||||||
crReadPlan :: ReadPlanTree
|
crReadPlan :: ReadPlanTree
|
||||||
, crCallPlan :: CallPlan
|
, crCallPlan :: CallPlan
|
||||||
, crTxMode :: SQL.Mode
|
, crTxMode :: SQL.Mode
|
||||||
, crProc :: ProcDescription
|
, crProc :: Routine
|
||||||
, crBinField :: Maybe FieldName
|
, crBinField :: Maybe FieldName
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,9 +117,9 @@ callReadPlan identifier conf sCache apiRequest invMethod = do
|
|||||||
InvGet -> S.fromList $ fst <$> qsParams'
|
InvGet -> S.fromList $ fst <$> qsParams'
|
||||||
InvHead -> S.fromList $ fst <$> qsParams'
|
InvHead -> S.fromList $ fst <$> qsParams'
|
||||||
InvPost -> iColumns apiRequest
|
InvPost -> iColumns apiRequest
|
||||||
proc@ProcDescription{..} <- mapLeft ApiRequestError $
|
proc@Function{..} <- mapLeft ApiRequestError $
|
||||||
findProc identifier paramKeys (preferParameters == Just SingleObject) (dbProcs sCache) (iContentMediaType apiRequest) (invMethod == InvPost)
|
findProc identifier paramKeys (preferParameters == Just SingleObject) (dbRoutines sCache) (iContentMediaType apiRequest) (invMethod == InvPost)
|
||||||
let relIdentifier = QualifiedIdentifier pdSchema (fromMaybe pdName $ Proc.procTableName proc) -- done so a set returning function can embed other relations
|
let relIdentifier = QualifiedIdentifier pdSchema (fromMaybe pdName $ Routine.funcTableName proc) -- done so a set returning function can embed other relations
|
||||||
rPlan <- readPlan relIdentifier conf sCache apiRequest
|
rPlan <- readPlan relIdentifier conf sCache apiRequest
|
||||||
let args = case (invMethod, iContentMediaType apiRequest) of
|
let args = case (invMethod, iContentMediaType apiRequest) of
|
||||||
(InvGet, _) -> jsonRpcParams proc qsParams'
|
(InvGet, _) -> jsonRpcParams proc qsParams'
|
||||||
@@ -127,11 +127,11 @@ callReadPlan identifier conf sCache apiRequest invMethod = do
|
|||||||
(InvPost, MTUrlEncoded) -> maybe mempty (jsonRpcParams proc . payArray) $ iPayload apiRequest
|
(InvPost, MTUrlEncoded) -> maybe mempty (jsonRpcParams proc . payArray) $ iPayload apiRequest
|
||||||
(InvPost, _) -> maybe mempty payRaw $ iPayload apiRequest
|
(InvPost, _) -> maybe mempty payRaw $ iPayload apiRequest
|
||||||
txMode = case (invMethod, pdVolatility) of
|
txMode = case (invMethod, pdVolatility) of
|
||||||
(InvGet, _) -> SQL.Read
|
(InvGet, _) -> SQL.Read
|
||||||
(InvHead, _) -> SQL.Read
|
(InvHead, _) -> SQL.Read
|
||||||
(InvPost, Proc.Stable) -> SQL.Read
|
(InvPost, Routine.Stable) -> SQL.Read
|
||||||
(InvPost, Proc.Immutable) -> SQL.Read
|
(InvPost, Routine.Immutable) -> SQL.Read
|
||||||
(InvPost, Proc.Volatile) -> SQL.Write
|
(InvPost, Routine.Volatile) -> SQL.Write
|
||||||
cPlan = callPlan proc apiRequest paramKeys args rPlan
|
cPlan = callPlan proc apiRequest paramKeys args rPlan
|
||||||
binField <- mapLeft ApiRequestError $ binaryField conf (iAcceptMediaType apiRequest) (Just proc) rPlan
|
binField <- mapLeft ApiRequestError $ binaryField conf (iAcceptMediaType apiRequest) (Just proc) rPlan
|
||||||
return $ CallReadPlan rPlan cPlan txMode proc binField
|
return $ CallReadPlan rPlan cPlan txMode proc binField
|
||||||
@@ -143,7 +143,7 @@ callReadPlan identifier conf sCache apiRequest invMethod = do
|
|||||||
Search a pg proc by matching name and arguments keys to parameters. Since a function can be overloaded,
|
Search a pg proc by matching name and arguments keys to parameters. Since a function can be overloaded,
|
||||||
the name is not enough to find it. An overloaded function can have a different volatility or even a different return type.
|
the name is not enough to find it. An overloaded function can have a different volatility or even a different return type.
|
||||||
-}
|
-}
|
||||||
findProc :: QualifiedIdentifier -> S.Set Text -> Bool -> ProcsMap -> MediaType -> Bool -> Either ApiRequestError ProcDescription
|
findProc :: QualifiedIdentifier -> S.Set Text -> Bool -> RoutineMap -> MediaType -> Bool -> Either ApiRequestError Routine
|
||||||
findProc qi argumentsKeys paramsAsSingleObject allProcs contentMediaType isInvPost =
|
findProc qi argumentsKeys paramsAsSingleObject allProcs contentMediaType isInvPost =
|
||||||
case matchProc of
|
case matchProc of
|
||||||
([], []) -> Left $ NoRpc (qiSchema qi) (qiName qi) (S.toList argumentsKeys) paramsAsSingleObject contentMediaType isInvPost (HM.keys allProcs) lookupProcName
|
([], []) -> Left $ NoRpc (qiSchema qi) (qiName qi) (S.toList argumentsKeys) paramsAsSingleObject contentMediaType isInvPost (HM.keys allProcs) lookupProcName
|
||||||
@@ -166,7 +166,7 @@ findProc qi argumentsKeys paramsAsSingleObject allProcs contentMediaType isInvPo
|
|||||||
| otherwise = (ts,fs)
|
| otherwise = (ts,fs)
|
||||||
-- If the function is called with post and has a single unnamed parameter
|
-- If the function is called with post and has a single unnamed parameter
|
||||||
-- it can be called depending on content type and the parameter type
|
-- it can be called depending on content type and the parameter type
|
||||||
hasSingleUnnamedParam ProcDescription{pdParams=[ProcParam{ppType}]} = isInvPost && case (contentMediaType, ppType) of
|
hasSingleUnnamedParam Function{pdParams=[RoutineParam{ppType}]} = isInvPost && case (contentMediaType, ppType) of
|
||||||
(MTApplicationJSON, "json") -> True
|
(MTApplicationJSON, "json") -> True
|
||||||
(MTApplicationJSON, "jsonb") -> True
|
(MTApplicationJSON, "jsonb") -> True
|
||||||
(MTTextPlain, "text") -> True
|
(MTTextPlain, "text") -> True
|
||||||
@@ -544,14 +544,14 @@ resolveOrError (Just table) field =
|
|||||||
Nothing -> Left $ ColumnNotFound (tableName table) field
|
Nothing -> Left $ ColumnNotFound (tableName table) field
|
||||||
Just typedField -> Right typedField
|
Just typedField -> Right typedField
|
||||||
|
|
||||||
callPlan :: ProcDescription -> ApiRequest -> S.Set FieldName -> LBS.ByteString -> ReadPlanTree -> CallPlan
|
callPlan :: Routine -> ApiRequest -> S.Set FieldName -> LBS.ByteString -> ReadPlanTree -> CallPlan
|
||||||
callPlan proc ApiRequest{iPreferences=Preferences{..}} paramKeys args readReq = FunctionCall {
|
callPlan proc ApiRequest{iPreferences=Preferences{..}} paramKeys args readReq = FunctionCall {
|
||||||
funCQi = QualifiedIdentifier (pdSchema proc) (pdName proc)
|
funCQi = QualifiedIdentifier (pdSchema proc) (pdName proc)
|
||||||
, funCParams = callParams
|
, funCParams = callParams
|
||||||
, funCArgs = Just args
|
, funCArgs = Just args
|
||||||
, funCScalar = procReturnsScalar proc
|
, funCScalar = funcReturnsScalar proc
|
||||||
, funCSetOfScalar = procReturnsSetOfScalar proc
|
, funCSetOfScalar = funcReturnsSetOfScalar proc
|
||||||
, funCRetCompositeAlias = procReturnsCompositeAlias proc
|
, funCRetCompositeAlias = funcReturnsCompositeAlias proc
|
||||||
, funCReturning = inferColsEmbedNeeds readReq []
|
, funCReturning = inferColsEmbedNeeds readReq []
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
@@ -616,11 +616,11 @@ addFilterToLogicForest flt lf = Stmnt flt : lf
|
|||||||
-- | If raw(binary) output is requested, check that MediaType is one of the
|
-- | If raw(binary) output is requested, check that MediaType is one of the
|
||||||
-- admitted rawMediaTypes and that`?select=...` contains only one field other
|
-- admitted rawMediaTypes and that`?select=...` contains only one field other
|
||||||
-- than `*`
|
-- than `*`
|
||||||
binaryField :: AppConfig -> MediaType -> Maybe ProcDescription -> ReadPlanTree -> Either ApiRequestError (Maybe FieldName)
|
binaryField :: AppConfig -> MediaType -> Maybe Routine -> ReadPlanTree -> Either ApiRequestError (Maybe FieldName)
|
||||||
binaryField AppConfig{configRawMediaTypes} acceptMediaType proc rpTree
|
binaryField AppConfig{configRawMediaTypes} acceptMediaType proc rpTree
|
||||||
| isRawMediaType =
|
| isRawMediaType =
|
||||||
if (procReturnsScalar <$> proc) == Just True ||
|
if (funcReturnsScalar <$> proc) == Just True ||
|
||||||
(procReturnsSetOfScalar <$> proc) == Just True
|
(funcReturnsSetOfScalar <$> proc) == Just True
|
||||||
then Right $ Just "pgrst_scalar"
|
then Right $ Just "pgrst_scalar"
|
||||||
else
|
else
|
||||||
let
|
let
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import qualified Data.ByteString.Lazy as LBS
|
|||||||
import qualified Data.HashMap.Strict as HM
|
import qualified Data.HashMap.Strict as HM
|
||||||
import PostgREST.SchemaCache.Identifiers (FieldName,
|
import PostgREST.SchemaCache.Identifiers (FieldName,
|
||||||
QualifiedIdentifier)
|
QualifiedIdentifier)
|
||||||
import PostgREST.SchemaCache.Proc (ProcDescription (..),
|
import PostgREST.SchemaCache.Routine (Routine (..),
|
||||||
ProcParam (..))
|
RoutineParam (..))
|
||||||
|
|
||||||
import Protolude
|
import Protolude
|
||||||
|
|
||||||
@@ -27,11 +27,11 @@ data CallPlan = FunctionCall
|
|||||||
}
|
}
|
||||||
|
|
||||||
data CallParams
|
data CallParams
|
||||||
= KeyParams [ProcParam] -- ^ Call with key params: func(a := val1, b:= val2)
|
= KeyParams [RoutineParam] -- ^ Call with key params: func(a := val1, b:= val2)
|
||||||
| OnePosParam ProcParam -- ^ Call with positional params(only one supported): func(val)
|
| OnePosParam RoutineParam -- ^ Call with positional params(only one supported): func(val)
|
||||||
|
|
||||||
-- | Convert rpc params `/rpc/func?a=val1&b=val2` to json `{"a": "val1", "b": "val2"}
|
-- | Convert rpc params `/rpc/func?a=val1&b=val2` to json `{"a": "val1", "b": "val2"}
|
||||||
jsonRpcParams :: ProcDescription -> [(Text, Text)] -> LBS.ByteString
|
jsonRpcParams :: Routine -> [(Text, Text)] -> LBS.ByteString
|
||||||
jsonRpcParams proc prms =
|
jsonRpcParams proc prms =
|
||||||
if not $ pdHasVariadic proc then -- if proc has no variadic param, save steps and directly convert to json
|
if not $ pdHasVariadic proc then -- if proc has no variadic param, save steps and directly convert to json
|
||||||
JSON.encode $ HM.fromList $ second JSON.toJSON <$> prms
|
JSON.encode $ HM.fromList $ second JSON.toJSON <$> prms
|
||||||
@@ -43,11 +43,11 @@ jsonRpcParams proc prms =
|
|||||||
mergeParams (Variadic a) (Variadic b) = Variadic $ b ++ a
|
mergeParams (Variadic a) (Variadic b) = Variadic $ b ++ a
|
||||||
mergeParams v _ = v -- repeated params for non-variadic parameters are not merged
|
mergeParams v _ = v -- repeated params for non-variadic parameters are not merged
|
||||||
|
|
||||||
toRpcParamValue :: ProcDescription -> (Text, Text) -> (Text, RpcParamValue)
|
toRpcParamValue :: Routine -> (Text, Text) -> (Text, RpcParamValue)
|
||||||
toRpcParamValue proc (k, v) | prmIsVariadic k = (k, Variadic [v])
|
toRpcParamValue proc (k, v) | prmIsVariadic k = (k, Variadic [v])
|
||||||
| otherwise = (k, Fixed v)
|
| otherwise = (k, Fixed v)
|
||||||
where
|
where
|
||||||
prmIsVariadic prm = isJust $ find (\ProcParam{ppName, ppVar} -> ppName == prm && ppVar) $ pdParams proc
|
prmIsVariadic prm = isJust $ find (\RoutineParam{ppName, ppVar} -> ppName == prm && ppVar) $ pdParams proc
|
||||||
|
|
||||||
-- | RPC query param value `/rpc/func?v=<value>`, used for VARIADIC functions on form-urlencoded POST and GETs
|
-- | RPC query param value `/rpc/func?v=<value>`, used for VARIADIC functions on form-urlencoded POST and GETs
|
||||||
-- | It can be fixed `?v=1` or repeated `?v=1&v=2&v=3.
|
-- | It can be fixed `?v=1` or repeated `?v=1&v=2&v=3.
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
module PostgREST.Plan.Types
|
module PostgREST.Plan.Types
|
||||||
( TypedField(..)
|
( TypedField(..)
|
||||||
, resolveTableField
|
, resolveTableField
|
||||||
|
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import qualified Data.HashMap.Strict.InsOrd as HMI
|
import qualified Data.HashMap.Strict.InsOrd as HMI
|
||||||
|
|||||||
+14
-15
@@ -27,12 +27,12 @@ import qualified Hasql.Encoders as HE
|
|||||||
import qualified Hasql.Statement as SQL
|
import qualified Hasql.Statement as SQL
|
||||||
import qualified Hasql.Transaction as SQL
|
import qualified Hasql.Transaction as SQL
|
||||||
|
|
||||||
import qualified PostgREST.Error as Error
|
import qualified PostgREST.Error as Error
|
||||||
import qualified PostgREST.Query.QueryBuilder as QueryBuilder
|
import qualified PostgREST.Query.QueryBuilder as QueryBuilder
|
||||||
import qualified PostgREST.Query.Statements as Statements
|
import qualified PostgREST.Query.Statements as Statements
|
||||||
import qualified PostgREST.RangeQuery as RangeQuery
|
import qualified PostgREST.RangeQuery as RangeQuery
|
||||||
import qualified PostgREST.SchemaCache as SchemaCache
|
import qualified PostgREST.SchemaCache as SchemaCache
|
||||||
import qualified PostgREST.SchemaCache.Proc as Proc
|
import qualified PostgREST.SchemaCache.Routine as Routine
|
||||||
|
|
||||||
import Data.Scientific (FPFormat (..), formatScientific, isInteger)
|
import Data.Scientific (FPFormat (..), formatScientific, isInteger)
|
||||||
|
|
||||||
@@ -59,8 +59,7 @@ import PostgREST.Query.Statements (ResultSet (..))
|
|||||||
import PostgREST.SchemaCache (SchemaCache (..))
|
import PostgREST.SchemaCache (SchemaCache (..))
|
||||||
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..),
|
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..),
|
||||||
Schema)
|
Schema)
|
||||||
import PostgREST.SchemaCache.Proc (ProcDescription (..),
|
import PostgREST.SchemaCache.Routine (Routine (..), RoutineMap)
|
||||||
ProcsMap)
|
|
||||||
import PostgREST.SchemaCache.Table (TablesMap)
|
import PostgREST.SchemaCache.Table (TablesMap)
|
||||||
|
|
||||||
import Protolude hiding (Handler)
|
import Protolude hiding (Handler)
|
||||||
@@ -152,14 +151,14 @@ deleteQuery mrPlan apiReq@ApiRequest{..} conf = do
|
|||||||
optionalRollback conf apiReq
|
optionalRollback conf apiReq
|
||||||
pure resultSet
|
pure resultSet
|
||||||
|
|
||||||
invokeQuery :: ProcDescription -> CallReadPlan -> ApiRequest -> AppConfig -> PgVersion -> DbHandler ResultSet
|
invokeQuery :: Routine -> CallReadPlan -> ApiRequest -> AppConfig -> PgVersion -> DbHandler ResultSet
|
||||||
invokeQuery proc CallReadPlan{crReadPlan, crCallPlan, crBinField} apiReq@ApiRequest{iPreferences=Preferences{..}, ..} conf@AppConfig{..} pgVer = do
|
invokeQuery proc CallReadPlan{crReadPlan, crCallPlan, crBinField} apiReq@ApiRequest{iPreferences=Preferences{..}, ..} conf@AppConfig{..} pgVer = do
|
||||||
resultSet <-
|
resultSet <-
|
||||||
lift . SQL.statement mempty $
|
lift . SQL.statement mempty $
|
||||||
Statements.prepareCall
|
Statements.prepareCall
|
||||||
(Proc.procReturnsScalar proc)
|
(Routine.funcReturnsScalar proc)
|
||||||
(Proc.procReturnsSingleComposite proc)
|
(Routine.funcReturnsSingleComposite proc)
|
||||||
(Proc.procReturnsSetOfScalar proc)
|
(Routine.funcReturnsSetOfScalar proc)
|
||||||
(QueryBuilder.callPlanToQuery crCallPlan pgVer)
|
(QueryBuilder.callPlanToQuery crCallPlan pgVer)
|
||||||
(QueryBuilder.readPlanToQuery crReadPlan)
|
(QueryBuilder.readPlanToQuery crReadPlan)
|
||||||
(QueryBuilder.readPlanToCountQuery crReadPlan)
|
(QueryBuilder.readPlanToCountQuery crReadPlan)
|
||||||
@@ -172,19 +171,19 @@ invokeQuery proc CallReadPlan{crReadPlan, crCallPlan, crBinField} apiReq@ApiRequ
|
|||||||
failNotSingular iAcceptMediaType resultSet
|
failNotSingular iAcceptMediaType resultSet
|
||||||
pure resultSet
|
pure resultSet
|
||||||
|
|
||||||
openApiQuery :: SchemaCache -> PgVersion -> AppConfig -> Schema -> DbHandler (Maybe (TablesMap, ProcsMap, Maybe Text))
|
openApiQuery :: SchemaCache -> PgVersion -> AppConfig -> Schema -> DbHandler (Maybe (TablesMap, RoutineMap, Maybe Text))
|
||||||
openApiQuery sCache pgVer AppConfig{..} tSchema =
|
openApiQuery sCache pgVer AppConfig{..} tSchema =
|
||||||
lift $ case configOpenApiMode of
|
lift $ case configOpenApiMode of
|
||||||
OAFollowPriv -> do
|
OAFollowPriv -> do
|
||||||
tableAccess <- SQL.statement [tSchema] (SchemaCache.accessibleTables pgVer configDbPreparedStatements)
|
tableAccess <- SQL.statement [tSchema] (SchemaCache.accessibleTables pgVer configDbPreparedStatements)
|
||||||
Just <$> ((,,)
|
Just <$> ((,,)
|
||||||
(HM.filterWithKey (\qi _ -> S.member qi tableAccess) $ SchemaCache.dbTables sCache)
|
(HM.filterWithKey (\qi _ -> S.member qi tableAccess) $ SchemaCache.dbTables sCache)
|
||||||
<$> SQL.statement tSchema (SchemaCache.accessibleProcs pgVer configDbPreparedStatements)
|
<$> SQL.statement tSchema (SchemaCache.accessibleFuncs pgVer configDbPreparedStatements)
|
||||||
<*> SQL.statement tSchema (SchemaCache.schemaDescription configDbPreparedStatements))
|
<*> SQL.statement tSchema (SchemaCache.schemaDescription configDbPreparedStatements))
|
||||||
OAIgnorePriv ->
|
OAIgnorePriv ->
|
||||||
Just <$> ((,,)
|
Just <$> ((,,)
|
||||||
(HM.filterWithKey (\(QualifiedIdentifier sch _) _ -> sch == tSchema) $ SchemaCache.dbTables sCache)
|
(HM.filterWithKey (\(QualifiedIdentifier sch _) _ -> sch == tSchema) $ SchemaCache.dbTables sCache)
|
||||||
(HM.filterWithKey (\(QualifiedIdentifier sch _) _ -> sch == tSchema) $ SchemaCache.dbProcs sCache)
|
(HM.filterWithKey (\(QualifiedIdentifier sch _) _ -> sch == tSchema) $ SchemaCache.dbRoutines sCache)
|
||||||
<$> SQL.statement tSchema (SchemaCache.schemaDescription configDbPreparedStatements))
|
<$> SQL.statement tSchema (SchemaCache.schemaDescription configDbPreparedStatements))
|
||||||
OADisabled ->
|
OADisabled ->
|
||||||
pure Nothing
|
pure Nothing
|
||||||
|
|||||||
@@ -25,11 +25,11 @@ import PostgREST.ApiRequest.Preferences (PreferResolution (..))
|
|||||||
import PostgREST.Config.PgVersion (PgVersion, pgVersion110,
|
import PostgREST.Config.PgVersion (PgVersion, pgVersion110,
|
||||||
pgVersion130)
|
pgVersion130)
|
||||||
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..))
|
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..))
|
||||||
import PostgREST.SchemaCache.Proc (ProcParam (..))
|
|
||||||
import PostgREST.SchemaCache.Relationship (Cardinality (..),
|
import PostgREST.SchemaCache.Relationship (Cardinality (..),
|
||||||
Junction (..),
|
Junction (..),
|
||||||
Relationship (..),
|
Relationship (..),
|
||||||
relIsToOne)
|
relIsToOne)
|
||||||
|
import PostgREST.SchemaCache.Routine (RoutineParam (..))
|
||||||
|
|
||||||
import PostgREST.ApiRequest.Types
|
import PostgREST.ApiRequest.Types
|
||||||
import PostgREST.Plan.CallPlan
|
import PostgREST.Plan.CallPlan
|
||||||
@@ -180,7 +180,7 @@ callPlanToQuery (FunctionCall qi params args returnsScalar returnsSetOfScalar re
|
|||||||
callIt argument | pgVer < pgVersion130 && pgVer >= pgVersion110 && returnsCompositeAlias = "(SELECT (" <> SQL.sql (fromQi qi) <> "(" <> argument <> ")).*) pgrst_call"
|
callIt argument | pgVer < pgVersion130 && pgVer >= pgVersion110 && returnsCompositeAlias = "(SELECT (" <> SQL.sql (fromQi qi) <> "(" <> argument <> ")).*) pgrst_call"
|
||||||
| otherwise = SQL.sql (fromQi qi) <> "(" <> argument <> ") pgrst_call"
|
| otherwise = SQL.sql (fromQi qi) <> "(" <> argument <> ") pgrst_call"
|
||||||
|
|
||||||
fmtParams :: [ProcParam] -> SQL.Snippet
|
fmtParams :: [RoutineParam] -> SQL.Snippet
|
||||||
fmtParams prms = SQL.sql $ BS.intercalate ", "
|
fmtParams prms = SQL.sql $ BS.intercalate ", "
|
||||||
((\a -> (if ppVar a then "VARIADIC " else mempty) <> pgFmtIdent (ppName a) <> " := pgrst_body." <> pgFmtIdent (ppName a)) <$> prms)
|
((\a -> (if ppVar a then "VARIADIC " else mempty) <> pgFmtIdent (ppName a) <> " := pgrst_body." <> pgFmtIdent (ppName a)) <$> prms)
|
||||||
|
|
||||||
|
|||||||
@@ -50,13 +50,12 @@ import PostgREST.Response.GucHeader (GucHeader, unwrapGucHeader)
|
|||||||
import PostgREST.SchemaCache (SchemaCache (..))
|
import PostgREST.SchemaCache (SchemaCache (..))
|
||||||
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..),
|
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..),
|
||||||
Schema)
|
Schema)
|
||||||
import PostgREST.SchemaCache.Proc (ProcDescription (..),
|
import PostgREST.SchemaCache.Routine (FuncVolatility (..),
|
||||||
ProcVolatility (..),
|
Routine (..), RoutineMap)
|
||||||
ProcsMap)
|
|
||||||
import PostgREST.SchemaCache.Table (Table (..), TablesMap)
|
import PostgREST.SchemaCache.Table (Table (..), TablesMap)
|
||||||
|
|
||||||
import qualified PostgREST.ApiRequest.Types as ApiRequestTypes
|
import qualified PostgREST.ApiRequest.Types as ApiRequestTypes
|
||||||
import qualified PostgREST.SchemaCache.Proc as Proc
|
import qualified PostgREST.SchemaCache.Routine as Routine
|
||||||
|
|
||||||
import Protolude hiding (Handler, toS)
|
import Protolude hiding (Handler, toS)
|
||||||
import Protolude.Conv (toS)
|
import Protolude.Conv (toS)
|
||||||
@@ -189,7 +188,7 @@ infoIdentResponse identifier sCache =
|
|||||||
["PATCH" | tableUpdatable table] ++
|
["PATCH" | tableUpdatable table] ++
|
||||||
["DELETE" | tableDeletable table]
|
["DELETE" | tableDeletable table]
|
||||||
|
|
||||||
infoProcResponse :: ProcDescription -> Wai.Response
|
infoProcResponse :: Routine -> Wai.Response
|
||||||
infoProcResponse proc | pdVolatility proc == Volatile = respondInfo "OPTIONS,POST"
|
infoProcResponse proc | pdVolatility proc == Volatile = respondInfo "OPTIONS,POST"
|
||||||
| otherwise = respondInfo "OPTIONS,GET,HEAD,POST"
|
| otherwise = respondInfo "OPTIONS,GET,HEAD,POST"
|
||||||
|
|
||||||
@@ -201,7 +200,7 @@ respondInfo allowHeader =
|
|||||||
let allOrigins = ("Access-Control-Allow-Origin", "*") in
|
let allOrigins = ("Access-Control-Allow-Origin", "*") in
|
||||||
Wai.responseLBS HTTP.status200 [allOrigins, (HTTP.hAllow, allowHeader)] mempty
|
Wai.responseLBS HTTP.status200 [allOrigins, (HTTP.hAllow, allowHeader)] mempty
|
||||||
|
|
||||||
invokeResponse :: InvokeMethod -> ProcDescription -> ApiRequest -> ResultSet -> Wai.Response
|
invokeResponse :: InvokeMethod -> Routine -> ApiRequest -> ResultSet -> Wai.Response
|
||||||
invokeResponse invMethod proc ctxApiRequest@ApiRequest{..} resultSet = case resultSet of
|
invokeResponse invMethod proc ctxApiRequest@ApiRequest{..} resultSet = case resultSet of
|
||||||
RSStandard {..} -> do
|
RSStandard {..} -> do
|
||||||
let
|
let
|
||||||
@@ -214,7 +213,7 @@ invokeResponse invMethod proc ctxApiRequest@ApiRequest{..} resultSet = case resu
|
|||||||
else LBS.fromStrict rsBody
|
else LBS.fromStrict rsBody
|
||||||
headers = [contentRange]
|
headers = [contentRange]
|
||||||
|
|
||||||
if Proc.procReturnsVoid proc then
|
if Routine.funcReturnsVoid proc then
|
||||||
response HTTP.status204 headers mempty
|
response HTTP.status204 headers mempty
|
||||||
else
|
else
|
||||||
response status
|
response status
|
||||||
@@ -224,7 +223,7 @@ invokeResponse invMethod proc ctxApiRequest@ApiRequest{..} resultSet = case resu
|
|||||||
RSPlan plan ->
|
RSPlan plan ->
|
||||||
Wai.responseLBS HTTP.status200 (contentTypeHeaders ctxApiRequest) $ LBS.fromStrict plan
|
Wai.responseLBS HTTP.status200 (contentTypeHeaders ctxApiRequest) $ LBS.fromStrict plan
|
||||||
|
|
||||||
openApiResponse :: Bool -> Maybe (TablesMap, ProcsMap, Maybe Text) -> AppConfig -> SchemaCache -> Schema -> Bool -> Wai.Response
|
openApiResponse :: Bool -> Maybe (TablesMap, RoutineMap, Maybe Text) -> AppConfig -> SchemaCache -> Schema -> Bool -> Wai.Response
|
||||||
openApiResponse headersOnly body conf sCache schema negotiatedByProfile =
|
openApiResponse headersOnly body conf sCache schema negotiatedByProfile =
|
||||||
Wai.responseLBS HTTP.status200
|
Wai.responseLBS HTTP.status200
|
||||||
(MediaType.toContentType MTOpenAPI : maybeToList (profileHeader schema negotiatedByProfile))
|
(MediaType.toContentType MTOpenAPI : maybeToList (profileHeader schema negotiatedByProfile))
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ import PostgREST.Config (AppConfig (..), Proxy (..),
|
|||||||
isMalformedProxyUri, toURI)
|
isMalformedProxyUri, toURI)
|
||||||
import PostgREST.SchemaCache (SchemaCache (..))
|
import PostgREST.SchemaCache (SchemaCache (..))
|
||||||
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..))
|
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..))
|
||||||
import PostgREST.SchemaCache.Proc (ProcDescription (..),
|
|
||||||
ProcParam (..))
|
|
||||||
import PostgREST.SchemaCache.Relationship (Cardinality (..),
|
import PostgREST.SchemaCache.Relationship (Cardinality (..),
|
||||||
Relationship (..),
|
Relationship (..),
|
||||||
RelationshipsMap)
|
RelationshipsMap)
|
||||||
|
import PostgREST.SchemaCache.Routine (Routine (..),
|
||||||
|
RoutineParam (..))
|
||||||
import PostgREST.SchemaCache.Table (Column (..), Table (..),
|
import PostgREST.SchemaCache.Table (Column (..), Table (..),
|
||||||
TablesMap,
|
TablesMap,
|
||||||
tableColumnsList)
|
tableColumnsList)
|
||||||
@@ -42,7 +42,7 @@ import PostgREST.MediaType
|
|||||||
|
|
||||||
import Protolude hiding (Proxy, get)
|
import Protolude hiding (Proxy, get)
|
||||||
|
|
||||||
encode :: AppConfig -> SchemaCache -> TablesMap -> HM.HashMap k [ProcDescription] -> Maybe Text -> LBS.ByteString
|
encode :: AppConfig -> SchemaCache -> TablesMap -> HM.HashMap k [Routine] -> Maybe Text -> LBS.ByteString
|
||||||
encode conf sCache tables procs schemaDescription =
|
encode conf sCache tables procs schemaDescription =
|
||||||
JSON.encode $
|
JSON.encode $
|
||||||
postgrestSpec
|
postgrestSpec
|
||||||
@@ -145,7 +145,7 @@ makeProperty tbl rels col = (colName col, Inline s)
|
|||||||
& type_ .~ toSwaggerType (colType col)
|
& type_ .~ toSwaggerType (colType col)
|
||||||
& items .~ (SwaggerItemsObject <$> makePropertyItems (colType col))
|
& items .~ (SwaggerItemsObject <$> makePropertyItems (colType col))
|
||||||
|
|
||||||
makeProcSchema :: ProcDescription -> Schema
|
makeProcSchema :: Routine -> Schema
|
||||||
makeProcSchema pd =
|
makeProcSchema pd =
|
||||||
(mempty :: Schema)
|
(mempty :: Schema)
|
||||||
& description .~ pdDescription pd
|
& description .~ pdDescription pd
|
||||||
@@ -153,8 +153,8 @@ makeProcSchema pd =
|
|||||||
& properties .~ fromList (fmap makeProcProperty (pdParams pd))
|
& properties .~ fromList (fmap makeProcProperty (pdParams pd))
|
||||||
& required .~ fmap ppName (filter ppReq (pdParams pd))
|
& required .~ fmap ppName (filter ppReq (pdParams pd))
|
||||||
|
|
||||||
makeProcProperty :: ProcParam -> (Text, Referenced Schema)
|
makeProcProperty :: RoutineParam -> (Text, Referenced Schema)
|
||||||
makeProcProperty (ProcParam n t _ _) = (n, Inline s)
|
makeProcProperty (RoutineParam n t _ _) = (n, Inline s)
|
||||||
where
|
where
|
||||||
s = (mempty :: Schema)
|
s = (mempty :: Schema)
|
||||||
& type_ .~ toSwaggerType t
|
& type_ .~ toSwaggerType t
|
||||||
@@ -180,8 +180,8 @@ makePreferParam ts =
|
|||||||
"resolution" -> ["resolution=ignore-duplicates", "resolution=merge-duplicates"]
|
"resolution" -> ["resolution=ignore-duplicates", "resolution=merge-duplicates"]
|
||||||
_ -> []
|
_ -> []
|
||||||
|
|
||||||
makeProcGetParam :: ProcParam -> Referenced Param
|
makeProcGetParam :: RoutineParam -> Referenced Param
|
||||||
makeProcGetParam (ProcParam n t r v) =
|
makeProcGetParam (RoutineParam n t r v) =
|
||||||
Inline $ (mempty :: Param)
|
Inline $ (mempty :: Param)
|
||||||
& name .~ n
|
& name .~ n
|
||||||
& required ?~ r
|
& required ?~ r
|
||||||
@@ -206,10 +206,10 @@ makeProcGetParam (ProcParam n t r v) =
|
|||||||
Nothing -> SwaggerString
|
Nothing -> SwaggerString
|
||||||
_ -> fromJust paramType
|
_ -> fromJust paramType
|
||||||
|
|
||||||
makeProcGetParams :: [ProcParam] -> [Referenced Param]
|
makeProcGetParams :: [RoutineParam] -> [Referenced Param]
|
||||||
makeProcGetParams = fmap makeProcGetParam
|
makeProcGetParams = fmap makeProcGetParam
|
||||||
|
|
||||||
makeProcPostParams :: ProcDescription -> [Referenced Param]
|
makeProcPostParams :: Routine -> [Referenced Param]
|
||||||
makeProcPostParams pd =
|
makeProcPostParams pd =
|
||||||
[ Inline $ (mempty :: Param)
|
[ Inline $ (mempty :: Param)
|
||||||
& name .~ "args"
|
& name .~ "args"
|
||||||
@@ -340,7 +340,7 @@ makePathItem t = ("/" ++ T.unpack tn, p $ tableInsertable t || tableUpdatable t
|
|||||||
rs = [ T.intercalate "." ["rowFilter", tn, colName c ] | c <- tableColumnsList t ]
|
rs = [ T.intercalate "." ["rowFilter", tn, colName c ] | c <- tableColumnsList t ]
|
||||||
ref = Ref . Reference
|
ref = Ref . Reference
|
||||||
|
|
||||||
makeProcPathItem :: ProcDescription -> (FilePath, PathItem)
|
makeProcPathItem :: Routine -> (FilePath, PathItem)
|
||||||
makeProcPathItem pd = ("/rpc/" ++ toS (pdName pd), pe)
|
makeProcPathItem pd = ("/rpc/" ++ toS (pdName pd), pe)
|
||||||
where
|
where
|
||||||
-- Use first line of proc description as summary; rest as description (if present)
|
-- Use first line of proc description as summary; rest as description (if present)
|
||||||
@@ -372,7 +372,7 @@ makeRootPathItem = ("/", p)
|
|||||||
pr = (mempty :: PathItem) & get ?~ getOp
|
pr = (mempty :: PathItem) & get ?~ getOp
|
||||||
p = pr
|
p = pr
|
||||||
|
|
||||||
makePathItems :: [ProcDescription] -> [Table] -> InsOrdHashMap FilePath PathItem
|
makePathItems :: [Routine] -> [Table] -> InsOrdHashMap FilePath PathItem
|
||||||
makePathItems pds ti = fromList $ makeRootPathItem :
|
makePathItems pds ti = fromList $ makeRootPathItem :
|
||||||
fmap makePathItem ti ++ fmap makeProcPathItem pds
|
fmap makePathItem ti ++ fmap makeProcPathItem pds
|
||||||
|
|
||||||
@@ -392,7 +392,7 @@ escapeHostName "*6" = "0.0.0.0"
|
|||||||
escapeHostName "!6" = "0.0.0.0"
|
escapeHostName "!6" = "0.0.0.0"
|
||||||
escapeHostName h = h
|
escapeHostName h = h
|
||||||
|
|
||||||
postgrestSpec :: RelationshipsMap -> [ProcDescription] -> [Table] -> (Text, Text, Integer, Text) -> Maybe Text -> Bool -> Swagger
|
postgrestSpec :: RelationshipsMap -> [Routine] -> [Table] -> (Text, Text, Integer, Text) -> Maybe Text -> Bool -> Swagger
|
||||||
postgrestSpec rels pds ti (s, h, p, b) sd allowSecurityDef = (mempty :: Swagger)
|
postgrestSpec rels pds ti (s, h, p, b) sd allowSecurityDef = (mempty :: Swagger)
|
||||||
& basePath ?~ T.unpack b
|
& basePath ?~ T.unpack b
|
||||||
& schemes ?~ [s']
|
& schemes ?~ [s']
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ module PostgREST.SchemaCache
|
|||||||
( SchemaCache(..)
|
( SchemaCache(..)
|
||||||
, querySchemaCache
|
, querySchemaCache
|
||||||
, accessibleTables
|
, accessibleTables
|
||||||
, accessibleProcs
|
, accessibleFuncs
|
||||||
, schemaDescription
|
, schemaDescription
|
||||||
) where
|
) where
|
||||||
|
|
||||||
@@ -44,15 +44,14 @@ import PostgREST.Config.PgVersion (PgVersion, pgVersion100,
|
|||||||
import PostgREST.SchemaCache.Identifiers (AccessSet, FieldName,
|
import PostgREST.SchemaCache.Identifiers (AccessSet, FieldName,
|
||||||
QualifiedIdentifier (..),
|
QualifiedIdentifier (..),
|
||||||
Schema)
|
Schema)
|
||||||
import PostgREST.SchemaCache.Proc (PgType (..),
|
|
||||||
ProcDescription (..),
|
|
||||||
ProcParam (..),
|
|
||||||
ProcVolatility (..),
|
|
||||||
ProcsMap, RetType (..))
|
|
||||||
import PostgREST.SchemaCache.Relationship (Cardinality (..),
|
import PostgREST.SchemaCache.Relationship (Cardinality (..),
|
||||||
Junction (..),
|
Junction (..),
|
||||||
Relationship (..),
|
Relationship (..),
|
||||||
RelationshipsMap)
|
RelationshipsMap)
|
||||||
|
import PostgREST.SchemaCache.Routine (FuncVolatility (..),
|
||||||
|
PgType (..), RetType (..),
|
||||||
|
Routine (..), RoutineMap,
|
||||||
|
RoutineParam (..))
|
||||||
import PostgREST.SchemaCache.Table (Column (..), ColumnMap,
|
import PostgREST.SchemaCache.Table (Column (..), ColumnMap,
|
||||||
Table (..), TablesMap)
|
Table (..), TablesMap)
|
||||||
|
|
||||||
@@ -62,7 +61,7 @@ import Protolude
|
|||||||
data SchemaCache = SchemaCache
|
data SchemaCache = SchemaCache
|
||||||
{ dbTables :: TablesMap
|
{ dbTables :: TablesMap
|
||||||
, dbRelationships :: RelationshipsMap
|
, dbRelationships :: RelationshipsMap
|
||||||
, dbProcs :: ProcsMap
|
, dbRoutines :: RoutineMap
|
||||||
}
|
}
|
||||||
deriving (Generic, JSON.ToJSON)
|
deriving (Generic, JSON.ToJSON)
|
||||||
|
|
||||||
@@ -111,7 +110,7 @@ querySchemaCache schemas extraSearchPath prepared = do
|
|||||||
tabs <- SQL.statement schemas $ allTables pgVer prepared
|
tabs <- SQL.statement schemas $ allTables pgVer prepared
|
||||||
keyDeps <- SQL.statement (schemas, extraSearchPath) $ allViewsKeyDependencies prepared
|
keyDeps <- SQL.statement (schemas, extraSearchPath) $ allViewsKeyDependencies prepared
|
||||||
m2oRels <- SQL.statement mempty $ allM2OandO2ORels pgVer prepared
|
m2oRels <- SQL.statement mempty $ allM2OandO2ORels pgVer prepared
|
||||||
procs <- SQL.statement schemas $ allProcs pgVer prepared
|
funcs <- SQL.statement schemas $ allFunctions pgVer prepared
|
||||||
cRels <- SQL.statement mempty $ allComputedRels prepared
|
cRels <- SQL.statement mempty $ allComputedRels prepared
|
||||||
|
|
||||||
let tabsWViewsPks = addViewPrimaryKeys tabs keyDeps
|
let tabsWViewsPks = addViewPrimaryKeys tabs keyDeps
|
||||||
@@ -120,7 +119,7 @@ querySchemaCache schemas extraSearchPath prepared = do
|
|||||||
return $ removeInternal schemas $ SchemaCache {
|
return $ removeInternal schemas $ SchemaCache {
|
||||||
dbTables = tabsWViewsPks
|
dbTables = tabsWViewsPks
|
||||||
, dbRelationships = getOverrideRelationshipsMap rels cRels
|
, dbRelationships = getOverrideRelationshipsMap rels cRels
|
||||||
, dbProcs = procs
|
, dbRoutines = funcs
|
||||||
}
|
}
|
||||||
|
|
||||||
-- | overrides detected relationships with the computed relationships and gets the RelationshipsMap
|
-- | overrides detected relationships with the computed relationships and gets the RelationshipsMap
|
||||||
@@ -150,7 +149,7 @@ removeInternal schemas dbStruct =
|
|||||||
dbTables = HM.filterWithKey (\(QualifiedIdentifier sch _) _ -> sch `elem` schemas) $ dbTables dbStruct
|
dbTables = HM.filterWithKey (\(QualifiedIdentifier sch _) _ -> sch `elem` schemas) $ dbTables dbStruct
|
||||||
, dbRelationships = filter (\r -> qiSchema (relForeignTable r) `elem` schemas && not (hasInternalJunction r)) <$>
|
, dbRelationships = filter (\r -> qiSchema (relForeignTable r) `elem` schemas && not (hasInternalJunction r)) <$>
|
||||||
HM.filterWithKey (\(QualifiedIdentifier sch _, _) _ -> sch `elem` schemas ) (dbRelationships dbStruct)
|
HM.filterWithKey (\(QualifiedIdentifier sch _, _) _ -> sch `elem` schemas ) (dbRelationships dbStruct)
|
||||||
, dbProcs = dbProcs dbStruct -- procs are only obtained from the exposed schemas, no need to filter them.
|
, dbRoutines = dbRoutines dbStruct -- procs are only obtained from the exposed schemas, no need to filter them.
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
hasInternalJunction ComputedRelationship{} = False
|
hasInternalJunction ComputedRelationship{} = False
|
||||||
@@ -228,17 +227,17 @@ viewKeyDepFromRow (s1,t1,s2,v2,cons,consType,sCols) = ViewKeyDependency (Qualifi
|
|||||||
| consType == "f" = FKDep
|
| consType == "f" = FKDep
|
||||||
| otherwise = FKDepRef -- f_ref, we build this type in the query
|
| otherwise = FKDepRef -- f_ref, we build this type in the query
|
||||||
|
|
||||||
decodeProcs :: HD.Result ProcsMap
|
decodeFuncs :: HD.Result RoutineMap
|
||||||
decodeProcs =
|
decodeFuncs =
|
||||||
-- Duplicate rows for a function means they're overloaded, order these by least args according to ProcDescription Ord instance
|
-- Duplicate rows for a function means they're overloaded, order these by least args according to Routine Ord instance
|
||||||
map sort . HM.fromListWith (++) . map ((\(x,y) -> (x, [y])) . addKey) <$> HD.rowList procRow
|
map sort . HM.fromListWith (++) . map ((\(x,y) -> (x, [y])) . addKey) <$> HD.rowList funcRow
|
||||||
where
|
where
|
||||||
procRow = ProcDescription
|
funcRow = Function
|
||||||
<$> column HD.text
|
<$> column HD.text
|
||||||
<*> column HD.text
|
<*> column HD.text
|
||||||
<*> nullableColumn HD.text
|
<*> nullableColumn HD.text
|
||||||
<*> compositeArrayColumn
|
<*> compositeArrayColumn
|
||||||
(ProcParam
|
(RoutineParam
|
||||||
<$> compositeField HD.text
|
<$> compositeField HD.text
|
||||||
<*> compositeField HD.text
|
<*> compositeField HD.text
|
||||||
<*> compositeField HD.bool
|
<*> compositeField HD.bool
|
||||||
@@ -253,7 +252,7 @@ decodeProcs =
|
|||||||
<*> (parseVolatility <$> column HD.char)
|
<*> (parseVolatility <$> column HD.char)
|
||||||
<*> column HD.bool
|
<*> column HD.bool
|
||||||
|
|
||||||
addKey :: ProcDescription -> (QualifiedIdentifier, ProcDescription)
|
addKey :: Routine -> (QualifiedIdentifier, Routine)
|
||||||
addKey pd = (QualifiedIdentifier (pdSchema pd) (pdName pd), pd)
|
addKey pd = (QualifiedIdentifier (pdSchema pd) (pdName pd), pd)
|
||||||
|
|
||||||
parseRetType :: Text -> Text -> Bool -> Bool -> Bool -> Bool -> RetType
|
parseRetType :: Text -> Text -> Bool -> Bool -> Bool -> Bool -> RetType
|
||||||
@@ -267,23 +266,23 @@ decodeProcs =
|
|||||||
| isComposite = Composite qi isCompositeAlias
|
| isComposite = Composite qi isCompositeAlias
|
||||||
| otherwise = Scalar False
|
| otherwise = Scalar False
|
||||||
|
|
||||||
parseVolatility :: Char -> ProcVolatility
|
parseVolatility :: Char -> FuncVolatility
|
||||||
parseVolatility v | v == 'i' = Immutable
|
parseVolatility v | v == 'i' = Immutable
|
||||||
| v == 's' = Stable
|
| v == 's' = Stable
|
||||||
| otherwise = Volatile -- only 'v' can happen here
|
| otherwise = Volatile -- only 'v' can happen here
|
||||||
|
|
||||||
allProcs :: PgVersion -> Bool -> SQL.Statement [Schema] ProcsMap
|
allFunctions :: PgVersion -> Bool -> SQL.Statement [Schema] RoutineMap
|
||||||
allProcs pgVer = SQL.Statement sql (arrayParam HE.text) decodeProcs
|
allFunctions pgVer = SQL.Statement sql (arrayParam HE.text) decodeFuncs
|
||||||
where
|
where
|
||||||
sql = procsSqlQuery pgVer <> " AND pn.nspname = ANY($1)"
|
sql = funcsSqlQuery pgVer <> " AND pn.nspname = ANY($1)"
|
||||||
|
|
||||||
accessibleProcs :: PgVersion -> Bool -> SQL.Statement Schema ProcsMap
|
accessibleFuncs :: PgVersion -> Bool -> SQL.Statement Schema RoutineMap
|
||||||
accessibleProcs pgVer = SQL.Statement sql (param HE.text) decodeProcs
|
accessibleFuncs pgVer = SQL.Statement sql (param HE.text) decodeFuncs
|
||||||
where
|
where
|
||||||
sql = procsSqlQuery pgVer <> " AND pn.nspname = $1 AND has_function_privilege(p.oid, 'execute')"
|
sql = funcsSqlQuery pgVer <> " AND pn.nspname = $1 AND has_function_privilege(p.oid, 'execute')"
|
||||||
|
|
||||||
procsSqlQuery :: PgVersion -> SqlQuery
|
funcsSqlQuery :: PgVersion -> SqlQuery
|
||||||
procsSqlQuery pgVer = [q|
|
funcsSqlQuery pgVer = [q|
|
||||||
-- Recursively get the base types of domains
|
-- Recursively get the base types of domains
|
||||||
WITH
|
WITH
|
||||||
base_types AS (
|
base_types AS (
|
||||||
|
|||||||
@@ -1,103 +0,0 @@
|
|||||||
{-# LANGUAGE DeriveAnyClass #-}
|
|
||||||
{-# LANGUAGE DeriveGeneric #-}
|
|
||||||
|
|
||||||
module PostgREST.SchemaCache.Proc
|
|
||||||
( PgType(..)
|
|
||||||
, ProcDescription(..)
|
|
||||||
, ProcParam(..)
|
|
||||||
, ProcVolatility(..)
|
|
||||||
, ProcsMap
|
|
||||||
, RetType(..)
|
|
||||||
, procReturnsScalar
|
|
||||||
, procReturnsSetOfScalar
|
|
||||||
, procReturnsSingleComposite
|
|
||||||
, procReturnsVoid
|
|
||||||
, procTableName
|
|
||||||
, procReturnsCompositeAlias
|
|
||||||
) where
|
|
||||||
|
|
||||||
import qualified Data.Aeson as JSON
|
|
||||||
import qualified Data.HashMap.Strict as HM
|
|
||||||
|
|
||||||
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..),
|
|
||||||
Schema, TableName)
|
|
||||||
|
|
||||||
import Protolude
|
|
||||||
|
|
||||||
data PgType
|
|
||||||
= Scalar Bool -- True if the type is void
|
|
||||||
| Composite QualifiedIdentifier Bool -- True if the composite is a domain alias(used to work around a bug in pg 11 and 12, see QueryBuilder.hs)
|
|
||||||
deriving (Eq, Ord, Generic, JSON.ToJSON)
|
|
||||||
|
|
||||||
data RetType
|
|
||||||
= Single PgType
|
|
||||||
| SetOf PgType
|
|
||||||
deriving (Eq, Ord, Generic, JSON.ToJSON)
|
|
||||||
|
|
||||||
data ProcVolatility
|
|
||||||
= Volatile
|
|
||||||
| Stable
|
|
||||||
| Immutable
|
|
||||||
deriving (Eq, Ord, Generic, JSON.ToJSON)
|
|
||||||
|
|
||||||
data ProcDescription = ProcDescription
|
|
||||||
{ pdSchema :: Schema
|
|
||||||
, pdName :: Text
|
|
||||||
, pdDescription :: Maybe Text
|
|
||||||
, pdParams :: [ProcParam]
|
|
||||||
, pdReturnType :: RetType
|
|
||||||
, pdVolatility :: ProcVolatility
|
|
||||||
, pdHasVariadic :: Bool
|
|
||||||
}
|
|
||||||
deriving (Eq, Generic, JSON.ToJSON)
|
|
||||||
|
|
||||||
data ProcParam = ProcParam
|
|
||||||
{ ppName :: Text
|
|
||||||
, ppType :: Text
|
|
||||||
, ppReq :: Bool
|
|
||||||
, ppVar :: Bool
|
|
||||||
}
|
|
||||||
deriving (Eq, Ord, Generic, JSON.ToJSON)
|
|
||||||
|
|
||||||
-- Order by least number of params in the case of overloaded functions
|
|
||||||
instance Ord ProcDescription where
|
|
||||||
ProcDescription schema1 name1 des1 prms1 rt1 vol1 hasVar1 `compare` ProcDescription schema2 name2 des2 prms2 rt2 vol2 hasVar2
|
|
||||||
| schema1 == schema2 && name1 == name2 && length prms1 < length prms2 = LT
|
|
||||||
| schema2 == schema2 && name1 == name2 && length prms1 > length prms2 = GT
|
|
||||||
| otherwise = (schema1, name1, des1, prms1, rt1, vol1, hasVar1) `compare` (schema2, name2, des2, prms2, rt2, vol2, hasVar2)
|
|
||||||
|
|
||||||
-- | A map of all procs, all of which can be overloaded(one entry will have more than one ProcDescription).
|
|
||||||
-- | It uses a HashMap for a faster lookup.
|
|
||||||
type ProcsMap = HM.HashMap QualifiedIdentifier [ProcDescription]
|
|
||||||
|
|
||||||
procReturnsScalar :: ProcDescription -> Bool
|
|
||||||
procReturnsScalar proc = case proc of
|
|
||||||
ProcDescription{pdReturnType = Single (Scalar _)} -> True
|
|
||||||
_ -> False
|
|
||||||
|
|
||||||
procReturnsSetOfScalar :: ProcDescription -> Bool
|
|
||||||
procReturnsSetOfScalar proc = case proc of
|
|
||||||
ProcDescription{pdReturnType = SetOf (Scalar _)} -> True
|
|
||||||
_ -> False
|
|
||||||
|
|
||||||
procReturnsCompositeAlias :: ProcDescription -> Bool
|
|
||||||
procReturnsCompositeAlias proc = case proc of
|
|
||||||
ProcDescription{pdReturnType = Single (Composite _ True)} -> True
|
|
||||||
ProcDescription{pdReturnType = SetOf (Composite _ True)} -> True
|
|
||||||
_ -> False
|
|
||||||
|
|
||||||
procReturnsSingleComposite :: ProcDescription -> Bool
|
|
||||||
procReturnsSingleComposite proc = case proc of
|
|
||||||
ProcDescription{pdReturnType = Single (Composite _ _)} -> True
|
|
||||||
_ -> False
|
|
||||||
|
|
||||||
procReturnsVoid :: ProcDescription -> Bool
|
|
||||||
procReturnsVoid proc = case proc of
|
|
||||||
ProcDescription{pdReturnType = Single (Scalar True)} -> True
|
|
||||||
_ -> False
|
|
||||||
|
|
||||||
procTableName :: ProcDescription -> Maybe TableName
|
|
||||||
procTableName proc = case pdReturnType proc of
|
|
||||||
SetOf (Composite qi _) -> Just $ qiName qi
|
|
||||||
Single (Composite qi _) -> Just $ qiName qi
|
|
||||||
_ -> Nothing
|
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
{-# LANGUAGE DeriveAnyClass #-}
|
||||||
|
{-# LANGUAGE DeriveGeneric #-}
|
||||||
|
|
||||||
|
module PostgREST.SchemaCache.Routine
|
||||||
|
( PgType(..)
|
||||||
|
, Routine(..)
|
||||||
|
, RoutineParam(..)
|
||||||
|
, FuncVolatility(..)
|
||||||
|
, RoutineMap
|
||||||
|
, RetType(..)
|
||||||
|
, funcReturnsScalar
|
||||||
|
, funcReturnsSetOfScalar
|
||||||
|
, funcReturnsSingleComposite
|
||||||
|
, funcReturnsVoid
|
||||||
|
, funcTableName
|
||||||
|
, funcReturnsCompositeAlias
|
||||||
|
) where
|
||||||
|
|
||||||
|
import qualified Data.Aeson as JSON
|
||||||
|
import qualified Data.HashMap.Strict as HM
|
||||||
|
|
||||||
|
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..),
|
||||||
|
Schema, TableName)
|
||||||
|
|
||||||
|
import Protolude
|
||||||
|
|
||||||
|
data PgType
|
||||||
|
= Scalar Bool -- True if the type is void
|
||||||
|
| Composite QualifiedIdentifier Bool -- True if the composite is a domain alias(used to work around a bug in pg 11 and 12, see QueryBuilder.hs)
|
||||||
|
deriving (Eq, Ord, Generic, JSON.ToJSON)
|
||||||
|
|
||||||
|
data RetType
|
||||||
|
= Single PgType
|
||||||
|
| SetOf PgType
|
||||||
|
deriving (Eq, Ord, Generic, JSON.ToJSON)
|
||||||
|
|
||||||
|
data FuncVolatility
|
||||||
|
= Volatile
|
||||||
|
| Stable
|
||||||
|
| Immutable
|
||||||
|
deriving (Eq, Ord, Generic, JSON.ToJSON)
|
||||||
|
|
||||||
|
data Routine = Function
|
||||||
|
{ pdSchema :: Schema
|
||||||
|
, pdName :: Text
|
||||||
|
, pdDescription :: Maybe Text
|
||||||
|
, pdParams :: [RoutineParam]
|
||||||
|
, pdReturnType :: RetType
|
||||||
|
, pdVolatility :: FuncVolatility
|
||||||
|
, pdHasVariadic :: Bool
|
||||||
|
}
|
||||||
|
deriving (Eq, Generic, JSON.ToJSON)
|
||||||
|
|
||||||
|
data RoutineParam = RoutineParam
|
||||||
|
{ ppName :: Text
|
||||||
|
, ppType :: Text
|
||||||
|
, ppReq :: Bool
|
||||||
|
, ppVar :: Bool
|
||||||
|
}
|
||||||
|
deriving (Eq, Ord, Generic, JSON.ToJSON)
|
||||||
|
|
||||||
|
-- Order by least number of params in the case of overloaded functions
|
||||||
|
instance Ord Routine where
|
||||||
|
Function schema1 name1 des1 prms1 rt1 vol1 hasVar1 `compare` Function schema2 name2 des2 prms2 rt2 vol2 hasVar2
|
||||||
|
| schema1 == schema2 && name1 == name2 && length prms1 < length prms2 = LT
|
||||||
|
| schema2 == schema2 && name1 == name2 && length prms1 > length prms2 = GT
|
||||||
|
| otherwise = (schema1, name1, des1, prms1, rt1, vol1, hasVar1) `compare` (schema2, name2, des2, prms2, rt2, vol2, hasVar2)
|
||||||
|
|
||||||
|
-- | A map of all procs, all of which can be overloaded(one entry will have more than one Routine).
|
||||||
|
-- | It uses a HashMap for a faster lookup.
|
||||||
|
type RoutineMap = HM.HashMap QualifiedIdentifier [Routine]
|
||||||
|
|
||||||
|
funcReturnsScalar :: Routine -> Bool
|
||||||
|
funcReturnsScalar proc = case proc of
|
||||||
|
Function{pdReturnType = Single (Scalar _)} -> True
|
||||||
|
_ -> False
|
||||||
|
|
||||||
|
funcReturnsSetOfScalar :: Routine -> Bool
|
||||||
|
funcReturnsSetOfScalar proc = case proc of
|
||||||
|
Function{pdReturnType = SetOf (Scalar _)} -> True
|
||||||
|
_ -> False
|
||||||
|
|
||||||
|
funcReturnsCompositeAlias :: Routine -> Bool
|
||||||
|
funcReturnsCompositeAlias proc = case proc of
|
||||||
|
Function{pdReturnType = Single (Composite _ True)} -> True
|
||||||
|
Function{pdReturnType = SetOf (Composite _ True)} -> True
|
||||||
|
_ -> False
|
||||||
|
|
||||||
|
funcReturnsSingleComposite :: Routine -> Bool
|
||||||
|
funcReturnsSingleComposite proc = case proc of
|
||||||
|
Function{pdReturnType = Single (Composite _ _)} -> True
|
||||||
|
_ -> False
|
||||||
|
|
||||||
|
funcReturnsVoid :: Routine -> Bool
|
||||||
|
funcReturnsVoid proc = case proc of
|
||||||
|
Function{pdReturnType = Single (Scalar True)} -> True
|
||||||
|
_ -> False
|
||||||
|
|
||||||
|
funcTableName :: Routine -> Maybe TableName
|
||||||
|
funcTableName proc = case pdReturnType proc of
|
||||||
|
SetOf (Composite qi _) -> Just $ qiName qi
|
||||||
|
Single (Composite qi _) -> Just $ qiName qi
|
||||||
|
_ -> Nothing
|
||||||
Reference in New Issue
Block a user