refactor: wrap proc logic in asJsonF

* add explicit logic for returning setof scalars
This commit is contained in:
steve-chavez
2023-04-04 19:55:10 -05:00
committed by Steve Chavez
parent d945e8c06a
commit 16f2849724
7 changed files with 41 additions and 30 deletions
+5 -2
View File
@@ -56,7 +56,8 @@ import PostgREST.SchemaCache.Identifiers (FieldName,
Schema) Schema)
import PostgREST.SchemaCache.Proc (ProcDescription (..), import PostgREST.SchemaCache.Proc (ProcDescription (..),
ProcParam (..), ProcsMap, ProcParam (..), ProcsMap,
procReturnsScalar) procReturnsScalar,
procReturnsSetOfScalar)
import PostgREST.SchemaCache.Relationship (Cardinality (..), import PostgREST.SchemaCache.Relationship (Cardinality (..),
Junction (..), Junction (..),
Relationship (..), Relationship (..),
@@ -548,6 +549,7 @@ callPlan proc ApiRequest{iPreferences=Preferences{..}} paramKeys args readReq =
, funCParams = callParams , funCParams = callParams
, funCArgs = Just args , funCArgs = Just args
, funCScalar = procReturnsScalar proc , funCScalar = procReturnsScalar proc
, funCSetOfScalar = procReturnsSetOfScalar proc
, funCReturning = inferColsEmbedNeeds readReq [] , funCReturning = inferColsEmbedNeeds readReq []
} }
where where
@@ -615,7 +617,8 @@ addFilterToLogicForest flt lf = Stmnt flt : lf
binaryField :: AppConfig -> MediaType -> Maybe ProcDescription -> ReadPlanTree -> Either ApiRequestError (Maybe FieldName) binaryField :: AppConfig -> MediaType -> Maybe ProcDescription -> 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 (procReturnsScalar <$> proc) == Just True ||
(procReturnsSetOfScalar <$> proc) == Just True
then Right $ Just "pgrst_scalar" then Right $ Just "pgrst_scalar"
else else
let let
+1
View File
@@ -21,6 +21,7 @@ data CallPlan = FunctionCall
, funCParams :: CallParams , funCParams :: CallParams
, funCArgs :: Maybe LBS.ByteString , funCArgs :: Maybe LBS.ByteString
, funCScalar :: Bool , funCScalar :: Bool
, funCSetOfScalar :: Bool
, funCReturning :: [FieldName] , funCReturning :: [FieldName]
} }
+2 -1
View File
@@ -158,7 +158,8 @@ invokeQuery proc CallReadPlan{crReadPlan, crCallPlan, crBinField} apiReq@ApiRequ
lift . SQL.statement mempty $ lift . SQL.statement mempty $
Statements.prepareCall Statements.prepareCall
(Proc.procReturnsScalar proc) (Proc.procReturnsScalar proc)
(Proc.procReturnsSingle proc) (Proc.procReturnsSingleComposite proc)
(Proc.procReturnsSetOfScalar proc)
(QueryBuilder.callPlanToQuery crCallPlan) (QueryBuilder.callPlanToQuery crCallPlan)
(QueryBuilder.readPlanToQuery crReadPlan) (QueryBuilder.readPlanToQuery crReadPlan)
(QueryBuilder.readPlanToCountQuery crReadPlan) (QueryBuilder.readPlanToCountQuery crReadPlan)
+2 -2
View File
@@ -164,8 +164,8 @@ mutatePlanToQuery (Delete mainQi logicForest range ordts returnings)
(whereRangeIdF, rangeIdF) = mutRangeF mainQi (fst . otTerm <$> ordts) (whereRangeIdF, rangeIdF) = mutRangeF mainQi (fst . otTerm <$> ordts)
callPlanToQuery :: CallPlan -> SQL.Snippet callPlanToQuery :: CallPlan -> SQL.Snippet
callPlanToQuery (FunctionCall qi params args returnsScalar returnings) = callPlanToQuery (FunctionCall qi params args returnsScalar returnsSetOfScalar returnings) =
"SELECT " <> (if returnsScalar then "pgrst_call AS pgrst_scalar " else returnedColumns) <> " " <> "SELECT " <> (if returnsScalar || returnsSetOfScalar then "pgrst_call AS pgrst_scalar " else returnedColumns) <> " " <>
fromCall fromCall
where where
fromCall = case params of fromCall = case params of
+7 -5
View File
@@ -178,16 +178,18 @@ asCsvF = asCsvHeaderF <> " || '\n' || " <> asCsvBodyF
")" ")"
asCsvBodyF = "coalesce(string_agg(substring(_postgrest_t::text, 2, length(_postgrest_t::text) - 2), '\n'), '')" asCsvBodyF = "coalesce(string_agg(substring(_postgrest_t::text, 2, length(_postgrest_t::text) - 2), '\n'), '')"
asJsonF :: Bool -> SqlFragment
asJsonF returnsScalar
| returnsScalar = "coalesce(json_agg(_postgrest_t.pgrst_scalar), '[]')"
| otherwise = "coalesce(json_agg(_postgrest_t), '[]')"
asJsonSingleF :: Bool -> SqlFragment asJsonSingleF :: Bool -> SqlFragment
asJsonSingleF returnsScalar asJsonSingleF returnsScalar
| returnsScalar = "coalesce(json_agg(_postgrest_t.pgrst_scalar)->0, 'null')" | returnsScalar = "coalesce(json_agg(_postgrest_t.pgrst_scalar)->0, 'null')"
| otherwise = "coalesce(json_agg(_postgrest_t)->0, 'null')" | otherwise = "coalesce(json_agg(_postgrest_t)->0, 'null')"
asJsonF :: Bool -> Bool -> Bool -> SqlFragment
asJsonF returnsScalar returnsSetOfScalar returnsSingleComposite
| returnsSingleComposite = "coalesce(json_agg(_postgrest_t)->0, 'null')"
| returnsScalar = "coalesce(json_agg(_postgrest_t.pgrst_scalar)->0, 'null')"
| returnsSetOfScalar = "coalesce(json_agg(_postgrest_t.pgrst_scalar), '[]')"
| otherwise = "coalesce(json_agg(_postgrest_t), '[]')"
asXmlF :: FieldName -> SqlFragment asXmlF :: FieldName -> SqlFragment
asXmlF fieldName = "coalesce(xmlagg(_postgrest_t." <> pgFmtIdent fieldName <> "), '')" asXmlF fieldName = "coalesce(xmlagg(_postgrest_t." <> pgFmtIdent fieldName <> "), '')"
+5 -6
View File
@@ -87,7 +87,7 @@ prepareWrite selectQuery mutateQuery isInsert mt rep pKeys =
| getMediaType mt == MTTextCSV = asCsvF | getMediaType mt == MTTextCSV = asCsvF
| getMediaType mt == MTGeoJSON = asGeoJsonF | getMediaType mt == MTGeoJSON = asGeoJsonF
| getMediaType mt == MTSingularJSON = asJsonSingleF False | getMediaType mt == MTSingularJSON = asJsonSingleF False
| otherwise = asJsonF False | otherwise = asJsonF False False False
selectF selectF
-- prevent using any of the column names in ?select= when no response is returned from the CTE -- prevent using any of the column names in ?select= when no response is returned from the CTE
@@ -123,17 +123,17 @@ prepareRead selectQuery countQuery countTotal mt binaryField =
| getMediaType mt == MTGeoJSON = asGeoJsonF | getMediaType mt == MTGeoJSON = asGeoJsonF
| isJust binaryField && getMediaType mt == MTTextXML = asXmlF $ fromJust binaryField | isJust binaryField && getMediaType mt == MTTextXML = asXmlF $ fromJust binaryField
| isJust binaryField = asBinaryF $ fromJust binaryField | isJust binaryField = asBinaryF $ fromJust binaryField
| otherwise = asJsonF False | otherwise = asJsonF False False False
decodeIt :: HD.Result ResultSet decodeIt :: HD.Result ResultSet
decodeIt = case mt of decodeIt = case mt of
MTPlan{} -> planRow MTPlan{} -> planRow
_ -> HD.singleRow $ standardRow True _ -> HD.singleRow $ standardRow True
prepareCall :: Bool -> Bool -> SQL.Snippet -> SQL.Snippet -> SQL.Snippet -> Bool -> prepareCall :: Bool -> Bool -> Bool -> SQL.Snippet -> SQL.Snippet -> SQL.Snippet -> Bool ->
MediaType -> Maybe FieldName -> Bool -> MediaType -> Maybe FieldName -> Bool ->
SQL.Statement () ResultSet SQL.Statement () ResultSet
prepareCall returnsScalar returnsSingle callProcQuery selectQuery countQuery countTotal mt binaryField = prepareCall returnsScalar returnsSingleComposite returnsSetOfScalar callProcQuery selectQuery countQuery countTotal mt binaryField =
SQL.dynamicallyParameterized (mtSnippet mt snippet) decodeIt SQL.dynamicallyParameterized (mtSnippet mt snippet) decodeIt
where where
snippet = snippet =
@@ -156,8 +156,7 @@ prepareCall returnsScalar returnsSingle callProcQuery selectQuery countQuery cou
| getMediaType mt == MTGeoJSON = asGeoJsonF | getMediaType mt == MTGeoJSON = asGeoJsonF
| isJust binaryField && getMediaType mt == MTTextXML = asXmlF $ fromJust binaryField | isJust binaryField && getMediaType mt == MTTextXML = asXmlF $ fromJust binaryField
| isJust binaryField = asBinaryF $ fromJust binaryField | isJust binaryField = asBinaryF $ fromJust binaryField
| returnsSingle = asJsonSingleF returnsScalar | otherwise = asJsonF returnsScalar returnsSetOfScalar returnsSingleComposite
| otherwise = asJsonF returnsScalar
decodeIt :: HD.Result ResultSet decodeIt :: HD.Result ResultSet
decodeIt = case mt of decodeIt = case mt of
+9 -4
View File
@@ -9,7 +9,8 @@ module PostgREST.SchemaCache.Proc
, ProcsMap , ProcsMap
, RetType(..) , RetType(..)
, procReturnsScalar , procReturnsScalar
, procReturnsSingle , procReturnsSetOfScalar
, procReturnsSingleComposite
, procReturnsVoid , procReturnsVoid
, procTableName , procTableName
) where ) where
@@ -71,12 +72,16 @@ type ProcsMap = HM.HashMap QualifiedIdentifier [ProcDescription]
procReturnsScalar :: ProcDescription -> Bool procReturnsScalar :: ProcDescription -> Bool
procReturnsScalar proc = case proc of procReturnsScalar proc = case proc of
ProcDescription{pdReturnType = Single (Scalar _)} -> True ProcDescription{pdReturnType = Single (Scalar _)} -> True
_ -> False
procReturnsSetOfScalar :: ProcDescription -> Bool
procReturnsSetOfScalar proc = case proc of
ProcDescription{pdReturnType = SetOf (Scalar _)} -> True ProcDescription{pdReturnType = SetOf (Scalar _)} -> True
_ -> False _ -> False
procReturnsSingle :: ProcDescription -> Bool procReturnsSingleComposite :: ProcDescription -> Bool
procReturnsSingle proc = case proc of procReturnsSingleComposite proc = case proc of
ProcDescription{pdReturnType = Single _} -> True ProcDescription{pdReturnType = Single (Composite _)} -> True
_ -> False _ -> False
procReturnsVoid :: ProcDescription -> Bool procReturnsVoid :: ProcDescription -> Bool