implement select/return representation for DELETE queries (fix #518)
This commit is contained in:
+2
-1
@@ -12,7 +12,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- Accept posts from HTML forms - @begriffs
|
- Accept posts from HTML forms - @begriffs
|
||||||
- Ability to order embedded entities - @ruslantalpa
|
- Ability to order embedded entities - @ruslantalpa
|
||||||
- Ability to paginate using &limit and &offset parameters - @ruslantalpa
|
- Ability to paginate using &limit and &offset parameters - @ruslantalpa
|
||||||
- Ability to apply limits to embedded entities and enforce --max-rows on all levels - @ruslantalpa, @begriffs
|
- Ability to apply limits to embedded entities and enforce --max-rows on all levels - @ruslantalpa, @begriffs
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Return 401 or 403 for access denied rather than 404 - @begriffs
|
- Return 401 or 403 for access denied rather than 404 - @begriffs
|
||||||
@@ -22,6 +22,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- Include entities from the same parent table using two different foreign keys - @ruslantalpa
|
- Include entities from the same parent table using two different foreign keys - @ruslantalpa
|
||||||
- Ensure that Location header in 201 response is URL-encoded - @league
|
- Ensure that Location header in 201 response is URL-encoded - @league
|
||||||
- Fix garbage collector CPU leak - @ruslantalpa et al.
|
- Fix garbage collector CPU leak - @ruslantalpa et al.
|
||||||
|
- Return deleted items when return=representation header is sent - @ruslantalpa
|
||||||
|
|
||||||
## [0.3.1.1] - 2016-03-28
|
## [0.3.1.1] - 2016-03-28
|
||||||
|
|
||||||
|
|||||||
@@ -150,9 +150,7 @@ userApiRequest schema req reqBody =
|
|||||||
, iPreferSingular = singular
|
, iPreferSingular = singular
|
||||||
, iPreferCount = not $ singular || hasPrefer "count=none"
|
, iPreferCount = not $ singular || hasPrefer "count=none"
|
||||||
, iFilters = [ (cs k, fromJust v) | (k,v) <- qParams, isJust v, k /= "select", k /= "offset", not (endingIn ["order", "limit"] k) ]
|
, iFilters = [ (cs k, fromJust v) | (k,v) <- qParams, isJust v, k /= "select", k /= "offset", not (endingIn ["order", "limit"] k) ]
|
||||||
, iSelect = if method == "DELETE"
|
, iSelect = fromMaybe "*" $ fromMaybe (Just "*") $ lookup "select" qParams
|
||||||
then "*"
|
|
||||||
else fromMaybe "*" $ fromMaybe (Just "*") $ lookup "select" qParams
|
|
||||||
, iOrder = [(cs k, fromJust v) | (k,v) <- qParams, isJust v, endingIn ["order"] k ]
|
, iOrder = [(cs k, fromJust v) | (k,v) <- qParams, isJust v, endingIn ["order"] k ]
|
||||||
, iCanonicalQS = urlEncodeVars
|
, iCanonicalQS = urlEncodeVars
|
||||||
. sortBy (comparing fst)
|
. sortBy (comparing fst)
|
||||||
|
|||||||
@@ -161,13 +161,16 @@ app dbStructure conf apiRequest =
|
|||||||
Left e -> return $ responseLBS status400 [jsonH] $ cs e
|
Left e -> return $ responseLBS status400 [jsonH] $ cs e
|
||||||
Right (sq,mq) -> do
|
Right (sq,mq) -> do
|
||||||
let emptyUniform = UniformObjects V.empty
|
let emptyUniform = UniformObjects V.empty
|
||||||
let fakeload = PayloadJSON emptyUniform
|
fakeload = PayloadJSON emptyUniform
|
||||||
let stm = createWriteStatement qi sq mq False (iPreferRepresentation apiRequest) [] (contentType == TextCSV) fakeload
|
stm = createWriteStatement qi sq mq False (iPreferRepresentation apiRequest) [] (contentType == TextCSV) fakeload
|
||||||
row <- H.query emptyUniform stm
|
row <- H.query emptyUniform stm
|
||||||
let (_, queryTotal, _, _) = extractQueryResult row
|
let (_, queryTotal, _, body) = extractQueryResult row
|
||||||
|
r = contentRangeH 1 0 (toInteger <$> Just queryTotal)
|
||||||
return $ if queryTotal == 0
|
return $ if queryTotal == 0
|
||||||
then notFound
|
then notFound
|
||||||
else responseLBS status204 [("Content-Range", "*/"<> cs (show queryTotal))] ""
|
else if iPreferRepresentation apiRequest == Full
|
||||||
|
then responseLBS status200 [contentTypeH, r] (cs body)
|
||||||
|
else responseLBS status204 [r] ""
|
||||||
|
|
||||||
(ActionInfo, TargetIdent (QualifiedIdentifier tSchema tTable), Nothing) ->
|
(ActionInfo, TargetIdent (QualifiedIdentifier tSchema tTable), Nothing) ->
|
||||||
if isJust $ find (\t -> tableName t == tTable && tableSchema t == tSchema) (dbTables dbStructure)
|
if isJust $ find (\t -> tableName t == tTable && tableSchema t == tSchema) (dbTables dbStructure)
|
||||||
@@ -346,6 +349,7 @@ buildReadRequest maxRows allRels apiRequest =
|
|||||||
relations = case action of
|
relations = case action of
|
||||||
ActionCreate -> fakeSourceRelations ++ allRels
|
ActionCreate -> fakeSourceRelations ++ allRels
|
||||||
ActionUpdate -> fakeSourceRelations ++ allRels
|
ActionUpdate -> fakeSourceRelations ++ allRels
|
||||||
|
ActionDelete -> fakeSourceRelations ++ allRels
|
||||||
_ -> allRels
|
_ -> allRels
|
||||||
where fakeSourceRelations = mapMaybe (toSourceRelation rootTableName) allRels -- see comment in toSourceRelation
|
where fakeSourceRelations = mapMaybe (toSourceRelation rootTableName) allRels -- see comment in toSourceRelation
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,28 @@ spec =
|
|||||||
, matchHeaders = ["Content-Range" <:> "*/1"]
|
, matchHeaders = ["Content-Range" <:> "*/1"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
it "returns the deleted item" $
|
||||||
|
request methodDelete "/items?id=eq.2" [("Prefer", "return=representation")] ""
|
||||||
|
`shouldRespondWith` ResponseMatcher {
|
||||||
|
matchBody = Just [str|[{"id":2}]|]
|
||||||
|
, matchStatus = 200
|
||||||
|
, matchHeaders = ["Content-Range" <:> "*/1"]
|
||||||
|
}
|
||||||
|
it "returns the deleted item and shapes the response" $
|
||||||
|
request methodDelete "/complex_items?id=eq.2&select=id,name" [("Prefer", "return=representation")] ""
|
||||||
|
`shouldRespondWith` ResponseMatcher {
|
||||||
|
matchBody = Just [str|[{"id":2,"name":"Two"}]|]
|
||||||
|
, matchStatus = 200
|
||||||
|
, matchHeaders = ["Content-Range" <:> "*/1"]
|
||||||
|
}
|
||||||
|
it "can embed (parent) entities" $
|
||||||
|
request methodDelete "/tasks?id=eq.8&select=id,name,project{id}" [("Prefer", "return=representation")] ""
|
||||||
|
`shouldRespondWith` ResponseMatcher {
|
||||||
|
matchBody = Just [str|[{"id":8,"name":"Code OSX","project":{"id":4}}]|]
|
||||||
|
, matchStatus = 200
|
||||||
|
, matchHeaders = ["Content-Range" <:> "*/1"]
|
||||||
|
}
|
||||||
|
|
||||||
it "actually clears items ouf the db" $ do
|
it "actually clears items ouf the db" $ do
|
||||||
_ <- request methodDelete "/items?id=lt.15" [] ""
|
_ <- request methodDelete "/items?id=lt.15" [] ""
|
||||||
get "/items"
|
get "/items"
|
||||||
|
|||||||
Reference in New Issue
Block a user