Applies range headers to /rpc calls using LIMIT/OFFSET.
This commit is contained in:
+14
-13
@@ -71,13 +71,10 @@ app dbStructure conf reqBody req =
|
||||
case readSqlParts of
|
||||
Left e -> return $ responseLBS status400 [jsonH] $ cs e
|
||||
Right (q, cq) -> do
|
||||
let range = restrictRange (configMaxRows conf) $ iRange apiRequest
|
||||
singular = iPreferSingular apiRequest
|
||||
let singular = iPreferSingular apiRequest
|
||||
stm = createReadStatement q cq range singular
|
||||
(iPreferCount apiRequest) (contentType == TextCSV)
|
||||
if range == emptyRange
|
||||
then return $ errResponse status416 "HTTP Range error"
|
||||
else do
|
||||
respondToRange $ do
|
||||
row <- H.query () stm
|
||||
let (tableTotal, queryTotal, _ , body) = row
|
||||
if singular
|
||||
@@ -165,14 +162,14 @@ app dbStructure conf reqBody req =
|
||||
then do
|
||||
let p = V.head payload
|
||||
jwtSecret = configJwtSecret conf
|
||||
|
||||
bodyJson <- H.query () (callProc qi p)
|
||||
returnJWT <- H.query qi doesProcReturnJWT
|
||||
return $ responseLBS status200 [jsonH]
|
||||
(let body = fromMaybe emptyArray bodyJson in
|
||||
if returnJWT
|
||||
then "{\"token\":\"" <> cs (tokenJWT jwtSecret body) <> "\"}"
|
||||
else cs $ encode body)
|
||||
respondToRange $ do
|
||||
bodyJson <- H.query () (callProc qi p range)
|
||||
returnJWT <- H.query qi doesProcReturnJWT
|
||||
return $ responseLBS status200 [jsonH]
|
||||
(let body = fromMaybe emptyArray bodyJson in
|
||||
if returnJWT
|
||||
then "{\"token\":\"" <> cs (tokenJWT jwtSecret body) <> "\"}"
|
||||
else cs $ encode body)
|
||||
else return notFound
|
||||
|
||||
(ActionRead, TargetRoot, Nothing) -> do
|
||||
@@ -196,6 +193,7 @@ app dbStructure conf reqBody req =
|
||||
allOrigins = ("Access-Control-Allow-Origin", "*") :: Header
|
||||
schema = cs $ configSchema conf
|
||||
apiRequest = userApiRequest schema req reqBody
|
||||
range = restrictRange (configMaxRows conf) $ iRange apiRequest
|
||||
readDbRequest = DbRead <$> buildReadRequest (dbRelations dbStructure) apiRequest
|
||||
mutateDbRequest = DbMutate <$> buildMutateRequest apiRequest
|
||||
selectQuery = requestToQuery schema <$> readDbRequest
|
||||
@@ -203,6 +201,9 @@ app dbStructure conf reqBody req =
|
||||
mutateQuery = requestToQuery schema <$> mutateDbRequest
|
||||
readSqlParts = (,) <$> selectQuery <*> countQuery
|
||||
mutateSqlParts = (,) <$> selectQuery <*> mutateQuery
|
||||
respondToRange response = if range == emptyRange
|
||||
then return $ errResponse status416 "HTTP Range error"
|
||||
else response
|
||||
|
||||
rangeStatus :: Integer -> Integer -> Maybe Integer -> Status
|
||||
rangeStatus _ _ Nothing = status200
|
||||
|
||||
@@ -30,7 +30,6 @@ import System.IO (BufferMode (..),
|
||||
hSetBuffering, stderr,
|
||||
stdin, stdout)
|
||||
import Web.JWT (secret)
|
||||
|
||||
#ifndef mingw32_HOST_OS
|
||||
import System.Posix.Signals
|
||||
import Control.Concurrent (myThreadId)
|
||||
@@ -64,7 +63,6 @@ main = do
|
||||
Prelude.putStrLn $ "Listening on port " ++
|
||||
(show $ configPort conf :: String)
|
||||
|
||||
|
||||
pool <- P.acquire (configPool conf, 10, pgSettings)
|
||||
|
||||
#ifndef mingw32_HOST_OS
|
||||
|
||||
@@ -203,8 +203,8 @@ addJoinConditions schema (Node (query, (n, r)) forest) =
|
||||
updatedForest = mapM (addJoinConditions schema) forest
|
||||
addCond query' con = query'{flt_=con ++ flt_ query'}
|
||||
|
||||
callProc :: QualifiedIdentifier -> JSON.Object -> H.Query () (Maybe JSON.Value)
|
||||
callProc qi params =
|
||||
callProc :: QualifiedIdentifier -> JSON.Object -> NonnegRange -> H.Query () (Maybe JSON.Value)
|
||||
callProc qi params range =
|
||||
H.statement sql HE.unit decodeObj True
|
||||
where
|
||||
sql = [qc| SELECT array_to_json(
|
||||
@@ -213,7 +213,7 @@ callProc qi params =
|
||||
from ({_callSql}) t |]
|
||||
_args = intercalate "," $ map _assignment (HM.toList params)
|
||||
_assignment (n,v) = pgFmtIdent n <> ":=" <> insertableValue v
|
||||
_callSql = [qc| select * from {fromQi qi}({_args}) |] :: BS.ByteString
|
||||
_callSql = [qc| select * from {fromQi qi}({_args}) {limitF range} |] :: BS.ByteString
|
||||
decodeObj = HD.maybeRow (HD.value HD.json)
|
||||
|
||||
operators :: [(Text, SqlFragment)]
|
||||
|
||||
@@ -370,7 +370,10 @@ spec = do
|
||||
[json| [{"data": {"id": 1, "foo": {"bar": "baz"}}}] |]
|
||||
|
||||
describe "remote procedure call" $ do
|
||||
context "a proc that returns a set" $
|
||||
context "a proc that returns a set" $ do
|
||||
it "returns paginated results" $
|
||||
request methodPost "/rpc/getitemrange" (rangeHdrs (ByteRangeFromTo 0 0)) [json| { "min": 2, "max": 4 } |] `shouldRespondWith`
|
||||
[json| [ {"id": 3} ] |]
|
||||
it "returns proper json" $
|
||||
post "/rpc/getitemrange" [json| { "min": 2, "max": 4 } |] `shouldRespondWith`
|
||||
[json| [ {"id": 3}, {"id":4} ] |]
|
||||
|
||||
Reference in New Issue
Block a user