Refactor tests: replace str with json QuasiQuoter where appropriate
This commit is contained in:
committed by
Steve Chavez
parent
e08bb3a197
commit
2c52b96e04
@@ -6,7 +6,6 @@ import Network.HTTP.Types
|
||||
import Test.Hspec
|
||||
import Test.Hspec.Wai
|
||||
import Test.Hspec.Wai.JSON
|
||||
import Text.Heredoc
|
||||
|
||||
import PostgREST.Types (PgVersion, pgVersion112)
|
||||
import Protolude hiding (get)
|
||||
@@ -85,7 +84,7 @@ spec actualPgVersion = describe "authorization" $ do
|
||||
it "sql functions can read custom and standard claims variables" $ do
|
||||
let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJmdW4iLCJqdGkiOiJmb28iLCJuYmYiOjEzMDA4MTkzODAsImV4cCI6OTk5OTk5OTk5OSwiaHR0cDovL3Bvc3RncmVzdC5jb20vZm9vIjp0cnVlLCJpc3MiOiJqb2UiLCJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIiwiaWF0IjoxMzAwODE5MzgwfQ.V5fEpXfpb7feqwVqlcDleFdKu86bdwU2cBRT4fcMhXg"
|
||||
request methodPost "/rpc/reveal_big_jwt" [auth] "{}"
|
||||
`shouldRespondWith` [str|[{"iss":"joe","sub":"fun","exp":9999999999,"nbf":1300819380,"iat":1300819380,"jti":"foo","http://postgrest.com/foo":true}]|]
|
||||
`shouldRespondWith` [json|[{"iss":"joe","sub":"fun","exp":9999999999,"nbf":1300819380,"iat":1300819380,"jti":"foo","http://postgrest.com/foo":true}]|]
|
||||
|
||||
it "allows users with permissions to see their tables" $ do
|
||||
let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIiwiaWQiOiJqZG9lIn0.B-lReuGNDwAlU1GOC476MlO0vAt9JNoHIlxg2vwMaO0"
|
||||
@@ -148,7 +147,7 @@ spec actualPgVersion = describe "authorization" $ do
|
||||
let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MX0.gKw7qI50i9hMrSJW8BlTpdMEVmMXJYxlAqueGqpa_mE" in
|
||||
request methodPost "/rpc/get_current_user" [auth]
|
||||
[json| {} |]
|
||||
`shouldRespondWith` [str|"postgrest_test_author"|]
|
||||
`shouldRespondWith` [json|"postgrest_test_author"|]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = []
|
||||
}
|
||||
@@ -157,7 +156,7 @@ spec actualPgVersion = describe "authorization" $ do
|
||||
let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6Mn0.nwzjMI0YLvVGJQTeoCPEBsK983b__gxdpLXisBNaO2A" in
|
||||
request methodPost "/rpc/get_current_user" [auth]
|
||||
[json| {} |]
|
||||
`shouldRespondWith` [str|"postgrest_test_default_role"|]
|
||||
`shouldRespondWith` [json|"postgrest_test_default_role"|]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = []
|
||||
}
|
||||
@@ -166,7 +165,7 @@ spec actualPgVersion = describe "authorization" $ do
|
||||
let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6M30.OGxEJAf60NKZiTn-tIb2jy4rqKs_ZruLGWZ40TjrJsM" in
|
||||
request methodPost "/rpc/get_current_user" [auth]
|
||||
[json| {} |]
|
||||
`shouldRespondWith` [str|{"hint":"Please contact administrator","details":null,"code":"P0001","message":"Disabled ID --> 3"}|]
|
||||
`shouldRespondWith` [json|{"hint":"Please contact administrator","details":null,"code":"P0001","message":"Disabled ID --> 3"}|]
|
||||
{ matchStatus = 400
|
||||
, matchHeaders = []
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import Network.HTTP.Types
|
||||
import Test.Hspec
|
||||
import Test.Hspec.Wai
|
||||
import Test.Hspec.Wai.JSON
|
||||
import Text.Heredoc
|
||||
|
||||
import Protolude hiding (get)
|
||||
|
||||
@@ -23,7 +22,7 @@ spec =
|
||||
|
||||
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}]|]
|
||||
`shouldRespondWith` [json|[{"id":2}]|]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Range" <:> "*/1"]
|
||||
}
|
||||
@@ -42,18 +41,18 @@ spec =
|
||||
|
||||
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"}]|]
|
||||
`shouldRespondWith` [json|[{"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"}]|]
|
||||
`shouldRespondWith` [json|[{"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}}]|]
|
||||
`shouldRespondWith` [json|[{"id":8,"name":"Code OSX","project":{"id":4}}]|]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Range" <:> "*/*"]
|
||||
}
|
||||
@@ -61,7 +60,7 @@ spec =
|
||||
it "actually clears items ouf the db" $ do
|
||||
_ <- request methodDelete "/items?id=lt.15" [] ""
|
||||
get "/items"
|
||||
`shouldRespondWith` [str|[{"id":15}]|]
|
||||
`shouldRespondWith` [json|[{"id":15}]|]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Range" <:> "0-0/*"]
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import Network.Wai (Application)
|
||||
import Test.Hspec hiding (pendingWith)
|
||||
import Test.Hspec.Wai
|
||||
import Test.Hspec.Wai.JSON
|
||||
import Text.Heredoc
|
||||
|
||||
import Protolude hiding (get)
|
||||
import SpecHelper
|
||||
@@ -154,7 +153,7 @@ spec =
|
||||
|
||||
it "can embed parent with view!fk and grandparent by using fk" $
|
||||
get "/tasks?id=eq.1&select=id,name,projects_view!project(id,name,client(id,name))" `shouldRespondWith`
|
||||
[str|[{"id":1,"name":"Design w7","projects_view":{"id":1,"name":"Windows 7","client":{"id":1,"name":"Microsoft"}}}]|]
|
||||
[json|[{"id":1,"name":"Design w7","projects_view":{"id":1,"name":"Windows 7","client":{"id":1,"name":"Microsoft"}}}]|]
|
||||
|
||||
it "can embed by using a composite FK name" $
|
||||
get "/unit_workdays?select=unit_id,day,fst_shift(car_id,schedule(name)),snd_shift(camera_id,schedule(name))" `shouldRespondWith`
|
||||
@@ -230,7 +229,7 @@ spec =
|
||||
|
||||
it "can embed parent by using view!column and grandparent by using the column" $
|
||||
get "/tasks?id=eq.1&select=id,name,project:projects_view!project_id(id,name,client:client_id(id,name))" `shouldRespondWith`
|
||||
[str|[{"id":1,"name":"Design w7","project":{"id":1,"name":"Windows 7","client":{"id":1,"name":"Microsoft"}}}]|]
|
||||
[json|[{"id":1,"name":"Design w7","project":{"id":1,"name":"Windows 7","client":{"id":1,"name":"Microsoft"}}}]|]
|
||||
|
||||
it "can specify table!column" $
|
||||
get "/message?select=id,body,sender:person!sender(name),recipient:person!recipient(name)&id=lt.4" `shouldRespondWith`
|
||||
|
||||
+29
-30
@@ -42,7 +42,7 @@ spec actualPgVersion = do
|
||||
"integer": 14, "double": 3.14159, "varchar": "testing!"
|
||||
, "boolean": false, "date": "1900-01-01", "money": "$3.99"
|
||||
, "enum": "foo"
|
||||
}] |] `shouldRespondWith` [str|[{"integer":14,"varchar":"testing!"}]|]
|
||||
}] |] `shouldRespondWith` [json|[{"integer":14,"varchar":"testing!"}]|]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = [matchContentTypeJson]
|
||||
}
|
||||
@@ -86,7 +86,7 @@ spec actualPgVersion = do
|
||||
it "includes related data after insert" $
|
||||
request methodPost "/projects?select=id,name,clients(id,name)"
|
||||
[("Prefer", "return=representation"), ("Prefer", "count=exact")]
|
||||
[str|{"id":6,"name":"New Project","client_id":2}|] `shouldRespondWith` [str|[{"id":6,"name":"New Project","clients":{"id":2,"name":"Apple"}}]|]
|
||||
[json|{"id":6,"name":"New Project","client_id":2}|] `shouldRespondWith` [json|[{"id":6,"name":"New Project","clients":{"id":2,"name":"Apple"}}]|]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = [ matchContentTypeJson
|
||||
, "Location" <:> "/projects?id=eq.6"
|
||||
@@ -96,8 +96,8 @@ spec actualPgVersion = do
|
||||
it "can rename and cast the selected columns" $
|
||||
request methodPost "/projects?select=pId:id::text,pName:name,cId:client_id::text"
|
||||
[("Prefer", "return=representation")]
|
||||
[str|{"id":7,"name":"New Project","client_id":2}|] `shouldRespondWith`
|
||||
[str|[{"pId":"7","pName":"New Project","cId":"2"}]|]
|
||||
[json|{"id":7,"name":"New Project","client_id":2}|] `shouldRespondWith`
|
||||
[json|[{"pId":"7","pName":"New Project","cId":"2"}]|]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = [ matchContentTypeJson
|
||||
, "Location" <:> "/projects?id=eq.7"
|
||||
@@ -106,8 +106,8 @@ spec actualPgVersion = do
|
||||
|
||||
it "should not throw and return location header when selecting without PK" $
|
||||
request methodPost "/projects?select=name,client_id" [("Prefer", "return=representation")]
|
||||
[str|{"id":10,"name":"New Project","client_id":2}|] `shouldRespondWith`
|
||||
[str|[{"name":"New Project","client_id":2}]|]
|
||||
[json|{"id":10,"name":"New Project","client_id":2}|] `shouldRespondWith`
|
||||
[json|[{"name":"New Project","client_id":2}]|]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = [ matchContentTypeJson
|
||||
, "Location" <:> "/projects?id=eq.10"
|
||||
@@ -117,7 +117,7 @@ spec actualPgVersion = do
|
||||
context "requesting no representation" $
|
||||
it "should not throw and return location header when selecting without PK" $
|
||||
request methodPost "/projects?select=name,client_id" []
|
||||
[str|{"id":11,"name":"New Project","client_id":2}|] `shouldRespondWith` ""
|
||||
[json|{"id":11,"name":"New Project","client_id":2}|] `shouldRespondWith` ""
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = [ "Location" <:> "/projects?id=eq.11"
|
||||
, "Content-Range" <:> "*/*" ]
|
||||
@@ -263,7 +263,7 @@ spec actualPgVersion = do
|
||||
request methodPost "/json_table"
|
||||
[("Prefer", "return=representation")]
|
||||
inserted
|
||||
`shouldRespondWith` [str|[{"data":{"foo":"bar"}}]|]
|
||||
`shouldRespondWith` [json|[{"data":{"foo":"bar"}}]|]
|
||||
{ matchStatus = 201
|
||||
}
|
||||
|
||||
@@ -272,7 +272,7 @@ spec actualPgVersion = do
|
||||
request methodPost "/json_table"
|
||||
[("Prefer", "return=representation")]
|
||||
inserted
|
||||
`shouldRespondWith` [str|[{"data":[1,2,3]}]|]
|
||||
`shouldRespondWith` [json|[{"data":[1,2,3]}]|]
|
||||
{ matchStatus = 201
|
||||
}
|
||||
|
||||
@@ -423,24 +423,23 @@ spec actualPgVersion = do
|
||||
|
||||
describe "Row level permission" $
|
||||
it "set user_id when inserting rows" $ do
|
||||
let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIiwiaWQiOiJqZG9lIn0.B-lReuGNDwAlU1GOC476MlO0vAt9JNoHIlxg2vwMaO0"
|
||||
_ <- post "/postgrest/users" [json| { "id":"jdoe", "pass": "1234", "role": "postgrest_test_author" } |]
|
||||
_ <- post "/postgrest/users" [json| { "id":"jroe", "pass": "1234", "role": "postgrest_test_author" } |]
|
||||
post "/postgrest/users" [json| { "id":"jdoe", "pass": "1234", "role": "postgrest_test_author" } |]
|
||||
post "/postgrest/users" [json| { "id":"jroe", "pass": "1234", "role": "postgrest_test_author" } |]
|
||||
|
||||
p1 <- request methodPost "/authors_only"
|
||||
[ auth, ("Prefer", "return=representation") ]
|
||||
[json| { "secret": "nyancat" } |]
|
||||
liftIO $ do
|
||||
simpleBody p1 `shouldBe` [str|[{"owner":"jdoe","secret":"nyancat"}]|]
|
||||
simpleStatus p1 `shouldBe` created201
|
||||
request methodPost "/authors_only"
|
||||
[ authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIiwiaWQiOiJqZG9lIn0.B-lReuGNDwAlU1GOC476MlO0vAt9JNoHIlxg2vwMaO0", ("Prefer", "return=representation") ]
|
||||
[json| { "secret": "nyancat" } |]
|
||||
`shouldRespondWith`
|
||||
[json|[{"owner":"jdoe","secret":"nyancat"}]|]
|
||||
{ matchStatus = 201 }
|
||||
|
||||
p2 <- request methodPost "/authors_only"
|
||||
-- jwt token for jroe
|
||||
[ authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIiwiaWQiOiJqcm9lIn0.2e7mx0U4uDcInlbJVOBGlrRufwqWLINDIEDC1vS0nw8", ("Prefer", "return=representation") ]
|
||||
[json| { "secret": "lolcat", "owner": "hacker" } |]
|
||||
liftIO $ do
|
||||
simpleBody p2 `shouldBe` [str|[{"owner":"jroe","secret":"lolcat"}]|]
|
||||
simpleStatus p2 `shouldBe` created201
|
||||
request methodPost "/authors_only"
|
||||
-- jwt token for jroe
|
||||
[ authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIiwiaWQiOiJqcm9lIn0.2e7mx0U4uDcInlbJVOBGlrRufwqWLINDIEDC1vS0nw8", ("Prefer", "return=representation") ]
|
||||
[json| { "secret": "lolcat", "owner": "hacker" } |]
|
||||
`shouldRespondWith`
|
||||
[json|[{"owner":"jroe","secret":"lolcat"}]|]
|
||||
{ matchStatus = 201 }
|
||||
|
||||
context "tables with self reference foreign keys" $ do
|
||||
it "embeds parent after insert" $
|
||||
@@ -456,7 +455,7 @@ spec actualPgVersion = do
|
||||
context "table with limited privileges" $ do
|
||||
it "succeeds inserting if correct select is applied" $
|
||||
request methodPost "/limited_article_stars?select=article_id,user_id" [("Prefer", "return=representation")]
|
||||
[json| {"article_id": 2, "user_id": 1} |] `shouldRespondWith` [str|[{"article_id":2,"user_id":1}]|]
|
||||
[json| {"article_id": 2, "user_id": 1} |] `shouldRespondWith` [json|[{"article_id":2,"user_id":1}]|]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = []
|
||||
}
|
||||
@@ -465,9 +464,9 @@ spec actualPgVersion = do
|
||||
request methodPost "/limited_article_stars?select=article_id,user_id,created_at" [("Prefer", "return=representation")]
|
||||
[json| {"article_id": 2, "user_id": 2} |] `shouldRespondWith` (
|
||||
if actualPgVersion >= pgVersion112 then
|
||||
[str|{"hint":null,"details":null,"code":"42501","message":"permission denied for view limited_article_stars"}|]
|
||||
[json|{"hint":null,"details":null,"code":"42501","message":"permission denied for view limited_article_stars"}|]
|
||||
else
|
||||
[str|{"hint":null,"details":null,"code":"42501","message":"permission denied for relation limited_article_stars"}|]
|
||||
[json|{"hint":null,"details":null,"code":"42501","message":"permission denied for relation limited_article_stars"}|]
|
||||
)
|
||||
{ matchStatus = 401
|
||||
, matchHeaders = []
|
||||
@@ -477,9 +476,9 @@ spec actualPgVersion = do
|
||||
request methodPost "/limited_article_stars" [("Prefer", "return=representation")]
|
||||
[json| {"article_id": 3, "user_id": 1} |] `shouldRespondWith` (
|
||||
if actualPgVersion >= pgVersion112 then
|
||||
[str|{"hint":null,"details":null,"code":"42501","message":"permission denied for view limited_article_stars"}|]
|
||||
[json|{"hint":null,"details":null,"code":"42501","message":"permission denied for view limited_article_stars"}|]
|
||||
else
|
||||
[str|{"hint":null,"details":null,"code":"42501","message":"permission denied for relation limited_article_stars"}|]
|
||||
[json|{"hint":null,"details":null,"code":"42501","message":"permission denied for relation limited_article_stars"}|]
|
||||
)
|
||||
{ matchStatus = 401
|
||||
, matchHeaders = []
|
||||
|
||||
+10
-12
@@ -8,8 +8,6 @@ import Test.Hspec hiding (pendingWith)
|
||||
import Test.Hspec.Wai
|
||||
import Test.Hspec.Wai.JSON
|
||||
|
||||
import Text.Heredoc
|
||||
|
||||
import PostgREST.Types (PgVersion, pgVersion112, pgVersion121,
|
||||
pgVersion96)
|
||||
import Protolude hiding (get)
|
||||
@@ -72,19 +70,19 @@ spec actualPgVersion = do
|
||||
[json| [{"a": null, "b": null}] |]
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
get "/nullable_integer?a=is.null" `shouldRespondWith` [str|[{"a":null}]|]
|
||||
get "/nullable_integer?a=is.null" `shouldRespondWith` [json|[{"a":null}]|]
|
||||
|
||||
it "matches with like" $ do
|
||||
get "/simple_pk?k=like.*yx" `shouldRespondWith`
|
||||
[str|[{"k":"xyyx","extra":"u"}]|]
|
||||
[json|[{"k":"xyyx","extra":"u"}]|]
|
||||
get "/simple_pk?k=like.xy*" `shouldRespondWith`
|
||||
[str|[{"k":"xyyx","extra":"u"}]|]
|
||||
[json|[{"k":"xyyx","extra":"u"}]|]
|
||||
get "/simple_pk?k=like.*YY*" `shouldRespondWith`
|
||||
[str|[{"k":"xYYx","extra":"v"}]|]
|
||||
[json|[{"k":"xYYx","extra":"v"}]|]
|
||||
|
||||
it "matches with like using not operator" $
|
||||
get "/simple_pk?k=not.like.*yx" `shouldRespondWith`
|
||||
[str|[{"k":"xYYx","extra":"v"}]|]
|
||||
[json|[{"k":"xYYx","extra":"v"}]|]
|
||||
|
||||
it "matches with ilike" $ do
|
||||
get "/simple_pk?k=ilike.xy*&order=extra.asc" `shouldRespondWith`
|
||||
@@ -251,11 +249,11 @@ spec actualPgVersion = do
|
||||
describe "Shaping response with select parameter" $ do
|
||||
it "selectStar works in absense of parameter" $
|
||||
get "/complex_items?id=eq.3" `shouldRespondWith`
|
||||
[str|[{"id":3,"name":"Three","settings":{"foo":{"int":1,"bar":"baz"}},"arr_data":[1,2,3],"field-with_sep":1}]|]
|
||||
[json|[{"id":3,"name":"Three","settings":{"foo":{"int":1,"bar":"baz"}},"arr_data":[1,2,3],"field-with_sep":1}]|]
|
||||
|
||||
it "dash `-` in column names is accepted" $
|
||||
get "/complex_items?id=eq.3&select=id,field-with_sep" `shouldRespondWith`
|
||||
[str|[{"id":3,"field-with_sep":1}]|]
|
||||
[json|[{"id":3,"field-with_sep":1}]|]
|
||||
|
||||
it "one simple column" $
|
||||
get "/complex_items?select=id" `shouldRespondWith`
|
||||
@@ -320,7 +318,7 @@ spec actualPgVersion = do
|
||||
|
||||
it "requesting parents and filtering parent columns" $
|
||||
get "/projects?id=eq.1&select=id, name, clients(id)" `shouldRespondWith`
|
||||
[str|[{"id":1,"name":"Windows 7","clients":{"id":1}}]|]
|
||||
[json|[{"id":1,"name":"Windows 7","clients":{"id":1}}]|]
|
||||
|
||||
it "rows with missing parents are included" $
|
||||
get "/projects?id=in.(1,5)&select=id,clients(id)" `shouldRespondWith`
|
||||
@@ -329,7 +327,7 @@ spec actualPgVersion = do
|
||||
|
||||
it "rows with no children return [] instead of null" $
|
||||
get "/projects?id=in.(5)&select=id,tasks(id)" `shouldRespondWith`
|
||||
[str|[{"id":5,"tasks":[]}]|]
|
||||
[json|[{"id":5,"tasks":[]}]|]
|
||||
|
||||
it "requesting children 2 levels" $
|
||||
get "/clients?id=eq.1&select=id,projects(id,tasks(id))" `shouldRespondWith`
|
||||
@@ -660,7 +658,7 @@ spec actualPgVersion = do
|
||||
|
||||
it "ordering embeded parents does not break things" $
|
||||
get "/projects?id=eq.1&select=id, name, clients(id, name)&clients.order=name.asc" `shouldRespondWith`
|
||||
[str|[{"id":1,"name":"Windows 7","clients":{"id":1,"name":"Microsoft"}}]|]
|
||||
[json|[{"id":1,"name":"Windows 7","clients":{"id":1,"name":"Microsoft"}}]|]
|
||||
|
||||
context "order syntax errors" $ do
|
||||
it "gives meaningful error messages when asc/desc/nulls{first,last} are misspelled" $ do
|
||||
|
||||
+14
-14
@@ -123,9 +123,9 @@ spec actualPgVersion =
|
||||
context "shaping the response returned by a proc" $ do
|
||||
it "returns a project" $ do
|
||||
post "/rpc/getproject" [json| { "id": 1} |] `shouldRespondWith`
|
||||
[str|[{"id":1,"name":"Windows 7","client_id":1}]|]
|
||||
[json|[{"id":1,"name":"Windows 7","client_id":1}]|]
|
||||
get "/rpc/getproject?id=1" `shouldRespondWith`
|
||||
[str|[{"id":1,"name":"Windows 7","client_id":1}]|]
|
||||
[json|[{"id":1,"name":"Windows 7","client_id":1}]|]
|
||||
|
||||
it "can filter proc results" $ do
|
||||
post "/rpc/getallprojects?id=gt.1&id=lt.5&select=id" [json| {} |] `shouldRespondWith`
|
||||
@@ -147,9 +147,9 @@ spec actualPgVersion =
|
||||
|
||||
it "select works on the first level" $ do
|
||||
post "/rpc/getproject?select=id,name" [json| { "id": 1} |] `shouldRespondWith`
|
||||
[str|[{"id":1,"name":"Windows 7"}]|]
|
||||
[json|[{"id":1,"name":"Windows 7"}]|]
|
||||
get "/rpc/getproject?id=1&select=id,name" `shouldRespondWith`
|
||||
[str|[{"id":1,"name":"Windows 7"}]|]
|
||||
[json|[{"id":1,"name":"Windows 7"}]|]
|
||||
|
||||
context "foreign entities embedding" $ do
|
||||
it "can embed if related tables are in the exposed schema" $ do
|
||||
@@ -624,7 +624,7 @@ spec actualPgVersion =
|
||||
get "/rpc/overloaded?a=1&b=2" `shouldRespondWith` [str|3|]
|
||||
|
||||
it "overloaded(text, text, text)" $
|
||||
get "/rpc/overloaded?a=1&b=2&c=3" `shouldRespondWith` [str|"123"|]
|
||||
get "/rpc/overloaded?a=1&b=2&c=3" `shouldRespondWith` [json|"123"|]
|
||||
|
||||
context "only for POST rpc" $ do
|
||||
it "gives a parse filter error if GET style proc args are specified" $
|
||||
@@ -688,7 +688,7 @@ spec actualPgVersion =
|
||||
[("Custom-Header", "test")]
|
||||
[json| { "name": "request.header.custom-header" } |]
|
||||
`shouldRespondWith`
|
||||
[str|"test"|]
|
||||
[json|"test"|]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = [ matchContentTypeJson ]
|
||||
}
|
||||
@@ -697,7 +697,7 @@ spec actualPgVersion =
|
||||
[("Origin", "http://example.com")]
|
||||
[json| { "name": "request.header.origin" } |]
|
||||
`shouldRespondWith`
|
||||
[str|"http://example.com"|]
|
||||
[json|"http://example.com"|]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = [ matchContentTypeJson ]
|
||||
}
|
||||
@@ -705,7 +705,7 @@ spec actualPgVersion =
|
||||
request methodPost "/rpc/get_guc_value" []
|
||||
[json| { "name": "request.jwt.claim.role" } |]
|
||||
`shouldRespondWith`
|
||||
[str|"postgrest_test_anonymous"|]
|
||||
[json|"postgrest_test_anonymous"|]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = [ matchContentTypeJson ]
|
||||
}
|
||||
@@ -713,7 +713,7 @@ spec actualPgVersion =
|
||||
request methodPost "/rpc/get_guc_value" [("Cookie","acookie=cookievalue")]
|
||||
[json| {"name":"request.cookie.acookie"} |]
|
||||
`shouldRespondWith`
|
||||
[str|"cookievalue"|]
|
||||
[json|"cookievalue"|]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = []
|
||||
}
|
||||
@@ -721,7 +721,7 @@ spec actualPgVersion =
|
||||
request methodPost "/rpc/get_guc_value" [("Cookie","acookie=cookievalue;secondcookie=anothervalue")]
|
||||
[json| {"name":"request.cookie.secondcookie"} |]
|
||||
`shouldRespondWith`
|
||||
[str|"anothervalue"|]
|
||||
[json|"anothervalue"|]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = []
|
||||
}
|
||||
@@ -729,7 +729,7 @@ spec actualPgVersion =
|
||||
request methodPost "/rpc/get_guc_value" []
|
||||
[json| { "name": "app.settings.app_host" } |]
|
||||
`shouldRespondWith`
|
||||
[str|"localhost"|]
|
||||
[json|"localhost"|]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = [ matchContentTypeJson ]
|
||||
}
|
||||
@@ -737,7 +737,7 @@ spec actualPgVersion =
|
||||
request methodPost "/rpc/get_guc_value" [authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIn0.Xod-F15qsGL0WhdOCr2j3DdKuTw9QJERVgoFD3vGaWA"]
|
||||
[json| {"name":"request.header.authorization"} |]
|
||||
`shouldRespondWith`
|
||||
[str|"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIn0.Xod-F15qsGL0WhdOCr2j3DdKuTw9QJERVgoFD3vGaWA"|]
|
||||
[json|"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIn0.Xod-F15qsGL0WhdOCr2j3DdKuTw9QJERVgoFD3vGaWA"|]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = []
|
||||
}
|
||||
@@ -745,7 +745,7 @@ spec actualPgVersion =
|
||||
request methodPost "/rpc/get_guc_value" []
|
||||
[json| {"name":"request.method"} |]
|
||||
`shouldRespondWith`
|
||||
[str|"POST"|]
|
||||
[json|"POST"|]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = []
|
||||
}
|
||||
@@ -753,7 +753,7 @@ spec actualPgVersion =
|
||||
request methodPost "/rpc/get_guc_value" []
|
||||
[json| {"name":"request.path"} |]
|
||||
`shouldRespondWith`
|
||||
[str|"/rpc/get_guc_value"|]
|
||||
[json|"/rpc/get_guc_value"|]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = []
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import Network.HTTP.Types
|
||||
import Test.Hspec
|
||||
import Test.Hspec.Wai
|
||||
import Test.Hspec.Wai.JSON
|
||||
import Text.Heredoc
|
||||
|
||||
import Protolude hiding (get)
|
||||
import SpecHelper
|
||||
@@ -26,31 +25,37 @@ spec =
|
||||
|
||||
it "will select an existing object" $ do
|
||||
request methodGet "/items?id=eq.5" [singular] ""
|
||||
`shouldRespondWith` [str|{"id":5}|]
|
||||
`shouldRespondWith`
|
||||
[json|{"id":5}|]
|
||||
{ matchHeaders = [matchContentTypeSingular] }
|
||||
-- also test without the +json suffix
|
||||
request methodGet "/items?id=eq.5"
|
||||
[("Accept", "application/vnd.pgrst.object")] ""
|
||||
`shouldRespondWith` [str|{"id":5}|]
|
||||
[("Accept", "application/vnd.pgrst.object")] ""
|
||||
`shouldRespondWith`
|
||||
[json|{"id":5}|]
|
||||
{ matchHeaders = [matchContentTypeSingular] }
|
||||
|
||||
it "can combine multiple prefer values" $
|
||||
request methodGet "/items?id=eq.5" [singular, ("Prefer","count=none")] ""
|
||||
`shouldRespondWith` [str|{"id":5}|]
|
||||
`shouldRespondWith`
|
||||
[json|{"id":5}|]
|
||||
{ matchHeaders = [matchContentTypeSingular] }
|
||||
|
||||
it "can shape plurality singular object routes" $
|
||||
request methodGet "/projects_view?id=eq.1&select=id,name,clients(*),tasks(id,name)" [singular] ""
|
||||
`shouldRespondWith`
|
||||
[json|{"id":1,"name":"Windows 7","clients":{"id":1,"name":"Microsoft"},"tasks":[{"id":1,"name":"Design w7"},{"id":2,"name":"Code w7"}]}|]
|
||||
{ matchHeaders = ["Content-Type" <:> "application/vnd.pgrst.object+json; charset=utf-8"] }
|
||||
{ matchHeaders = [matchContentTypeSingular] }
|
||||
|
||||
context "when updating rows" $ do
|
||||
it "works for one row with return=rep" $ do
|
||||
_ <- post "/addresses" [json| { id: 97, address: "A Street" } |]
|
||||
request methodPatch
|
||||
"/addresses?id=eq.97"
|
||||
[("Prefer", "return=representation"), singular]
|
||||
[json| { address: "B Street" } |]
|
||||
post "/addresses" [json| { id: 97, address: "A Street" } |]
|
||||
request methodPatch "/addresses?id=eq.97"
|
||||
[("Prefer", "return=representation"), singular]
|
||||
[json| { address: "B Street" } |]
|
||||
`shouldRespondWith`
|
||||
[str|{"id":97,"address":"B Street"}|]
|
||||
[json|{"id":97,"address":"B Street"}|]
|
||||
{ matchHeaders = [matchContentTypeSingular] }
|
||||
|
||||
it "works for one row with return=minimal" $
|
||||
request methodPatch
|
||||
@@ -72,7 +77,7 @@ spec =
|
||||
isErrorFormat (simpleBody p) `shouldBe` True
|
||||
|
||||
-- the rows should not be updated, either
|
||||
get "/addresses?id=eq.98" `shouldRespondWith` [str|[{"id":98,"address":"xxx"}]|]
|
||||
get "/addresses?id=eq.98" `shouldRespondWith` [json|[{"id":98,"address":"xxx"}]|]
|
||||
|
||||
it "raises an error for multiple rows with return=rep" $ do
|
||||
_ <- post "/addresses" [json| { id: 100, address: "xxx" } |]
|
||||
@@ -85,33 +90,36 @@ spec =
|
||||
isErrorFormat (simpleBody p) `shouldBe` True
|
||||
|
||||
-- the rows should not be updated, either
|
||||
get "/addresses?id=eq.100" `shouldRespondWith` [str|[{"id":100,"address":"xxx"}]|]
|
||||
get "/addresses?id=eq.100" `shouldRespondWith` [json|[{"id":100,"address":"xxx"}]|]
|
||||
|
||||
it "raises an error for zero rows" $
|
||||
request methodPatch "/items?id=gt.0&id=lt.0"
|
||||
[singular] [json|{"id":1}|]
|
||||
`shouldRespondWith`
|
||||
[str|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned"}|]
|
||||
[json|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned"}|]
|
||||
{ matchStatus = 406
|
||||
, matchHeaders = ["Content-Type" <:> "application/vnd.pgrst.object+json; charset=utf-8"]
|
||||
, matchHeaders = [matchContentTypeSingular]
|
||||
}
|
||||
|
||||
it "raises an error for zero rows with return=rep" $
|
||||
request methodPatch "/items?id=gt.0&id=lt.0"
|
||||
[("Prefer", "return=representation"), singular] [json|{"id":1}|]
|
||||
`shouldRespondWith`
|
||||
[str|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned"}|]
|
||||
[json|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned"}|]
|
||||
{ matchStatus = 406
|
||||
, matchHeaders = ["Content-Type" <:> "application/vnd.pgrst.object+json; charset=utf-8"]
|
||||
, matchHeaders = [matchContentTypeSingular]
|
||||
}
|
||||
|
||||
context "when creating rows" $ do
|
||||
it "works for one row with return=rep" $ do
|
||||
p <- request methodPost
|
||||
"/addresses"
|
||||
[("Prefer", "return=representation"), singular]
|
||||
[json| [ { id: 102, address: "xxx" } ] |]
|
||||
liftIO $ simpleBody p `shouldBe` [str|{"id":102,"address":"xxx"}|]
|
||||
request methodPost "/addresses"
|
||||
[("Prefer", "return=representation"), singular]
|
||||
[json| [ { id: 102, address: "xxx" } ] |]
|
||||
`shouldRespondWith`
|
||||
[json|{"id":102,"address":"xxx"}|]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = [matchContentTypeSingular]
|
||||
}
|
||||
|
||||
it "works for one row with return=minimal" $ do
|
||||
request methodPost "/addresses"
|
||||
@@ -123,7 +131,7 @@ spec =
|
||||
}
|
||||
-- and the element should exist
|
||||
get "/addresses?id=eq.103"
|
||||
`shouldRespondWith` [str|[{"id":103,"address":"xxx"}]|]
|
||||
`shouldRespondWith` [json|[{"id":103,"address":"xxx"}]|]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = []
|
||||
}
|
||||
@@ -153,9 +161,9 @@ spec =
|
||||
[("Prefer", "return=minimal"), singular]
|
||||
[json| [ { id: 204, address: "xxx" }, { id: 205, address: "yyy" } ] |]
|
||||
`shouldRespondWith`
|
||||
[str|{"details":"Results contain 2 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned"}|]
|
||||
[json|{"details":"Results contain 2 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned"}|]
|
||||
{ matchStatus = 406
|
||||
, matchHeaders = ["Content-Type" <:> "application/vnd.pgrst.object+json; charset=utf-8"]
|
||||
, matchHeaders = [matchContentTypeSingular]
|
||||
}
|
||||
|
||||
-- the rows should not exist, either
|
||||
@@ -166,9 +174,9 @@ spec =
|
||||
[singular]
|
||||
[json| [ ] |]
|
||||
`shouldRespondWith`
|
||||
[str|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned"}|]
|
||||
[json|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned"}|]
|
||||
{ matchStatus = 406
|
||||
, matchHeaders = ["Content-Type" <:> "application/vnd.pgrst.object+json; charset=utf-8"]
|
||||
, matchHeaders = [matchContentTypeSingular]
|
||||
}
|
||||
|
||||
it "raises an error when creating zero entities with return=rep" $
|
||||
@@ -176,9 +184,9 @@ spec =
|
||||
[("Prefer", "return=representation"), singular]
|
||||
[json| [ ] |]
|
||||
`shouldRespondWith`
|
||||
[str|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned"}|]
|
||||
[json|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned"}|]
|
||||
{ matchStatus = 406
|
||||
, matchHeaders = ["Content-Type" <:> "application/vnd.pgrst.object+json; charset=utf-8"]
|
||||
, matchHeaders = [matchContentTypeSingular]
|
||||
}
|
||||
|
||||
context "when deleting rows" $ do
|
||||
@@ -186,7 +194,7 @@ spec =
|
||||
p <- request methodDelete
|
||||
"/items?id=eq.11"
|
||||
[("Prefer", "return=representation"), singular] ""
|
||||
liftIO $ simpleBody p `shouldBe` [str|{"id":11}|]
|
||||
liftIO $ simpleBody p `shouldBe` [json|{"id":11}|]
|
||||
|
||||
it "works for one row with return=minimal" $ do
|
||||
p <- request methodDelete
|
||||
@@ -222,18 +230,18 @@ spec =
|
||||
request methodDelete "/items?id=lt.0"
|
||||
[singular] ""
|
||||
`shouldRespondWith`
|
||||
[str|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned"}|]
|
||||
[json|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned"}|]
|
||||
{ matchStatus = 406
|
||||
, matchHeaders = ["Content-Type" <:> "application/vnd.pgrst.object+json; charset=utf-8"]
|
||||
, matchHeaders = [matchContentTypeSingular]
|
||||
}
|
||||
|
||||
it "raises an error when deleting zero entities with return=rep" $
|
||||
request methodDelete "/items?id=lt.0"
|
||||
[("Prefer", "return=representation"), singular] ""
|
||||
`shouldRespondWith`
|
||||
[str|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned"}|]
|
||||
[json|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned"}|]
|
||||
{ matchStatus = 406
|
||||
, matchHeaders = ["Content-Type" <:> "application/vnd.pgrst.object+json; charset=utf-8"]
|
||||
, matchHeaders = [matchContentTypeSingular]
|
||||
}
|
||||
|
||||
context "when calling a stored proc" $ do
|
||||
@@ -241,9 +249,9 @@ spec =
|
||||
request methodPost "/rpc/getproject"
|
||||
[singular] [json|{ "id": 9999999}|]
|
||||
`shouldRespondWith`
|
||||
[str|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned"}|]
|
||||
[json|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned"}|]
|
||||
{ matchStatus = 406
|
||||
, matchHeaders = ["Content-Type" <:> "application/vnd.pgrst.object+json; charset=utf-8"]
|
||||
, matchHeaders = [matchContentTypeSingular]
|
||||
}
|
||||
|
||||
-- this one may be controversial, should vnd.pgrst.object include
|
||||
@@ -255,30 +263,32 @@ spec =
|
||||
|
||||
it "returns a single object for json proc" $
|
||||
request methodPost "/rpc/getproject"
|
||||
[singular] [json|{ "id": 1}|] `shouldRespondWith`
|
||||
[str|{"id":1,"name":"Windows 7","client_id":1}|]
|
||||
[singular] [json|{ "id": 1}|]
|
||||
`shouldRespondWith`
|
||||
[json|{"id":1,"name":"Windows 7","client_id":1}|]
|
||||
{ matchHeaders = [matchContentTypeSingular] }
|
||||
|
||||
it "fails for multiple rows" $
|
||||
request methodPost "/rpc/getallprojects"
|
||||
[singular] "{}"
|
||||
`shouldRespondWith`
|
||||
[str|{"details":"Results contain 5 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned"}|]
|
||||
[json|{"details":"Results contain 5 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned"}|]
|
||||
{ matchStatus = 406
|
||||
, matchHeaders = ["Content-Type" <:> "application/vnd.pgrst.object+json; charset=utf-8"]
|
||||
, matchHeaders = [matchContentTypeSingular]
|
||||
}
|
||||
|
||||
it "executes the proc exactly once per request" $ do
|
||||
request methodPost "/rpc/getproject?select=id,name" [] [json| {"id": 1} |]
|
||||
`shouldRespondWith` [str|[{"id":1,"name":"Windows 7"}]|]
|
||||
`shouldRespondWith` [json|[{"id":1,"name":"Windows 7"}]|]
|
||||
|
||||
request methodPost "/rpc/setprojects" [singular]
|
||||
[json| {"id_l": 1, "id_h": 2, "name": "changed"} |]
|
||||
`shouldRespondWith`
|
||||
[str|{"details":"Results contain 2 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned"}|]
|
||||
[json|{"details":"Results contain 2 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned"}|]
|
||||
{ matchStatus = 406
|
||||
, matchHeaders = ["Content-Type" <:> "application/vnd.pgrst.object+json; charset=utf-8"]
|
||||
, matchHeaders = [matchContentTypeSingular]
|
||||
}
|
||||
|
||||
-- should not actually have executed the function
|
||||
request methodPost "/rpc/getproject?select=id,name" [] [json| {"id": 1} |]
|
||||
`shouldRespondWith` [str|[{"id":1,"name":"Windows 7"}]|]
|
||||
`shouldRespondWith` [json|[{"id":1,"name":"Windows 7"}]|]
|
||||
|
||||
@@ -85,7 +85,7 @@ spec = do
|
||||
it "returns updated object as array when return=rep" $
|
||||
request methodPatch "/items?id=eq.2"
|
||||
[("Prefer", "return=representation")] [json| { "id":2 } |]
|
||||
`shouldRespondWith` [str|[{"id":2}]|]
|
||||
`shouldRespondWith` [json|[{"id":2}]|]
|
||||
{ matchStatus = 200,
|
||||
matchHeaders = ["Content-Range" <:> "0-0/*"]
|
||||
}
|
||||
|
||||
+21
-22
@@ -6,7 +6,6 @@ import Network.HTTP.Types
|
||||
import Test.Hspec
|
||||
import Test.Hspec.Wai
|
||||
import Test.Hspec.Wai.JSON
|
||||
import Text.Heredoc
|
||||
|
||||
import Protolude hiding (get, put)
|
||||
import SpecHelper
|
||||
@@ -161,73 +160,73 @@ spec =
|
||||
context "Restrictions" $ do
|
||||
it "fails if Range is specified" $
|
||||
request methodPut "/tiobe_pls?name=eq.Javascript" [("Range", "0-5")]
|
||||
[str| [ { "name": "Javascript", "rank": 1 } ]|]
|
||||
[json| [ { "name": "Javascript", "rank": 1 } ]|]
|
||||
`shouldRespondWith`
|
||||
[json|{"message":"Range header and limit/offset querystring parameters are not allowed for PUT"}|]
|
||||
{ matchStatus = 400 , matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
it "fails if limit is specified" $
|
||||
put "/tiobe_pls?name=eq.Javascript&limit=1"
|
||||
[str| [ { "name": "Javascript", "rank": 1 } ]|]
|
||||
[json| [ { "name": "Javascript", "rank": 1 } ]|]
|
||||
`shouldRespondWith`
|
||||
[json|{"message":"Range header and limit/offset querystring parameters are not allowed for PUT"}|]
|
||||
{ matchStatus = 400 , matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
it "fails if offset is specified" $
|
||||
put "/tiobe_pls?name=eq.Javascript&offset=1"
|
||||
[str| [ { "name": "Javascript", "rank": 1 } ]|]
|
||||
[json| [ { "name": "Javascript", "rank": 1 } ]|]
|
||||
`shouldRespondWith`
|
||||
[json|{"message":"Range header and limit/offset querystring parameters are not allowed for PUT"}|]
|
||||
{ matchStatus = 400 , matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
it "rejects every other filter than pk cols eq's" $ do
|
||||
put "/tiobe_pls?rank=eq.19"
|
||||
[str| [ { "name": "Go", "rank": 19 } ]|]
|
||||
[json| [ { "name": "Go", "rank": 19 } ]|]
|
||||
`shouldRespondWith`
|
||||
[json|{"message":"Filters must include all and only primary key columns with 'eq' operators"}|]
|
||||
{ matchStatus = 405 , matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
put "/tiobe_pls?id=not.eq.Java"
|
||||
[str| [ { "name": "Go", "rank": 19 } ]|]
|
||||
[json| [ { "name": "Go", "rank": 19 } ]|]
|
||||
`shouldRespondWith`
|
||||
[json|{"message":"Filters must include all and only primary key columns with 'eq' operators"}|]
|
||||
{ matchStatus = 405 , matchHeaders = [matchContentTypeJson] }
|
||||
put "/tiobe_pls?id=in.(Go)"
|
||||
[str| [ { "name": "Go", "rank": 19 } ]|]
|
||||
[json| [ { "name": "Go", "rank": 19 } ]|]
|
||||
`shouldRespondWith`
|
||||
[json|{"message":"Filters must include all and only primary key columns with 'eq' operators"}|]
|
||||
{ matchStatus = 405 , matchHeaders = [matchContentTypeJson] }
|
||||
put "/tiobe_pls?and=(id.eq.Go)"
|
||||
[str| [ { "name": "Go", "rank": 19 } ]|]
|
||||
[json| [ { "name": "Go", "rank": 19 } ]|]
|
||||
`shouldRespondWith`
|
||||
[json|{"message":"Filters must include all and only primary key columns with 'eq' operators"}|]
|
||||
{ matchStatus = 405 , matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
it "fails if not all composite key cols are specified as eq filters" $ do
|
||||
put "/employees?first_name=eq.Susan"
|
||||
[str| [ { "first_name": "Susan", "last_name": "Heidt", "salary": "48000", "company": "GEX", "occupation": "Railroad engineer" } ]|]
|
||||
[json| [ { "first_name": "Susan", "last_name": "Heidt", "salary": "48000", "company": "GEX", "occupation": "Railroad engineer" } ]|]
|
||||
`shouldRespondWith`
|
||||
[json|{"message":"Filters must include all and only primary key columns with 'eq' operators"}|]
|
||||
{ matchStatus = 405 , matchHeaders = [matchContentTypeJson] }
|
||||
put "/employees?last_name=eq.Heidt"
|
||||
[str| [ { "first_name": "Susan", "last_name": "Heidt", "salary": "48000", "company": "GEX", "occupation": "Railroad engineer" } ]|]
|
||||
[json| [ { "first_name": "Susan", "last_name": "Heidt", "salary": "48000", "company": "GEX", "occupation": "Railroad engineer" } ]|]
|
||||
`shouldRespondWith`
|
||||
[json|{"message":"Filters must include all and only primary key columns with 'eq' operators"}|]
|
||||
{ matchStatus = 405 , matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
it "fails if the uri primary key doesn't match the payload primary key" $ do
|
||||
put "/tiobe_pls?name=eq.MATLAB" [str| [ { "name": "Perl", "rank": 17 } ]|]
|
||||
put "/tiobe_pls?name=eq.MATLAB" [json| [ { "name": "Perl", "rank": 17 } ]|]
|
||||
`shouldRespondWith`
|
||||
[json|{"message":"Payload values do not match URL in primary key column(s)"}|]
|
||||
{ matchStatus = 400 , matchHeaders = [matchContentTypeJson] }
|
||||
put "/employees?first_name=eq.Wendy&last_name=eq.Anderson"
|
||||
[str| [ { "first_name": "Susan", "last_name": "Heidt", "salary": "48000", "company": "GEX", "occupation": "Railroad engineer" } ]|]
|
||||
[json| [ { "first_name": "Susan", "last_name": "Heidt", "salary": "48000", "company": "GEX", "occupation": "Railroad engineer" } ]|]
|
||||
`shouldRespondWith`
|
||||
[json|{"message":"Payload values do not match URL in primary key column(s)"}|]
|
||||
{ matchStatus = 400 , matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
it "fails if the table has no PK" $
|
||||
put "/no_pk?a=eq.one&b=eq.two" [str| [ { "a": "one", "b": "two" } ]|]
|
||||
put "/no_pk?a=eq.one&b=eq.two" [json| [ { "a": "one", "b": "two" } ]|]
|
||||
`shouldRespondWith`
|
||||
[json|{"message":"Filters must include all and only primary key columns with 'eq' operators"}|]
|
||||
{ matchStatus = 405 , matchHeaders = [matchContentTypeJson] }
|
||||
@@ -235,14 +234,14 @@ spec =
|
||||
context "Inserting row" $ do
|
||||
it "succeeds on table with single pk col" $ do
|
||||
get "/tiobe_pls?name=eq.Go" `shouldRespondWith` "[]"
|
||||
put "/tiobe_pls?name=eq.Go" [str| [ { "name": "Go", "rank": 19 } ]|] `shouldRespondWith` 204
|
||||
put "/tiobe_pls?name=eq.Go" [json| [ { "name": "Go", "rank": 19 } ]|] `shouldRespondWith` 204
|
||||
get "/tiobe_pls?name=eq.Go" `shouldRespondWith` [json| [ { "name": "Go", "rank": 19 } ]|] { matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
it "succeeds on table with composite pk" $ do
|
||||
get "/employees?first_name=eq.Susan&last_name=eq.Heidt"
|
||||
`shouldRespondWith` "[]"
|
||||
put "/employees?first_name=eq.Susan&last_name=eq.Heidt"
|
||||
[str| [ { "first_name": "Susan", "last_name": "Heidt", "salary": "48000", "company": "GEX", "occupation": "Railroad engineer" } ]|]
|
||||
[json| [ { "first_name": "Susan", "last_name": "Heidt", "salary": "48000", "company": "GEX", "occupation": "Railroad engineer" } ]|]
|
||||
`shouldRespondWith` 204
|
||||
get "/employees?first_name=eq.Susan&last_name=eq.Heidt"
|
||||
`shouldRespondWith`
|
||||
@@ -251,19 +250,19 @@ spec =
|
||||
|
||||
it "succeeds if the table has only PK cols and no other cols" $ do
|
||||
get "/only_pk?id=eq.10" `shouldRespondWith` "[]"
|
||||
put "/only_pk?id=eq.10" [str|[ { "id": 10 } ]|] `shouldRespondWith` 204
|
||||
put "/only_pk?id=eq.10" [json|[ { "id": 10 } ]|] `shouldRespondWith` 204
|
||||
get "/only_pk?id=eq.10" `shouldRespondWith` [json|[ { "id": 10 } ]|] { matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
context "Updating row" $ do
|
||||
it "succeeds on table with single pk col" $ do
|
||||
get "/tiobe_pls?name=eq.Go" `shouldRespondWith` [json|[ { "name": "Go", "rank": 19 } ]|] { matchHeaders = [matchContentTypeJson] }
|
||||
put "/tiobe_pls?name=eq.Go" [str| [ { "name": "Go", "rank": 13 } ]|] `shouldRespondWith` 204
|
||||
put "/tiobe_pls?name=eq.Go" [json| [ { "name": "Go", "rank": 13 } ]|] `shouldRespondWith` 204
|
||||
get "/tiobe_pls?name=eq.Go" `shouldRespondWith` [json| [ { "name": "Go", "rank": 13 } ]|] { matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
it "succeeds if the payload has more than one row, but it only puts the first element" $
|
||||
request methodPut "/tiobe_pls?name=eq.Go"
|
||||
[("Prefer", "return=representation"), ("Accept", "application/vnd.pgrst.object+json")]
|
||||
[str| [ { "name": "Go", "rank": 19 }, { "name": "Swift", "rank": 12 } ] |]
|
||||
[json| [ { "name": "Go", "rank": 19 }, { "name": "Swift", "rank": 12 } ] |]
|
||||
`shouldRespondWith`
|
||||
[json|{ "name": "Go", "rank": 19 }|]
|
||||
{ matchStatus = 200 , matchHeaders = [matchContentTypeSingular] }
|
||||
@@ -274,7 +273,7 @@ spec =
|
||||
[json| [ { "first_name": "Susan", "last_name": "Heidt", "salary": "$48,000.00", "company": "GEX", "occupation": "Railroad engineer" } ]|]
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
put "/employees?first_name=eq.Susan&last_name=eq.Heidt"
|
||||
[str| [ { "first_name": "Susan", "last_name": "Heidt", "salary": "60000", "company": "Gamma Gas", "occupation": "Railroad engineer" } ]|]
|
||||
[json| [ { "first_name": "Susan", "last_name": "Heidt", "salary": "60000", "company": "Gamma Gas", "occupation": "Railroad engineer" } ]|]
|
||||
`shouldRespondWith` 204
|
||||
get "/employees?first_name=eq.Susan&last_name=eq.Heidt"
|
||||
`shouldRespondWith`
|
||||
@@ -283,13 +282,13 @@ spec =
|
||||
|
||||
it "succeeds if the table has only PK cols and no other cols" $ do
|
||||
get "/only_pk?id=eq.10" `shouldRespondWith` [json|[ { "id": 10 } ]|] { matchHeaders = [matchContentTypeJson] }
|
||||
put "/only_pk?id=eq.10" [str|[ { "id": 10 } ]|] `shouldRespondWith` 204
|
||||
put "/only_pk?id=eq.10" [json|[ { "id": 10 } ]|] `shouldRespondWith` 204
|
||||
get "/only_pk?id=eq.10" `shouldRespondWith` [json|[ { "id": 10 } ]|] { matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
it "works with return=representation and vnd.pgrst.object+json" $
|
||||
request methodPut "/tiobe_pls?name=eq.Ruby"
|
||||
[("Prefer", "return=representation"), ("Accept", "application/vnd.pgrst.object+json")]
|
||||
[str| [ { "name": "Ruby", "rank": 11 } ]|]
|
||||
[json| [ { "name": "Ruby", "rank": 11 } ]|]
|
||||
`shouldRespondWith` [json|{ "name": "Ruby", "rank": 11 }|] { matchHeaders = [matchContentTypeSingular] }
|
||||
|
||||
context "with a camel case pk column" $ do
|
||||
@@ -315,6 +314,6 @@ spec =
|
||||
}
|
||||
|
||||
it "works with PUT" $ do
|
||||
put "/UnitTest?idUnitTest=eq.1" [str| [ { "idUnitTest": 1, "nameUnitTest": "unit test 1" } ]|] `shouldRespondWith` 204
|
||||
put "/UnitTest?idUnitTest=eq.1" [json| [ { "idUnitTest": 1, "nameUnitTest": "unit test 1" } ]|] `shouldRespondWith` 204
|
||||
get "/UnitTest?idUnitTest=eq.1" `shouldRespondWith`
|
||||
[json| [ { "idUnitTest": 1, "nameUnitTest": "unit test 1" } ]|] { matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
Reference in New Issue
Block a user