From 5c372df4877af3e825df0158b45c3b556998690e Mon Sep 17 00:00:00 2001 From: steve-chavez Date: Wed, 14 Jun 2023 17:36:56 -0500 Subject: [PATCH] refactor: asJsonF/asJsonSingleF Routine param --- src/PostgREST/Query.hs | 17 +++++++---------- src/PostgREST/Query/SqlFragment.hs | 18 ++++++++++++++---- src/PostgREST/Query/Statements.hs | 17 +++++++++-------- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/PostgREST/Query.hs b/src/PostgREST/Query.hs index b72a0c772..c0f2097b5 100644 --- a/src/PostgREST/Query.hs +++ b/src/PostgREST/Query.hs @@ -28,12 +28,11 @@ import qualified Hasql.Encoders as HE import qualified Hasql.Statement as SQL import qualified Hasql.Transaction as SQL -import qualified PostgREST.Error as Error -import qualified PostgREST.Query.QueryBuilder as QueryBuilder -import qualified PostgREST.Query.Statements as Statements -import qualified PostgREST.RangeQuery as RangeQuery -import qualified PostgREST.SchemaCache as SchemaCache -import qualified PostgREST.SchemaCache.Routine as Routine +import qualified PostgREST.Error as Error +import qualified PostgREST.Query.QueryBuilder as QueryBuilder +import qualified PostgREST.Query.Statements as Statements +import qualified PostgREST.RangeQuery as RangeQuery +import qualified PostgREST.SchemaCache as SchemaCache import Data.Scientific (FPFormat (..), formatScientific, isInteger) @@ -153,13 +152,11 @@ deleteQuery mrPlan apiReq@ApiRequest{..} conf = do pure 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 <- lift . SQL.statement mempty $ Statements.prepareCall - (Routine.funcReturnsScalar proc) - (Routine.funcReturnsSingleComposite proc) - (Routine.funcReturnsSetOfScalar proc) + rout (QueryBuilder.callPlanToQuery crCallPlan pgVer) (QueryBuilder.readPlanToQuery crReadPlan) (QueryBuilder.readPlanToCountQuery crReadPlan) diff --git a/src/PostgREST/Query/SqlFragment.hs b/src/PostgREST/Query/SqlFragment.hs index be0e475eb..9e735e94c 100644 --- a/src/PostgREST/Query/SqlFragment.hs +++ b/src/PostgREST/Query/SqlFragment.hs @@ -80,6 +80,10 @@ import PostgREST.RangeQuery (NonnegRange, allRange, rangeLimit, rangeOffset) import PostgREST.SchemaCache.Identifiers (FieldName, QualifiedIdentifier (..)) +import PostgREST.SchemaCache.Routine (Routine (..), + funcReturnsScalar, + funcReturnsSetOfScalar, + funcReturnsSingleComposite) 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'), '')" -asJsonSingleF :: Bool -> SqlFragment -asJsonSingleF returnsScalar +asJsonSingleF :: Maybe Routine -> SqlFragment +asJsonSingleF rout | returnsScalar = "coalesce(json_agg(_postgrest_t.pgrst_scalar)->0, 'null')" | otherwise = "coalesce(json_agg(_postgrest_t)->0, 'null')" + where + returnsScalar = maybe False funcReturnsScalar rout -asJsonF :: Bool -> Bool -> Bool -> SqlFragment -asJsonF returnsScalar returnsSetOfScalar returnsSingleComposite +asJsonF :: Maybe Routine -> SqlFragment +asJsonF rout | 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), '[]')" + where + (returnsSingleComposite, returnsScalar, returnsSetOfScalar) = case rout of + Just r -> (funcReturnsSingleComposite r, funcReturnsScalar r, funcReturnsSetOfScalar r) + Nothing -> (False, False, False) asXmlF :: FieldName -> SqlFragment asXmlF fieldName = "coalesce(xmlagg(_postgrest_t." <> pgFmtIdent fieldName <> "), '')" diff --git a/src/PostgREST/Query/Statements.hs b/src/PostgREST/Query/Statements.hs index 145d3ce0f..99e5ef5cc 100644 --- a/src/PostgREST/Query/Statements.hs +++ b/src/PostgREST/Query/Statements.hs @@ -32,6 +32,7 @@ import PostgREST.MediaType (MTPlanAttrs (..), getMediaType) import PostgREST.Query.SqlFragment import PostgREST.SchemaCache.Identifiers (FieldName) +import PostgREST.SchemaCache.Routine (Routine) import Protolude @@ -86,8 +87,8 @@ prepareWrite selectQuery mutateQuery isInsert mt rep pKeys = | rep /= Full = "''" | getMediaType mt == MTTextCSV = asCsvF | getMediaType mt == MTGeoJSON = asGeoJsonF - | getMediaType mt == MTSingularJSON = asJsonSingleF False - | otherwise = asJsonF False False False + | getMediaType mt == MTSingularJSON = asJsonSingleF Nothing + | otherwise = asJsonF Nothing selectF -- 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 | getMediaType mt == MTTextCSV = asCsvF - | getMediaType mt == MTSingularJSON = asJsonSingleF False + | getMediaType mt == MTSingularJSON = asJsonSingleF Nothing | getMediaType mt == MTGeoJSON = asGeoJsonF | isJust binaryField && getMediaType mt == MTTextXML = asXmlF $ fromJust binaryField | isJust binaryField = asBinaryF $ fromJust binaryField - | otherwise = asJsonF False False False + | otherwise = asJsonF Nothing decodeIt :: HD.Result ResultSet decodeIt = case mt of MTPlan{} -> planRow _ -> 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 -> 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 where snippet = @@ -151,12 +152,12 @@ prepareCall returnsScalar returnsSingleComposite returnsSetOfScalar callProcQuer (countCTEF, countResultF) = countF countQuery countTotal bodyF - | getMediaType mt == MTSingularJSON = asJsonSingleF returnsScalar + | getMediaType mt == MTSingularJSON = asJsonSingleF $ Just rout | getMediaType mt == MTTextCSV = asCsvF | getMediaType mt == MTGeoJSON = asGeoJsonF | isJust binaryField && getMediaType mt == MTTextXML = asXmlF $ fromJust binaryField | isJust binaryField = asBinaryF $ fromJust binaryField - | otherwise = asJsonF returnsScalar returnsSetOfScalar returnsSingleComposite + | otherwise = asJsonF $ Just rout decodeIt :: HD.Result ResultSet decodeIt = case mt of