When having one-to-many relationships like: person -< message[sender] person -< message[recipient] person_detail -< message[sender] person_detail -< message[recipient] Where person_detail is a view of person. This request: GET "/message?select=*,sender(*)" Is ambiguous. Both person or person_detail could be embedded. Until now we have returned the first detected relationship but now we return a 300 Multiple Choices error with a descriptive error message asking the user to disambiguate. This is more helpful for the user and also aids in cases of more complex relationships.
87 lines
3.6 KiB
Haskell
87 lines
3.6 KiB
Haskell
module Feature.DeleteSpec where
|
|
|
|
import Network.Wai (Application)
|
|
|
|
import Network.HTTP.Types
|
|
import Test.Hspec
|
|
import Test.Hspec.Wai
|
|
import Test.Hspec.Wai.JSON
|
|
import Text.Heredoc
|
|
|
|
import Protolude hiding (get)
|
|
|
|
spec :: SpecWith Application
|
|
spec =
|
|
describe "Deleting" $ do
|
|
context "existing record" $ do
|
|
it "succeeds with 204 and deletion count" $
|
|
request methodDelete "/items?id=eq.1" [] ""
|
|
`shouldRespondWith` ""
|
|
{ matchStatus = 204
|
|
, matchHeaders = ["Content-Range" <:> "*/*"]
|
|
}
|
|
|
|
it "returns the deleted item and count if requested" $
|
|
request methodDelete "/items?id=eq.2" [("Prefer", "return=representation"), ("Prefer", "count=exact")] ""
|
|
`shouldRespondWith` [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` [str|[{"id":2,"name":"Two"}]|]
|
|
{ matchStatus = 200
|
|
, matchHeaders = ["Content-Range" <:> "*/*"]
|
|
}
|
|
it "can rename and cast the selected columns" $
|
|
request methodDelete "/complex_items?id=eq.3&select=ciId:id::text,ciName:name" [("Prefer", "return=representation")] ""
|
|
`shouldRespondWith` [str|[{"ciId":"3","ciName":"Three"}]|]
|
|
it "can embed (parent) entities" $
|
|
request methodDelete "/tasks?id=eq.8&select=id,name,project:projects(id)" [("Prefer", "return=representation")] ""
|
|
`shouldRespondWith` [str|[{"id":8,"name":"Code OSX","project":{"id":4}}]|]
|
|
{ matchStatus = 200
|
|
, matchHeaders = ["Content-Range" <:> "*/*"]
|
|
}
|
|
|
|
it "actually clears items ouf the db" $ do
|
|
_ <- request methodDelete "/items?id=lt.15" [] ""
|
|
get "/items"
|
|
`shouldRespondWith` [str|[{"id":15}]|]
|
|
{ matchStatus = 200
|
|
, matchHeaders = ["Content-Range" <:> "0-0/*"]
|
|
}
|
|
|
|
context "known route, no records matched" $
|
|
it "includes [] body if return=rep" $
|
|
request methodDelete "/items?id=eq.101"
|
|
[("Prefer", "return=representation")] ""
|
|
`shouldRespondWith` "[]"
|
|
{ matchStatus = 200
|
|
, matchHeaders = ["Content-Range" <:> "*/*"]
|
|
}
|
|
|
|
context "totally unknown route" $
|
|
it "fails with 404" $
|
|
request methodDelete "/foozle?id=eq.101" [] "" `shouldRespondWith` 404
|
|
|
|
context "table with limited privileges" $ do
|
|
it "fails deleting the row when return=representation and selecting all the columns" $
|
|
request methodDelete "/app_users?id=eq.1" [("Prefer", "return=representation")] mempty
|
|
`shouldRespondWith` 401
|
|
|
|
it "succeeds deleting the row when return=representation and selecting only the privileged columns" $
|
|
request methodDelete "/app_users?id=eq.1&select=id,email" [("Prefer", "return=representation")]
|
|
[json| { "password": "passxyz" } |]
|
|
`shouldRespondWith` [json|[ { "id": 1, "email": "test@123.com" } ]|]
|
|
{ matchStatus = 200
|
|
, matchHeaders = ["Content-Range" <:> "*/*"]
|
|
}
|
|
|
|
it "suceeds deleting the row with no explicit select when using return=minimal" $
|
|
request methodDelete "/app_users?id=eq.2" [("Prefer", "return=minimal")] mempty
|
|
`shouldRespondWith` 204
|
|
|
|
it "suceeds deleting the row with no explicit select by default" $
|
|
request methodDelete "/app_users?id=eq.3" [] mempty
|
|
`shouldRespondWith` 204
|