From ecd58e1ad20956dbc7435cd177770335f5a75b4e Mon Sep 17 00:00:00 2001 From: steve-chavez Date: Sat, 24 Jun 2017 20:18:40 -0500 Subject: [PATCH] Refactor rpc to not use count when returning scalar --- src/PostgREST/App.hs | 11 ++++++++--- src/PostgREST/DbStructure.hs | 4 +++- src/PostgREST/QueryBuilder.hs | 33 +++++++++++++++++---------------- src/PostgREST/Types.hs | 2 +- 4 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/PostgREST/App.hs b/src/PostgREST/App.hs index c2dd7e8bd..7ebff9960 100644 --- a/src/PostgREST/App.hs +++ b/src/PostgREST/App.hs @@ -238,8 +238,12 @@ app dbStructure conf apiRequest = let p = V.head payload singular = contentType == CTSingularJSON paramsAsSingleObject = iPreferSingleObjectParameter apiRequest + proc = M.lookup (qiName qi) allProcs + returnsScalar = case proc of + Just ProcDescription{pdReturnType = (Single (Scalar _))} -> True + _ -> False row <- H.query () $ - callProc qi p q cq topLevelRange shouldCount singular + callProc qi p returnsScalar q cq topLevelRange shouldCount singular paramsAsSingleObject (contentType == CTTextCSV) let (tableTotal, queryTotal, body) = fromMaybe (Just 0, 0, "[]") row @@ -257,7 +261,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 (M.elems $ dbProcs dbStructure) ti uri' + encodeApi ti = encodeOpenAPI (M.elems allProcs) ti uri' body <- encodeApi . toTableInfo <$> H.query schema accessibleTables return $ responseLBS status200 [toHeader CTOpenAPI] $ toS body @@ -276,6 +280,7 @@ app dbStructure conf apiRequest = filterCol :: Schema -> TableName -> Column -> Bool filterCol sc tb Column{colTable=Table{tableSchema=s, tableName=t}} = s==sc && t==tb allPrKeys = dbPrimaryKeys dbStructure + allProcs = dbProcs dbStructure allOrigins = ("Access-Control-Allow-Origin", "*") :: Header shouldCount = iPreferCount apiRequest schema = toS $ configSchema conf @@ -287,7 +292,7 @@ app dbStructure conf apiRequest = status = rangeStatus lower upper (toInteger <$> tableTotal) in (status, contentRange) - readReq = readRequest (configMaxRows conf) (dbRelations dbStructure) (dbProcs dbStructure) apiRequest + readReq = readRequest (configMaxRows conf) (dbRelations dbStructure) allProcs apiRequest fldNames = fieldNames <$> readReq readDbRequest = DbRead <$> readReq mutateDbRequest = DbMutate <$> (mutateRequest apiRequest =<< fldNames) diff --git a/src/PostgREST/DbStructure.hs b/src/PostgREST/DbStructure.hs index faf779f62..7438b2565 100644 --- a/src/PostgREST/DbStructure.hs +++ b/src/PostgREST/DbStructure.hs @@ -137,7 +137,9 @@ accessibleProcs = qi = QualifiedIdentifier schema name pgType = case typ of 'c' -> Composite qi - 'p' -> Pseudo name + 'p' -> if name == "record" -- Only pg pseudo type that is a row type is 'record' + then Composite qi + else Scalar qi _ -> Scalar qi -- 'b'ase, 'd'omain, 'e'num, 'r'ange parseVolatility :: Char -> ProcVolatility diff --git a/src/PostgREST/QueryBuilder.hs b/src/PostgREST/QueryBuilder.hs index 35be26a4e..d82dbe37f 100644 --- a/src/PostgREST/QueryBuilder.hs +++ b/src/PostgREST/QueryBuilder.hs @@ -144,26 +144,27 @@ createWriteStatement selectQuery mutateQuery wantSingle wantHdrs asCsv rep pKeys | otherwise = asJsonF type ProcResults = (Maybe Int64, Int64, ByteString) -callProc :: QualifiedIdentifier -> JSON.Object -> SqlQuery -> SqlQuery -> NonnegRange -> +callProc :: QualifiedIdentifier -> JSON.Object -> Bool -> SqlQuery -> SqlQuery -> NonnegRange -> Bool -> Bool -> Bool -> Bool -> H.Query () (Maybe ProcResults) -callProc qi params selectQuery countQuery _ countTotal isSingle paramsAsJson asCsv = +callProc qi params returnsScalar selectQuery countQuery _ countTotal isSingle paramsAsJson asCsv = unicodeStatement sql HE.unit decodeProc True where - sql = [qc| - WITH {sourceCTEName} AS ({_callSql}) - SELECT - {countResultF} AS total_result_set, - pg_catalog.count(_postgrest_t) AS page_total, - case - when pg_catalog.count(*) > 1 then - {bodyF} - else - coalesce(((array_agg(row_to_json(_postgrest_t)))[1]->{_procName})::character varying, {bodyF}) + sql = + if returnsScalar then [qc| + WITH {sourceCTEName} AS ({_callSql}) + SELECT + {countResultF} AS total_result_set, + 1 AS page_total, + (row_to_json(_postgrest_t)->{_procName})::character varying as body + FROM ({selectQuery}) _postgrest_t;|] + else [qc| + WITH {sourceCTEName} AS ({_callSql}) + SELECT + {countResultF} AS total_result_set, + pg_catalog.count(_postgrest_t) AS page_total, + {bodyF} as body + FROM ({selectQuery}) _postgrest_t;|] - end as body - FROM ({selectQuery}) _postgrest_t; - |] - -- FROM (select * from {sourceCTEName} {limitF range}) t; countResultF = if countTotal then "("<>countQuery<>")" else "null::bigint" :: Text _args = if paramsAsJson then insertableValueWithType "json" $ JSON.Object params diff --git a/src/PostgREST/Types.hs b/src/PostgREST/Types.hs index d63305edc..3c20cb549 100644 --- a/src/PostgREST/Types.hs +++ b/src/PostgREST/Types.hs @@ -38,7 +38,7 @@ data PgArg = PgArg { , pgaReq :: Bool } deriving (Show, Eq) -data PgType = Scalar QualifiedIdentifier | Composite QualifiedIdentifier | Pseudo Text deriving (Eq, Show) +data PgType = Scalar QualifiedIdentifier | Composite QualifiedIdentifier deriving (Eq, Show) data RetType = Single PgType | SetOf PgType deriving (Eq, Show)