feat: Allow limit=0 in query params to return an empty array

This commit is contained in:
Laurence Isla
2022-04-28 17:14:29 -05:00
committed by GitHub
parent d2aa50be52
commit 5ad8800773
4 changed files with 27 additions and 7 deletions
+1
View File
@@ -27,6 +27,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- #2176, Errors raised with `SQLSTATE` now include the message and the code in the response body - @laurenceisla
- #2236, Support POSIX regular expression operators for row filtering - @enote-kane
- #2202, Allow returning XML from RPCs - @fjf2002
- #2269, Allow `limit=0` in the request query to return an empty array - @gautam1168, @laurenceisla
### Fixed
+11
View File
@@ -10,6 +10,8 @@ module PostgREST.RangeQuery (
, restrictRange
, rangeGeq
, allRange
, limitZeroRange
, hasLimitZero
, NonnegRange
, rangeStatusHeader
, contentRangeH
@@ -74,6 +76,15 @@ rangeLeq :: Integer -> NonnegRange
rangeLeq n =
Range BoundaryBelowAll (BoundaryAbove n)
-- Special case to allow limit 0 queries
-- https://github.com/PostgREST/postgrest/issues/1121
-- 0 <= x <= -1
limitZeroRange :: Range Integer
limitZeroRange = Range (BoundaryBelow 0) (BoundaryAbove (-1))
hasLimitZero :: Range Integer -> Bool
hasLimitZero r = rangeUpper r == rangeUpper limitZeroRange
rangeStatusHeader :: NonnegRange -> Int64 -> Maybe Int64 -> (Status, Header)
rangeStatusHeader topLevelRange queryTotal tableTotal =
let lower = rangeOffset topLevelRange
+10 -2
View File
@@ -50,6 +50,8 @@ import PostgREST.DbStructure.Identifiers (FieldName,
import PostgREST.DbStructure.Proc (ProcDescription (..),
ProcParam (..), ProcsMap)
import PostgREST.RangeQuery (NonnegRange, allRange,
hasLimitZero,
limitZeroRange,
rangeRequested)
import PostgREST.Request.Preferences (PreferCount (..),
PreferParameters (..),
@@ -180,7 +182,7 @@ apiRequest :: AppConfig -> DbStructure -> Request -> RequestBody -> QueryParams.
apiRequest conf@AppConfig{..} dbStructure req reqBody queryparams@QueryParams{..}
| isJust profile && fromJust profile `notElem` configDbSchemas = Left $ UnacceptableSchema $ toList configDbSchemas
| isTargetingProc && method `notElem` ["HEAD", "GET", "POST"] = Left ActionInappropriate
| topLevelRange == emptyRange = Left InvalidRange
| isInvalidRange = Left InvalidRange
| shouldParsePayload && isLeft payload = either (Left . InvalidBody) witness payload
| not expectParams && not (L.null qsParams) = Left $ ParseRequestError "Unexpected param or filter missing operator" ("Failed to parse " <> show qsParams)
| otherwise = do
@@ -330,8 +332,14 @@ apiRequest conf@AppConfig{..} dbStructure req reqBody queryparams@QueryParams{..
lookupHeader = flip lookup hdrs
Preferences.Preferences{..} = Preferences.fromHeaders hdrs
headerRange = rangeRequested hdrs
limitRange = fromMaybe allRange (M.lookup "limit" qsRanges)
headerAndLimitRange = rangeIntersection headerRange limitRange
ranges = M.insert "limit" (rangeIntersection headerRange (fromMaybe allRange (M.lookup "limit" qsRanges))) qsRanges
-- Bypass all the ranges and send only the limit zero range (0 <= x <= -1) if
-- limit=0 is present in the query params (not allowed for the Range header)
ranges = M.insert "limit" (if hasLimitZero limitRange then limitZeroRange else headerAndLimitRange) qsRanges
-- The only emptyRange allowed is the limit zero range
isInvalidRange = topLevelRange == emptyRange && not (hasLimitZero limitRange)
{-|
Find the best match from a list of content types accepted by the
+5 -5
View File
@@ -184,12 +184,12 @@ spec = do
[json|[{"id":1},{"id":2},{"id":3},{"id":4},{"id":5},{"id":6},{"id":7},{"id":8},{"id":9},{"id":10},{"id":11},{"id":12},{"id":13},{"id":14},{"id":15}]|]
{ matchHeaders = ["Content-Range" <:> "0-14/*"] }
it "fails if limit equals 0" $
it "succeeds and returns an empty array if limit equals 0" $
get "/items?select=id&limit=0"
`shouldRespondWith` [json|{"message":"HTTP Range error","code":"PGRST103","details":null,"hint":null}|]
{ matchStatus = 416
, matchHeaders = [matchContentTypeJson]
}
`shouldRespondWith` [json|[]|]
{ matchStatus = 200
, matchHeaders = ["Content-Range" <:> "*/*"]
}
it "fails if limit is negative" $
get "/items?select=id&limit=-1"