refactor: asJsonF/asJsonSingleF Routine param

This commit is contained in:
steve-chavez
2023-06-16 17:36:44 -05:00
committed by Steve Chavez
parent fad47324c3
commit 5c372df487
3 changed files with 30 additions and 22 deletions
+7 -10
View File
@@ -28,12 +28,11 @@ 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.Routine as Routine
import Data.Scientific (FPFormat (..), formatScientific, isInteger) import Data.Scientific (FPFormat (..), formatScientific, isInteger)
@@ -153,13 +152,11 @@ deleteQuery mrPlan apiReq@ApiRequest{..} conf = do
pure resultSet pure resultSet
invokeQuery :: Routine -> 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 rout 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
(Routine.funcReturnsScalar proc) rout
(Routine.funcReturnsSingleComposite proc)
(Routine.funcReturnsSetOfScalar proc)
(QueryBuilder.callPlanToQuery crCallPlan pgVer) (QueryBuilder.callPlanToQuery crCallPlan pgVer)
(QueryBuilder.readPlanToQuery crReadPlan) (QueryBuilder.readPlanToQuery crReadPlan)
(QueryBuilder.readPlanToCountQuery crReadPlan) (QueryBuilder.readPlanToCountQuery crReadPlan)
+14 -4
View File
@@ -80,6 +80,10 @@ import PostgREST.RangeQuery (NonnegRange, allRange,
rangeLimit, rangeOffset) rangeLimit, rangeOffset)
import PostgREST.SchemaCache.Identifiers (FieldName, import PostgREST.SchemaCache.Identifiers (FieldName,
QualifiedIdentifier (..)) QualifiedIdentifier (..))
import PostgREST.SchemaCache.Routine (Routine (..),
funcReturnsScalar,
funcReturnsSetOfScalar,
funcReturnsSingleComposite)
import Protolude hiding (cast) import Protolude hiding (cast)
@@ -183,17 +187,23 @@ 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'), '')"
asJsonSingleF :: Bool -> SqlFragment asJsonSingleF :: Maybe Routine -> SqlFragment
asJsonSingleF returnsScalar asJsonSingleF rout
| 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')"
where
returnsScalar = maybe False funcReturnsScalar rout
asJsonF :: Bool -> Bool -> Bool -> SqlFragment asJsonF :: Maybe Routine -> SqlFragment
asJsonF returnsScalar returnsSetOfScalar returnsSingleComposite asJsonF rout
| returnsSingleComposite = "coalesce(json_agg(_postgrest_t)->0, 'null')" | returnsSingleComposite = "coalesce(json_agg(_postgrest_t)->0, 'null')"
| returnsScalar = "coalesce(json_agg(_postgrest_t.pgrst_scalar)->0, 'null')" | returnsScalar = "coalesce(json_agg(_postgrest_t.pgrst_scalar)->0, 'null')"
| returnsSetOfScalar = "coalesce(json_agg(_postgrest_t.pgrst_scalar), '[]')" | returnsSetOfScalar = "coalesce(json_agg(_postgrest_t.pgrst_scalar), '[]')"
| otherwise = "coalesce(json_agg(_postgrest_t), '[]')" | otherwise = "coalesce(json_agg(_postgrest_t), '[]')"
where
(returnsSingleComposite, returnsScalar, returnsSetOfScalar) = case rout of
Just r -> (funcReturnsSingleComposite r, funcReturnsScalar r, funcReturnsSetOfScalar r)
Nothing -> (False, False, False)
asXmlF :: FieldName -> SqlFragment asXmlF :: FieldName -> SqlFragment
asXmlF fieldName = "coalesce(xmlagg(_postgrest_t." <> pgFmtIdent fieldName <> "), '')" asXmlF fieldName = "coalesce(xmlagg(_postgrest_t." <> pgFmtIdent fieldName <> "), '')"
+9 -8
View File
@@ -32,6 +32,7 @@ import PostgREST.MediaType (MTPlanAttrs (..),
getMediaType) getMediaType)
import PostgREST.Query.SqlFragment import PostgREST.Query.SqlFragment
import PostgREST.SchemaCache.Identifiers (FieldName) import PostgREST.SchemaCache.Identifiers (FieldName)
import PostgREST.SchemaCache.Routine (Routine)
import Protolude import Protolude
@@ -86,8 +87,8 @@ prepareWrite selectQuery mutateQuery isInsert mt rep pKeys =
| rep /= Full = "''" | rep /= Full = "''"
| 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 Nothing
| otherwise = asJsonF False False False | otherwise = asJsonF Nothing
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
@@ -119,21 +120,21 @@ prepareRead selectQuery countQuery countTotal mt binaryField =
bodyF bodyF
| getMediaType mt == MTTextCSV = asCsvF | getMediaType mt == MTTextCSV = asCsvF
| getMediaType mt == MTSingularJSON = asJsonSingleF False | getMediaType mt == MTSingularJSON = asJsonSingleF Nothing
| 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 False False | otherwise = asJsonF Nothing
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 -> Bool -> SQL.Snippet -> SQL.Snippet -> SQL.Snippet -> Bool -> prepareCall :: Routine -> SQL.Snippet -> SQL.Snippet -> SQL.Snippet -> Bool ->
MediaType -> Maybe FieldName -> Bool -> MediaType -> Maybe FieldName -> Bool ->
SQL.Statement () ResultSet SQL.Statement () ResultSet
prepareCall returnsScalar returnsSingleComposite returnsSetOfScalar callProcQuery selectQuery countQuery countTotal mt binaryField = prepareCall rout callProcQuery selectQuery countQuery countTotal mt binaryField =
SQL.dynamicallyParameterized (mtSnippet mt snippet) decodeIt SQL.dynamicallyParameterized (mtSnippet mt snippet) decodeIt
where where
snippet = snippet =
@@ -151,12 +152,12 @@ prepareCall returnsScalar returnsSingleComposite returnsSetOfScalar callProcQuer
(countCTEF, countResultF) = countF countQuery countTotal (countCTEF, countResultF) = countF countQuery countTotal
bodyF bodyF
| getMediaType mt == MTSingularJSON = asJsonSingleF returnsScalar | getMediaType mt == MTSingularJSON = asJsonSingleF $ Just rout
| getMediaType mt == MTTextCSV = asCsvF | getMediaType mt == MTTextCSV = asCsvF
| 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 returnsScalar returnsSetOfScalar returnsSingleComposite | otherwise = asJsonF $ Just rout
decodeIt :: HD.Result ResultSet decodeIt :: HD.Result ResultSet
decodeIt = case mt of decodeIt = case mt of