Fix proc resource embedding issue with search_path and refactor return type (#831)

This commit is contained in:
Steve Chávez
2017-03-20 23:50:42 -07:00
committed by Joe Nelson
parent 206ab163b6
commit 47b023e858
7 changed files with 143 additions and 32 deletions
+2 -3
View File
@@ -232,7 +232,7 @@ app dbStructure conf apiRequest =
uri Nothing = ("http", host, port, "/")
uri (Just Proxy { proxyScheme = s, proxyHost = h, proxyPort = p, proxyPath = b }) = (s, h, p, b)
uri' = uri proxy
encodeApi ti = encodeOpenAPI (map snd $ dbProcs dbStructure) ti uri'
encodeApi ti = encodeOpenAPI (M.elems $ dbProcs dbStructure) ti uri'
body <- encodeApi . toTableInfo <$> H.query schema accessibleTables
return $ responseLBS status200 [toHeader CTOpenAPI] $ toS body
@@ -264,8 +264,7 @@ app dbStructure conf apiRequest =
status = rangeStatus lower upper (toInteger <$> tableTotal)
in (status, contentRange)
mapSnd f (a, b) = (a, f b)
readReq = readRequest (configMaxRows conf) (dbRelations dbStructure) (map (mapSnd pdReturnType) $ dbProcs dbStructure) apiRequest
readReq = readRequest (configMaxRows conf) (dbRelations dbStructure) (dbProcs dbStructure) apiRequest
fldNames = fieldNames <$> readReq
readDbRequest = DbRead <$> readReq
mutateDbRequest = DbMutate <$> (mutateRequest apiRequest =<< fldNames)
+9 -9
View File
@@ -9,9 +9,9 @@ import Control.Applicative
import Control.Lens.Getter (view)
import Control.Lens.Tuple (_1)
import qualified Data.ByteString.Char8 as BS
import Data.List (delete, lookup)
import Data.List (delete)
import Data.Maybe (fromJust)
import Data.Text (isInfixOf, dropWhile, drop)
import Data.Text (isInfixOf)
import Data.Tree
import Data.Either.Combinators (mapLeft)
@@ -35,7 +35,7 @@ import Protolude hiding (from, dropWhile, drop)
import Text.Regex.TDFA ((=~))
import Unsafe (unsafeHead)
readRequest :: Maybe Integer -> [Relation] -> [(Text, Text)] -> ApiRequest -> Either Response ReadRequest
readRequest :: Maybe Integer -> [Relation] -> M.HashMap Text ProcDescription -> ApiRequest -> Either Response ReadRequest
readRequest maxRows allRels allProcs apiRequest =
mapLeft apiRequestError $
treeRestrictRange maxRows =<<
@@ -46,13 +46,13 @@ readRequest maxRows allRels allProcs apiRequest =
let target = iTarget apiRequest in
case target of
(TargetIdent (QualifiedIdentifier s t) ) -> Just (s, t)
(TargetProc (QualifiedIdentifier s p) ) -> Just (s, t)
(TargetProc (QualifiedIdentifier s proc) ) -> Just (s, tName)
where
returnType = fromMaybe "" $ lookup p allProcs
-- we are looking for results looking like "SETOF schema.tablename" and want to extract tablename
t = if "SETOF " `isInfixOf` returnType
then drop 1 $ dropWhile (/= '.') returnType
else p
retType = pdReturnType <$> M.lookup proc allProcs
tName = case retType of
Just (SetOf (Composite qi)) -> qiName qi
Just (Single (Composite qi)) -> qiName qi
_ -> proc
_ -> Nothing
+28 -10
View File
@@ -13,6 +13,7 @@ import qualified Hasql.Encoders as HE
import qualified Hasql.Query as H
import Control.Applicative
import qualified Data.HashMap.Strict as M
import Data.List (elemIndex)
import Data.Maybe (fromJust)
import Data.Text (split, strip,
@@ -96,12 +97,13 @@ decodeSynonyms cols =
<*> HD.value HD.text <*> HD.value HD.text
<*> HD.value HD.text <*> HD.value HD.text
accessibleProcs :: H.Query Schema [(Text, ProcDescription)]
accessibleProcs :: H.Query Schema (M.HashMap Text ProcDescription)
accessibleProcs =
H.statement sql (HE.value HE.text)
(map addName <$> HD.rowsList (ProcDescription <$> HD.value HD.text
(M.fromList . map addName <$> HD.rowsList (ProcDescription <$> HD.value HD.text
<*> (parseArgs <$> HD.value HD.text)
<*> HD.value HD.text)) True
<*> (parseRetType <$> HD.value HD.text <*> HD.value HD.text <*>
HD.value HD.bool <*> HD.value HD.char))) True
where
addName :: ProcDescription -> (Text, ProcDescription)
addName pd = (pdName pd, pd)
@@ -118,14 +120,30 @@ accessibleProcs =
else Just $
PgArg (dropAround (== '"') name) (strip typ) (T.null def)
parseRetType :: Text -> Text -> Bool -> Char -> RetType
parseRetType schema name isSetOf typ
| isSetOf = SetOf pgType
| otherwise = Single pgType
where
qi = QualifiedIdentifier schema name
pgType = case typ of
'c' -> Composite qi
'p' -> Pseudo name
_ -> Scalar qi -- 'b'ase, 'd'omain, 'e'num, 'r'ange
sql = [q|
SELECT p.proname as "proc_name",
pg_get_function_arguments(p.oid) as "args",
pg_get_function_result(p.oid) as "return_type"
FROM pg_namespace n
JOIN pg_proc p
ON pronamespace = n.oid
WHERE n.nspname = $1|]
SELECT p.proname as "proc_name",
pg_get_function_arguments(p.oid) as "args",
tn.nspname as "rettype_schema",
coalesce(comp.relname, t.typname) as "rettype_name",
p.proretset as "rettype_is_setof",
t.typtype as "rettype_typ"
FROM pg_proc p
JOIN pg_namespace pn ON pn.oid = p.pronamespace
JOIN pg_type t ON t.oid = p.prorettype
JOIN pg_namespace tn ON tn.oid = t.typnamespace
LEFT JOIN pg_class comp ON comp.oid = t.typrelid
WHERE pn.nspname = $1|]
accessibleTables :: H.Query Schema [Table]
accessibleTables =
+7 -2
View File
@@ -3,6 +3,7 @@ import Protolude
import qualified GHC.Show
import Data.Aeson
import qualified Data.ByteString.Lazy as BL
import Data.HashMap.Strict as M
import Data.Tree
import qualified Data.Vector as V
import PostgREST.RangeQuery (NonnegRange)
@@ -27,7 +28,7 @@ data DbStructure = DbStructure {
, dbColumns :: [Column]
, dbRelations :: [Relation]
, dbPrimaryKeys :: [PrimaryKey]
, dbProcs :: [(Text,ProcDescription)]
, dbProcs :: M.HashMap Text ProcDescription
} deriving (Show, Eq)
data PgArg = PgArg {
@@ -36,10 +37,14 @@ data PgArg = PgArg {
, pgaReq :: Bool
} deriving (Show, Eq)
data PgType = Scalar QualifiedIdentifier | Composite QualifiedIdentifier | Pseudo Text deriving (Eq, Show)
data RetType = Single PgType | SetOf PgType deriving (Eq, Show)
data ProcDescription = ProcDescription {
pdName :: Text
, pdArgs :: [PgArg]
, pdReturnType :: Text
, pdReturnType :: RetType
} deriving (Show, Eq)
type Schema = Text