Merge v3
This commit is contained in:
+42
-44
@@ -18,55 +18,53 @@ spec = beforeAll
|
||||
it "hides tables that anonymous does not own" $
|
||||
get "/authors_only" `shouldRespondWith` 404
|
||||
|
||||
it "indicates login failure (BasicAuth)" $ do
|
||||
let auth = authHeaderBasic "postgrest_test_author" "fakefake"
|
||||
request methodGet "/authors_only" [auth] ""
|
||||
`shouldRespondWith` 401
|
||||
|
||||
it "allows users with permissions to see their tables (BasicAuth)" $ do
|
||||
_ <- post "/postgrest/users" [json| { "id": "jdoe", "pass": "1234", "role": "postgrest_test_author" } |]
|
||||
let auth = authHeaderBasic "jdoe" "1234"
|
||||
request methodGet "/authors_only" [auth] ""
|
||||
`shouldRespondWith` 200
|
||||
|
||||
it "respects database constraints for role" $
|
||||
post "/postgrest/users" [json| { "id": "ssmith", "pass": "1234", "role": "SUPER_ADMIN_TRUNCATE_POWERS" } |]
|
||||
`shouldRespondWith` 400
|
||||
|
||||
it "does not send a value when no role is provided" $ do
|
||||
post "/postgrest/users" [json| { "id": "bdeey", "pass": "1234" } |]
|
||||
`shouldRespondWith` 201
|
||||
let auth = authHeaderBasic "jdoe" "1234"
|
||||
request methodGet "/authors_only" [auth] ""
|
||||
`shouldRespondWith` 200
|
||||
|
||||
it "recovers after 400 error with logged in user" $ do
|
||||
_ <- post "/postgrest/users" [json| { "id": "jdoe", "pass": "1234", "role": "postgrest_test_author" } |]
|
||||
let auth = authHeaderBasic "jdoe" "1234"
|
||||
_ <- request methodPost "/rpc/problem" [auth] ""
|
||||
request methodGet "/authors_only" [auth] ""
|
||||
`shouldRespondWith` 200
|
||||
|
||||
it "allows users to login (JWT)" $ do
|
||||
_ <- post "/postgrest/users" [json| { "id": "jdoe", "pass": "1234", "role": "postgrest_test_author" } |]
|
||||
post "/postgrest/tokens" [json| { "id": "jdoe", "pass": "1234" } |]
|
||||
it "returns jwt functions as jwt tokens" $
|
||||
post "/rpc/login" [json| { "id": "jdoe", "pass": "1234" } |]
|
||||
`shouldRespondWith` ResponseMatcher {
|
||||
matchBody = Just [json| {"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIiwiaWQiOiJqZG9lIn0.y4vZuu1dDdwAl0-S00MCRWRYMlJ5YAMSir6Es6WtWx0"} |]
|
||||
, matchStatus = 201
|
||||
, matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json"]
|
||||
}
|
||||
|
||||
it "indicates login failure (JWT)" $ do
|
||||
_ <- post "/postgrest/users" [json| { "id": "jdoe", "pass": "1234", "role": "postgrest_test_author" } |]
|
||||
post "/postgrest/tokens" [json| { "id": "jdoe", "pass": "NOPE" } |]
|
||||
`shouldRespondWith` ResponseMatcher {
|
||||
matchBody = Just [json| {"message":"Failed authentication."} |]
|
||||
, matchStatus = 401
|
||||
, matchHeaders = ["Content-Type" <:> "application/json"]
|
||||
}
|
||||
|
||||
it "allows users with permissions to see their tables (JWT)" $ do
|
||||
_ <- post "/postgrest/users" [json| { "id": "jdoe", "pass": "1234", "role": "postgrest_test_author" } |]
|
||||
it "allows users with permissions to see their tables" $ do
|
||||
let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIiwiaWQiOiJqZG9lIn0.y4vZuu1dDdwAl0-S00MCRWRYMlJ5YAMSir6Es6WtWx0"
|
||||
request methodGet "/authors_only" [auth] ""
|
||||
`shouldRespondWith` 200
|
||||
|
||||
it "works with tokens which have extra fields" $ do
|
||||
let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIiwiaWQiOiJqZG9lIiwia2V5MSI6InZhbHVlMSIsImtleTIiOiJ2YWx1ZTIiLCJrZXkzIjoidmFsdWUzIiwiYSI6MSwiYiI6MiwiYyI6M30.GfydCh-F4wnM379xs0n1zUgalwJIsb6YoBapCo8HlFk"
|
||||
request methodGet "/authors_only" [auth] ""
|
||||
`shouldRespondWith` 200
|
||||
|
||||
-- this test will stop working 9999999999s after the UNIX EPOCH
|
||||
it "succeeds with an unexpired token" $ do
|
||||
let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjk5OTk5OTk5OTksInJvbGUiOiJwb3N0Z3Jlc3RfdGVzdF9hdXRob3IiLCJpZCI6Impkb2UifQ.QaPPLWTuyydMu_q7H4noMT7Lk6P4muet1OpJXF6ofhc"
|
||||
request methodGet "/authors_only" [auth] ""
|
||||
`shouldRespondWith` 200
|
||||
|
||||
it "fails with an expired token" $ do
|
||||
let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NDY2NzgxNDksInJvbGUiOiJwb3N0Z3Jlc3RfdGVzdF9hdXRob3IiLCJpZCI6Impkb2UifQ.enk_qZ_u6gZsXY4R8bREKB_HNExRpM0lIWSLktk9JJQ"
|
||||
request methodGet "/authors_only" [auth] ""
|
||||
`shouldRespondWith` 400
|
||||
|
||||
it "hides tables from users with invalid JWT" $ do
|
||||
let auth = authHeaderJWT "ey9zdGdyZXN0X3Rlc3RfYXV0aG9yIiwiaWQiOiJqZG9lIn0.y4vZuu1dDdwAl0-S00MCRWRYMlJ5YAMSir6Es6WtWx0"
|
||||
request methodGet "/authors_only" [auth] ""
|
||||
`shouldRespondWith` 400
|
||||
|
||||
it "should fail when jwt contains no claims" $ do
|
||||
let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.MKYc_lOECtB0LJOiykilAdlHodB-I0_id2qHKq35dmc"
|
||||
request methodGet "/authors_only" [auth] ""
|
||||
`shouldRespondWith` 400
|
||||
|
||||
it "hides tables from users with JWT that contain no claims about role" $ do
|
||||
let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6Impkb2UifQ.zyohGMnrDy4_8eJTl6I2AUXO3MeCCiwR24aGWRkTE9o"
|
||||
request methodGet "/authors_only" [auth] ""
|
||||
`shouldRespondWith` 400
|
||||
|
||||
it "recovers after 400 error with logged in user" $ do
|
||||
_ <- post "/authors_only" [json| { "owner": "jdoe", "secret": "test content" } |]
|
||||
let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIiwiaWQiOiJqZG9lIn0.y4vZuu1dDdwAl0-S00MCRWRYMlJ5YAMSir6Es6WtWx0"
|
||||
_ <- request methodPost "/rpc/problem" [auth] ""
|
||||
request methodGet "/authors_only" [auth] ""
|
||||
`shouldRespondWith` 200
|
||||
|
||||
@@ -41,7 +41,7 @@ spec = around withApp $ describe "CORS" $ do
|
||||
"true"
|
||||
respHeaders `shouldSatisfy` matchHeader
|
||||
"Access-Control-Allow-Methods"
|
||||
"GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD"
|
||||
"GET, POST, PATCH, DELETE, OPTIONS, HEAD"
|
||||
respHeaders `shouldSatisfy` matchHeader
|
||||
"Access-Control-Allow-Headers"
|
||||
"Authentication, Foo, Bar, Accept, Accept-Language, Content-Language"
|
||||
|
||||
+113
-41
@@ -1,6 +1,6 @@
|
||||
module Feature.InsertSpec where
|
||||
|
||||
import Test.Hspec
|
||||
import Test.Hspec hiding (pendingWith)
|
||||
import Test.Hspec.Wai
|
||||
import Test.Hspec.Wai.JSON
|
||||
import Network.Wai.Test (SResponse(simpleBody,simpleHeaders,simpleStatus))
|
||||
@@ -19,16 +19,38 @@ import TestTypes(IncPK(..), CompoundPK(..))
|
||||
spec :: Spec
|
||||
spec = afterAll_ resetDb $ around withApp $ do
|
||||
describe "Posting new record" $ do
|
||||
after_ (clearTable "menagerie") . it "accepts disparate json types" $ do
|
||||
p <- post "/menagerie"
|
||||
[json| {
|
||||
"integer": 13, "double": 3.14159, "varchar": "testing!"
|
||||
, "boolean": false, "date": "1900-01-01", "money": "$3.99"
|
||||
, "enum": "foo"
|
||||
} |]
|
||||
liftIO $ do
|
||||
simpleBody p `shouldBe` ""
|
||||
simpleStatus p `shouldBe` created201
|
||||
after_ (clearTable "menagerie") . context "disparate csv types" $ do
|
||||
it "accepts disparate json types" $ do
|
||||
p <- post "/menagerie"
|
||||
[json| {
|
||||
"integer": 13, "double": 3.14159, "varchar": "testing!"
|
||||
, "boolean": false, "date": "1900-01-01", "money": "$3.99"
|
||||
, "enum": "foo"
|
||||
} |]
|
||||
liftIO $ do
|
||||
simpleBody p `shouldBe` ""
|
||||
simpleStatus p `shouldBe` created201
|
||||
|
||||
it "filters columns in result using &select" $
|
||||
request methodPost "/menagerie?select=integer,varchar" [("Prefer", "return=representation")]
|
||||
[json| {
|
||||
"integer": 14, "double": 3.14159, "varchar": "testing!"
|
||||
, "boolean": false, "date": "1900-01-01", "money": "$3.99"
|
||||
, "enum": "foo"
|
||||
} |] `shouldRespondWith` ResponseMatcher {
|
||||
matchBody = Just [str|{"integer":14,"varchar":"testing!"}|]
|
||||
, matchStatus = 201
|
||||
, matchHeaders = ["Content-Type" <:> "application/json"]
|
||||
}
|
||||
|
||||
it "includes related data after insert" $
|
||||
request methodPost "/projects?select=id,name,clients(id,name)" [("Prefer", "return=representation")]
|
||||
[str|{"id":5,"name":"New Project","client_id":2}|] `shouldRespondWith` ResponseMatcher {
|
||||
matchBody = Just [str|{"id":5,"name":"New Project","clients":{"id":2,"name":"Apple"}}|]
|
||||
, matchStatus = 201
|
||||
, matchHeaders = ["Content-Type" <:> "application/json", "Location" <:> "/projects?id=eq.5"]
|
||||
}
|
||||
|
||||
|
||||
context "with no pk supplied" $ do
|
||||
context "into a table with auto-incrementing pk" . after_ (clearTable "auto_incrementing_pk") $
|
||||
@@ -92,55 +114,99 @@ spec = afterAll_ resetDb $ around withApp $ do
|
||||
context "jsonb" . after_ (clearTable "json") $ do
|
||||
it "serializes nested object" $ do
|
||||
let inserted = [json| { "data": { "foo":"bar" } } |]
|
||||
p <- request methodPost "json" [("Prefer", "return=representation")] inserted
|
||||
liftIO $ do
|
||||
simpleBody p `shouldBe` inserted
|
||||
simpleHeaders p `shouldSatisfy` matchHeader hLocation "/json\\?data=eq\\.%7B%22foo%22%3A%22bar%22%7D"
|
||||
simpleStatus p `shouldBe` created201
|
||||
request methodPost "/json"
|
||||
[("Prefer", "return=representation")]
|
||||
inserted
|
||||
`shouldRespondWith` ResponseMatcher {
|
||||
matchBody = Just inserted
|
||||
, matchStatus = 201
|
||||
, matchHeaders = ["Location" <:> [str|/json?data=eq.{"foo":"bar"}|]]
|
||||
}
|
||||
|
||||
-- TODO! the test above seems right, why was the one below working before and not now
|
||||
-- p <- request methodPost "/json" [("Prefer", "return=representation")] inserted
|
||||
-- liftIO $ do
|
||||
-- simpleBody p `shouldBe` inserted
|
||||
-- simpleHeaders p `shouldSatisfy` matchHeader hLocation "/json\\?data=eq\\.%7B%22foo%22%3A%22bar%22%7D"
|
||||
-- simpleStatus p `shouldBe` created201
|
||||
|
||||
it "serializes nested array" $ do
|
||||
let inserted = [json| { "data": [1,2,3] } |]
|
||||
p <- request methodPost "json" [("Prefer", "return=representation")] inserted
|
||||
liftIO $ do
|
||||
simpleBody p `shouldBe` inserted
|
||||
simpleHeaders p `shouldSatisfy` matchHeader hLocation "/json\\?data=eq\\.%5B1%2C2%2C3%5D"
|
||||
simpleStatus p `shouldBe` created201
|
||||
request methodPost "/json"
|
||||
[("Prefer", "return=representation")]
|
||||
inserted
|
||||
`shouldRespondWith` ResponseMatcher {
|
||||
matchBody = Just inserted
|
||||
, matchStatus = 201
|
||||
, matchHeaders = ["Location" <:> [str|/json?data=eq.[1,2,3]|]]
|
||||
}
|
||||
-- TODO! the test above seems right, why was the one below working before and not now
|
||||
-- p <- request methodPost "/json" [("Prefer", "return=representation")] inserted
|
||||
-- liftIO $ do
|
||||
-- simpleBody p `shouldBe` inserted
|
||||
-- simpleHeaders p `shouldSatisfy` matchHeader hLocation "/json\\?data=eq\\.%5B1%2C2%2C3%5D"
|
||||
-- simpleStatus p `shouldBe` created201
|
||||
|
||||
describe "CSV insert" $ do
|
||||
|
||||
after_ (clearTable "menagerie") . context "disparate csv types" $
|
||||
it "succeeds with multipart response" $ do
|
||||
p <- request methodPost "/menagerie" [("Content-Type", "text/csv")]
|
||||
[str|integer,double,varchar,boolean,date,money,enum
|
||||
|13,3.14159,testing!,false,1900-01-01,$3.99,foo
|
||||
|12,0.1,a string,true,1929-10-01,12,bar
|
||||
|]
|
||||
liftIO $ do
|
||||
simpleBody p `shouldBe` "Content-Type: application/json\nLocation: /menagerie?integer=eq.13\n\n\n--postgrest_boundary\nContent-Type: application/json\nLocation: /menagerie?integer=eq.12\n\n"
|
||||
simpleStatus p `shouldBe` created201
|
||||
pendingWith "Decide on what to do with CSV insert"
|
||||
let inserted = [str|integer,double,varchar,boolean,date,money,enum
|
||||
|13,3.14159,testing!,false,1900-01-01,$3.99,foo
|
||||
|12,0.1,a string,true,1929-10-01,12,bar
|
||||
|]
|
||||
request methodPost "/menagerie" [("Content-Type", "text/csv"), ("Accept", "text/csv"), ("Prefer", "return=representation")] inserted
|
||||
|
||||
`shouldRespondWith` ResponseMatcher {
|
||||
matchBody = Just inserted
|
||||
, matchStatus = 201
|
||||
, matchHeaders = ["Content-Type" <:> "text/csv"]
|
||||
}
|
||||
-- p <- request methodPost "/menagerie" [("Content-Type", "text/csv")]
|
||||
-- [str|integer,double,varchar,boolean,date,money,enum
|
||||
-- |13,3.14159,testing!,false,1900-01-01,$3.99,foo
|
||||
-- |12,0.1,a string,true,1929-10-01,12,bar
|
||||
-- |]
|
||||
-- liftIO $ do
|
||||
-- simpleBody p `shouldBe` "Content-Type: application/json\nLocation: /menagerie?integer=eq.13\n\n\n--postgrest_boundary\nContent-Type: application/json\nLocation: /menagerie?integer=eq.12\n\n"
|
||||
-- simpleStatus p `shouldBe` created201
|
||||
|
||||
after_ (clearTable "no_pk") . context "requesting full representation" $ do
|
||||
it "returns full details of inserted record" $
|
||||
request methodPost "/no_pk"
|
||||
[("Content-Type", "text/csv"), ("Prefer", "return=representation")]
|
||||
[("Content-Type", "text/csv"), ("Accept", "text/csv"), ("Prefer", "return=representation")]
|
||||
"a,b\nbar,baz"
|
||||
`shouldRespondWith` ResponseMatcher {
|
||||
matchBody = Just [json| { "a":"bar", "b":"baz" } |]
|
||||
matchBody = Just "a,b\nbar,baz"
|
||||
, matchStatus = 201
|
||||
, matchHeaders = ["Content-Type" <:> "application/json",
|
||||
, matchHeaders = ["Content-Type" <:> "text/csv",
|
||||
"Location" <:> "/no_pk?a=eq.bar&b=eq.baz"]
|
||||
}
|
||||
|
||||
-- it "can post nulls (old way)" $ do
|
||||
-- pendingWith "changed the response when in csv mode"
|
||||
-- request methodPost "/no_pk"
|
||||
-- [("Content-Type", "text/csv"), ("Prefer", "return=representation")]
|
||||
-- "a,b\nNULL,foo"
|
||||
-- `shouldRespondWith` ResponseMatcher {
|
||||
-- matchBody = Just [json| { "a":null, "b":"foo" } |]
|
||||
-- , matchStatus = 201
|
||||
-- , matchHeaders = ["Content-Type" <:> "application/json",
|
||||
-- "Location" <:> "/no_pk?a=is.null&b=eq.foo"]
|
||||
-- }
|
||||
it "can post nulls" $
|
||||
request methodPost "/no_pk"
|
||||
[("Content-Type", "text/csv"), ("Prefer", "return=representation")]
|
||||
[("Content-Type", "text/csv"), ("Accept", "text/csv"), ("Prefer", "return=representation")]
|
||||
"a,b\nNULL,foo"
|
||||
`shouldRespondWith` ResponseMatcher {
|
||||
matchBody = Just [json| { "a":null, "b":"foo" } |]
|
||||
matchBody = Just "a,b\n,foo"
|
||||
, matchStatus = 201
|
||||
, matchHeaders = ["Content-Type" <:> "application/json",
|
||||
, matchHeaders = ["Content-Type" <:> "text/csv",
|
||||
"Location" <:> "/no_pk?a=is.null&b=eq.foo"]
|
||||
}
|
||||
|
||||
|
||||
after_ (clearTable "no_pk") . context "with wrong number of columns" $ do
|
||||
it "fails for too few" $ do
|
||||
p <- request methodPost "/no_pk" [("Content-Type", "text/csv")] "a,b\nfoo,bar\nbaz"
|
||||
@@ -159,7 +225,8 @@ spec = afterAll_ resetDb $ around withApp $ do
|
||||
|
||||
context "to a known uri" $ do
|
||||
context "without a fully-specified primary key" $
|
||||
it "is not an allowed operation" $
|
||||
it "is not an allowed operation" $ do
|
||||
pendingWith "Decide on PUT usefullness"
|
||||
request methodPut "/compound_pk?k1=eq.12" []
|
||||
[json| { "k1":12, "k2":42 } |]
|
||||
`shouldRespondWith` 405
|
||||
@@ -167,13 +234,15 @@ spec = afterAll_ resetDb $ around withApp $ do
|
||||
context "with a fully-specified primary key" $ do
|
||||
|
||||
context "not specifying every column in the table" $
|
||||
it "is rejected for lack of idempotence" $
|
||||
it "is rejected for lack of idempotence" $ do
|
||||
pendingWith "Decide on PUT usefullness"
|
||||
request methodPut "/compound_pk?k1=eq.12&k2=eq.42" []
|
||||
[json| { "k1":12, "k2":42 } |]
|
||||
`shouldRespondWith` 400
|
||||
|
||||
context "specifying every column in the table" . after_ (clearTable "compound_pk") $ do
|
||||
it "can create a new record" $ do
|
||||
pendingWith "Decide on PUT usefullness"
|
||||
p <- request methodPut "/compound_pk?k1=eq.12&k2=eq.42" []
|
||||
[json| { "k1":12, "k2":42, "extra":3 } |]
|
||||
liftIO $ do
|
||||
@@ -190,6 +259,7 @@ spec = afterAll_ resetDb $ around withApp $ do
|
||||
compoundExtra record `shouldBe` Just 3
|
||||
|
||||
it "can update an existing record" $ do
|
||||
pendingWith "Decide on PUT usefullness"
|
||||
_ <- request methodPut "/compound_pk?k1=eq.12&k2=eq.42" []
|
||||
[json| { "k1":12, "k2":42, "extra":4 } |]
|
||||
_ <- request methodPut "/compound_pk?k1=eq.12&k2=eq.42" []
|
||||
@@ -204,7 +274,8 @@ spec = afterAll_ resetDb $ around withApp $ do
|
||||
|
||||
context "with an auto-incrementing primary key" . after_ (clearTable "auto_incrementing_pk") $
|
||||
|
||||
it "succeeds with 204" $
|
||||
it "succeeds with 204" $ do
|
||||
pendingWith "Decide on PUT usefullness"
|
||||
request methodPut "/auto_incrementing_pk?id=eq.1" []
|
||||
[json| {
|
||||
"id":1,
|
||||
@@ -284,14 +355,15 @@ spec = afterAll_ resetDb $ around withApp $ do
|
||||
|
||||
describe "Row level permission" $
|
||||
it "set user_id when inserting rows" $ do
|
||||
let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIiwiaWQiOiJqZG9lIn0.y4vZuu1dDdwAl0-S00MCRWRYMlJ5YAMSir6Es6WtWx0"
|
||||
_ <- 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"
|
||||
[ authHeaderBasic "jdoe" "1234", ("Prefer", "return=representation") ]
|
||||
[ auth, ("Prefer", "return=representation") ]
|
||||
[json| { "secret": "nyancat" } |]
|
||||
liftIO $ do
|
||||
simpleBody p1 `shouldBe` [json| { "owner":"jdoe", "secret":"nyancat" } |]
|
||||
simpleBody p1 `shouldBe` [str|{"owner":"jdoe","secret":"nyancat"}|]
|
||||
simpleStatus p1 `shouldBe` created201
|
||||
|
||||
p2 <- request methodPost "/authors_only"
|
||||
@@ -299,5 +371,5 @@ spec = afterAll_ resetDb $ around withApp $ do
|
||||
[ authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIiwiaWQiOiJqcm9lIn0.YuF_VfmyIxWyuceT7crnNKEprIYXsJAyXid3rjPjIow", ("Prefer", "return=representation") ]
|
||||
[json| { "secret": "lolcat", "owner": "hacker" } |]
|
||||
liftIO $ do
|
||||
simpleBody p2 `shouldBe` [json| { "owner":"jroe", "secret":"lolcat" } |]
|
||||
simpleBody p2 `shouldBe` [str|{"owner":"jroe","secret":"lolcat"}|]
|
||||
simpleStatus p2 `shouldBe` created201
|
||||
|
||||
@@ -7,10 +7,13 @@ import Network.HTTP.Types
|
||||
import Network.Wai.Test (SResponse(simpleHeaders))
|
||||
|
||||
import SpecHelper
|
||||
import Text.Heredoc
|
||||
|
||||
|
||||
spec :: Spec
|
||||
spec =
|
||||
beforeAll (clearTable "items" >> createItems 15)
|
||||
. beforeAll clearProjectsTable
|
||||
. beforeAll (clearTable "complex_items" >> createComplexItems)
|
||||
. beforeAll (clearTable "nullable_integer" >> createNullInteger)
|
||||
. beforeAll (
|
||||
@@ -134,11 +137,20 @@ spec =
|
||||
get "/clients?select=id,projects(id,tasks(id,name))&projects.tasks.name=like.Design*" `shouldRespondWith`
|
||||
"[{\"id\":1,\"projects\":[{\"id\":1,\"tasks\":[{\"id\":1,\"name\":\"Design w7\"}]},{\"id\":2,\"tasks\":[{\"id\":3,\"name\":\"Design w10\"}]}]},{\"id\":2,\"projects\":[{\"id\":3,\"tasks\":[{\"id\":5,\"name\":\"Design IOS\"}]},{\"id\":4,\"tasks\":[{\"id\":7,\"name\":\"Design OSX\"}]}]}]"
|
||||
|
||||
it "matches with @> operator" $
|
||||
get "/complex_items?select=id&arr_data=@>.{2}" `shouldRespondWith`
|
||||
[str|[{"id":2},{"id":3}]|]
|
||||
|
||||
it "matches with <@ operator" $
|
||||
get "/complex_items?select=id&arr_data=<@.{1,2,4}" `shouldRespondWith`
|
||||
[str|[{"id":1},{"id":2}]|]
|
||||
|
||||
|
||||
describe "Shaping response with select parameter" $ do
|
||||
|
||||
it "selectStar works in absense of parameter" $
|
||||
get "/complex_items?id=eq.3" `shouldRespondWith`
|
||||
"[{\"id\":3,\"name\":\"Three\",\"settings\":{\"foo\":{\"int\":1,\"bar\":\"baz\"}}}]"
|
||||
[str|[{"id":3,"name":"Three","settings":{"foo":{"int":1,"bar":"baz"}},"arr_data":[1,2,3]}]|]
|
||||
|
||||
it "one simple column" $
|
||||
get "/complex_items?select=id" `shouldRespondWith`
|
||||
@@ -272,7 +284,7 @@ spec =
|
||||
request methodGet "/simple_pk"
|
||||
(acceptHdrs "text/csv; version=1") ""
|
||||
`shouldRespondWith` ResponseMatcher {
|
||||
matchBody = Just "k,extra\rxyyx,u\rxYYx,v"
|
||||
matchBody = Just "k,extra\nxyyx,u\nxYYx,v"
|
||||
, matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "text/csv"]
|
||||
}
|
||||
|
||||
+140
-121
@@ -14,42 +14,42 @@ spec = around withApp $ do
|
||||
it "lists views in schema" $
|
||||
request methodGet "/" [] ""
|
||||
`shouldRespondWith` [json| [
|
||||
{"schema":"1","name":"auto_incrementing_pk","insertable":true}
|
||||
, {"schema":"1","name":"clients","insertable":true}
|
||||
, {"schema":"1","name":"comments","insertable":true}
|
||||
, {"schema":"1","name":"complex_items","insertable":true}
|
||||
, {"schema":"1","name":"compound_pk","insertable":true}
|
||||
, {"schema":"1","name":"has_count_column","insertable":false}
|
||||
, {"schema":"1","name":"has_fk","insertable":true}
|
||||
, {"schema":"1","name":"insertable_view_with_join","insertable":true}
|
||||
, {"schema":"1","name":"items","insertable":true}
|
||||
, {"schema":"1","name":"json","insertable":true}
|
||||
, {"schema":"1","name":"materialized_view","insertable":false}
|
||||
, {"schema":"1","name":"menagerie","insertable":true}
|
||||
, {"schema":"1","name":"no_pk","insertable":true}
|
||||
, {"schema":"1","name":"nullable_integer","insertable":true}
|
||||
, {"schema":"1","name":"projects","insertable":true}
|
||||
, {"schema":"1","name":"projects_view","insertable":true}
|
||||
, {"schema":"1","name":"simple_pk","insertable":true}
|
||||
, {"schema":"1","name":"tasks","insertable":true}
|
||||
, {"schema":"1","name":"tsearch","insertable":true}
|
||||
, {"schema":"1","name":"users","insertable":true}
|
||||
, {"schema":"1","name":"users_projects","insertable":true}
|
||||
, {"schema":"1","name":"users_tasks","insertable":true}
|
||||
{"schema":"test","name":"articleStars","insertable":true}
|
||||
, {"schema":"test","name":"articles","insertable":true}
|
||||
, {"schema":"test","name":"auto_incrementing_pk","insertable":true}
|
||||
, {"schema":"test","name":"clients","insertable":true}
|
||||
, {"schema":"test","name":"comments","insertable":true}
|
||||
, {"schema":"test","name":"complex_items","insertable":true}
|
||||
, {"schema":"test","name":"compound_pk","insertable":true}
|
||||
, {"schema":"test","name":"has_count_column","insertable":false}
|
||||
, {"schema":"test","name":"has_fk","insertable":true}
|
||||
, {"schema":"test","name":"insertable_view_with_join","insertable":true}
|
||||
, {"schema":"test","name":"items","insertable":true}
|
||||
, {"schema":"test","name":"json","insertable":true}
|
||||
, {"schema":"test","name":"materialized_view","insertable":false}
|
||||
, {"schema":"test","name":"menagerie","insertable":true}
|
||||
, {"schema":"test","name":"no_pk","insertable":true}
|
||||
, {"schema":"test","name":"nullable_integer","insertable":true}
|
||||
, {"schema":"test","name":"projects","insertable":true}
|
||||
, {"schema":"test","name":"projects_view","insertable":true}
|
||||
, {"schema":"test","name":"simple_pk","insertable":true}
|
||||
, {"schema":"test","name":"tasks","insertable":true}
|
||||
, {"schema":"test","name":"tsearch","insertable":true}
|
||||
, {"schema":"test","name":"users","insertable":true}
|
||||
, {"schema":"test","name":"users_projects","insertable":true}
|
||||
, {"schema":"test","name":"users_tasks","insertable":true}
|
||||
] |]
|
||||
{matchStatus = 200}
|
||||
|
||||
it "lists only views user has permission to see" $ do
|
||||
_ <- post "/postgrest/users" [json| { "id":"jdoe", "pass": "1234", "role": "postgrest_test_author" } |]
|
||||
let auth = authHeaderBasic "jdoe" "1234"
|
||||
let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIiwiaWQiOiJqZG9lIn0.y4vZuu1dDdwAl0-S00MCRWRYMlJ5YAMSir6Es6WtWx0"
|
||||
|
||||
request methodGet "/" [auth] ""
|
||||
`shouldRespondWith` [json| [
|
||||
{"schema":"1","name":"authors_only","insertable":true}
|
||||
{"schema":"test","name":"authors_only","insertable":true}
|
||||
] |]
|
||||
{matchStatus = 200}
|
||||
|
||||
|
||||
describe "Table info" $ do
|
||||
it "is available with OPTIONS verb" $
|
||||
request methodOptions "/menagerie" [] "" `shouldRespondWith`
|
||||
@@ -61,7 +61,7 @@ spec = around withApp $ do
|
||||
"default": null,
|
||||
"precision": 32,
|
||||
"updatable": true,
|
||||
"schema": "1",
|
||||
"schema": "test",
|
||||
"name": "integer",
|
||||
"type": "integer",
|
||||
"maxLen": null,
|
||||
@@ -74,7 +74,7 @@ spec = around withApp $ do
|
||||
"default": null,
|
||||
"precision": 53,
|
||||
"updatable": true,
|
||||
"schema": "1",
|
||||
"schema": "test",
|
||||
"name": "double",
|
||||
"type": "double precision",
|
||||
"maxLen": null,
|
||||
@@ -86,7 +86,7 @@ spec = around withApp $ do
|
||||
"default": null,
|
||||
"precision": null,
|
||||
"updatable": true,
|
||||
"schema": "1",
|
||||
"schema": "test",
|
||||
"name": "varchar",
|
||||
"type": "character varying",
|
||||
"maxLen": null,
|
||||
@@ -99,7 +99,7 @@ spec = around withApp $ do
|
||||
"default": null,
|
||||
"precision": null,
|
||||
"updatable": true,
|
||||
"schema": "1",
|
||||
"schema": "test",
|
||||
"name": "boolean",
|
||||
"type": "boolean",
|
||||
"maxLen": null,
|
||||
@@ -111,7 +111,7 @@ spec = around withApp $ do
|
||||
"default": null,
|
||||
"precision": null,
|
||||
"updatable": true,
|
||||
"schema": "1",
|
||||
"schema": "test",
|
||||
"name": "date",
|
||||
"type": "date",
|
||||
"maxLen": null,
|
||||
@@ -123,7 +123,7 @@ spec = around withApp $ do
|
||||
"default": null,
|
||||
"precision": null,
|
||||
"updatable": true,
|
||||
"schema": "1",
|
||||
"schema": "test",
|
||||
"name": "money",
|
||||
"type": "money",
|
||||
"maxLen": null,
|
||||
@@ -136,7 +136,7 @@ spec = around withApp $ do
|
||||
"default": null,
|
||||
"precision": null,
|
||||
"updatable": true,
|
||||
"schema": "1",
|
||||
"schema": "test",
|
||||
"name": "enum",
|
||||
"type": "USER-DEFINED",
|
||||
"maxLen": null,
|
||||
@@ -154,98 +154,57 @@ spec = around withApp $ do
|
||||
|]
|
||||
|
||||
it "it includes primary and foreign keys for views" $
|
||||
request methodOptions "/insertable_view_with_join" [] "" `shouldRespondWith`
|
||||
request methodOptions "/projects_view" [] "" `shouldRespondWith`
|
||||
[json|
|
||||
{
|
||||
"pkey":[
|
||||
"id"
|
||||
],
|
||||
"columns":[
|
||||
{
|
||||
"references":null,
|
||||
"default":null,
|
||||
"precision":64,
|
||||
"updatable":false,
|
||||
"schema":"1",
|
||||
"name":"id",
|
||||
"type":"bigint",
|
||||
"maxLen":null,
|
||||
"enum":[],
|
||||
"nullable":true,
|
||||
"position":1
|
||||
{
|
||||
"references":null,
|
||||
"default":null,
|
||||
"precision":32,
|
||||
"updatable":true,
|
||||
"schema":"test",
|
||||
"name":"id",
|
||||
"type":"integer",
|
||||
"maxLen":null,
|
||||
"enum":[],
|
||||
"nullable":true,
|
||||
"position":1
|
||||
},
|
||||
{
|
||||
"references":null,
|
||||
"default":null,
|
||||
"precision":null,
|
||||
"updatable":true,
|
||||
"schema":"test",
|
||||
"name":"name",
|
||||
"type":"text",
|
||||
"maxLen":null,
|
||||
"enum":[],
|
||||
"nullable":true,
|
||||
"position":2
|
||||
},
|
||||
{
|
||||
"references": {
|
||||
"schema":"test",
|
||||
"column":"id",
|
||||
"table":"clients"
|
||||
},
|
||||
{
|
||||
"references":{
|
||||
"column":"id",
|
||||
"table":"auto_incrementing_pk"
|
||||
},
|
||||
"default":null,
|
||||
"precision":32,
|
||||
"updatable":false,
|
||||
"schema":"1",
|
||||
"name":"auto_inc_fk",
|
||||
"type":"integer",
|
||||
"maxLen":null,
|
||||
"enum":[],
|
||||
"nullable":true,
|
||||
"position":2
|
||||
},
|
||||
{
|
||||
"references":{
|
||||
"column":"k",
|
||||
"table":"simple_pk"
|
||||
},
|
||||
"default":null,
|
||||
"precision":null,
|
||||
"updatable":false,
|
||||
"schema":"1",
|
||||
"name":"simple_fk",
|
||||
"type":"character varying",
|
||||
"maxLen":255,
|
||||
"enum":[],
|
||||
"nullable":true,
|
||||
"position":3
|
||||
},
|
||||
{
|
||||
"references":null,
|
||||
"default":null,
|
||||
"precision":null,
|
||||
"updatable":false,
|
||||
"schema":"1",
|
||||
"name":"nullable_string",
|
||||
"type":"character varying",
|
||||
"maxLen":null,
|
||||
"enum":[],
|
||||
"nullable":true,
|
||||
"position":4
|
||||
},
|
||||
{
|
||||
"references":null,
|
||||
"default":null,
|
||||
"precision":null,
|
||||
"updatable":false,
|
||||
"schema":"1",
|
||||
"name":"non_nullable_string",
|
||||
"type":"character varying",
|
||||
"maxLen":null,
|
||||
"enum":[],
|
||||
"nullable":true,
|
||||
"position":5
|
||||
},
|
||||
{
|
||||
"references":null,
|
||||
"default":null,
|
||||
"precision":null,
|
||||
"updatable":false,
|
||||
"schema":"1",
|
||||
"name":"inserted_at",
|
||||
"type":"timestamp with time zone",
|
||||
"maxLen":null,
|
||||
"enum":[],
|
||||
"nullable":true,
|
||||
"position":6
|
||||
}
|
||||
]
|
||||
"default":null,
|
||||
"precision":32,
|
||||
"updatable":true,
|
||||
"schema":"test",
|
||||
"name":"client_id",
|
||||
"type":"integer",
|
||||
"maxLen":null,
|
||||
"enum":[],
|
||||
"nullable":true,
|
||||
"position":3
|
||||
}
|
||||
]
|
||||
}
|
||||
|]
|
||||
|
||||
@@ -261,7 +220,7 @@ spec = around withApp $ do
|
||||
"default": "nextval('\"1\".has_fk_id_seq'::regclass)",
|
||||
"precision": 64,
|
||||
"updatable": true,
|
||||
"schema": "1",
|
||||
"schema": "test",
|
||||
"name": "id",
|
||||
"type": "bigint",
|
||||
"maxLen": null,
|
||||
@@ -273,7 +232,7 @@ spec = around withApp $ do
|
||||
"default": null,
|
||||
"precision": 32,
|
||||
"updatable": true,
|
||||
"schema": "1",
|
||||
"schema": "test",
|
||||
"name": "auto_inc_fk",
|
||||
"type": "integer",
|
||||
"maxLen": null,
|
||||
@@ -285,7 +244,7 @@ spec = around withApp $ do
|
||||
"default": null,
|
||||
"precision": null,
|
||||
"updatable": true,
|
||||
"schema": "1",
|
||||
"schema": "test",
|
||||
"name": "simple_fk",
|
||||
"type": "character varying",
|
||||
"maxLen": 255,
|
||||
@@ -297,3 +256,63 @@ spec = around withApp $ do
|
||||
]
|
||||
}
|
||||
|]
|
||||
|
||||
it "includes all information on views for renamed columns, and raises relations to correct schema" $
|
||||
request methodOptions "/articleStars" [] ""
|
||||
`shouldRespondWith` [json|
|
||||
{
|
||||
"pkey": [
|
||||
"articleId",
|
||||
"userId"
|
||||
],
|
||||
"columns": [
|
||||
{
|
||||
"references": {
|
||||
"schema": "test",
|
||||
"column": "id",
|
||||
"table": "articles"
|
||||
},
|
||||
"default": null,
|
||||
"precision": 32,
|
||||
"updatable": true,
|
||||
"schema": "test",
|
||||
"name": "articleId",
|
||||
"type": "integer",
|
||||
"maxLen": null,
|
||||
"enum": [],
|
||||
"nullable": true,
|
||||
"position": 1
|
||||
},
|
||||
{
|
||||
"references": {
|
||||
"schema": "test",
|
||||
"column": "id",
|
||||
"table": "users"
|
||||
},
|
||||
"default": null,
|
||||
"precision": 32,
|
||||
"updatable": true,
|
||||
"schema": "test",
|
||||
"name": "userId",
|
||||
"type": "integer",
|
||||
"maxLen": null,
|
||||
"enum": [],
|
||||
"nullable": true,
|
||||
"position": 2
|
||||
},
|
||||
{
|
||||
"references": null,
|
||||
"default": null,
|
||||
"precision": null,
|
||||
"updatable": true,
|
||||
"schema": "test",
|
||||
"name": "createdAt",
|
||||
"type": "timestamp without time zone",
|
||||
"maxLen": null,
|
||||
"enum": [],
|
||||
"nullable": true,
|
||||
"position": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
|]
|
||||
|
||||
+29
-37
@@ -30,25 +30,23 @@ import PostgREST.App (app)
|
||||
import PostgREST.Config (AppConfig(..))
|
||||
import PostgREST.Middleware
|
||||
import PostgREST.Error(errResponse)
|
||||
import PostgREST.PgStructure
|
||||
import PostgREST.Types
|
||||
import PostgREST.DbStructure
|
||||
|
||||
dbString :: String
|
||||
dbString = "postgres://postgrest_test@localhost:5432/postgrest_test"
|
||||
|
||||
isLeft :: Either a b -> Bool
|
||||
isLeft (Left _ ) = True
|
||||
isLeft _ = False
|
||||
|
||||
cfg :: AppConfig
|
||||
cfg = AppConfig "postgrest_test" 5432 "postgrest_test" "" "localhost" 3000 "postgrest_anonymous" False 10 "1" "safe"
|
||||
cfg = AppConfig dbString 3000 "postgrest_anonymous" "test" "safe" 10
|
||||
|
||||
testPoolOpts :: PoolSettings
|
||||
testPoolOpts = fromMaybe (error "bad settings") $ H.poolSettings 1 30
|
||||
|
||||
pgSettings :: P.Settings
|
||||
pgSettings = P.ParamSettings (cs $ configDbHost cfg)
|
||||
(fromIntegral $ configDbPort cfg)
|
||||
(cs $ configDbUser cfg)
|
||||
(cs $ configDbPass cfg)
|
||||
(cs $ configDbName cfg)
|
||||
pgSettings = P.StringSettings $ cs dbString
|
||||
|
||||
withApp :: ActionWith Application -> IO ()
|
||||
withApp perform = do
|
||||
@@ -56,30 +54,16 @@ withApp perform = do
|
||||
<- H.acquirePool pgSettings testPoolOpts
|
||||
|
||||
let txSettings = Just (H.ReadCommitted, Just True)
|
||||
metadata <- H.session pool $ H.tx txSettings $ do
|
||||
tabs <- allTables
|
||||
rels <- allRelations
|
||||
cols <- allColumns rels
|
||||
keys <- allPrimaryKeys
|
||||
return (tabs, rels, cols, keys)
|
||||
|
||||
dbstructure <- case metadata of
|
||||
Left e -> fail $ show e
|
||||
Right (tabs, rels, cols, keys) ->
|
||||
return $ DbStructure {
|
||||
tables=tabs
|
||||
, columns=cols
|
||||
, relations=rels
|
||||
, primaryKeys=keys
|
||||
}
|
||||
dbOrError <- H.session pool $ H.tx txSettings $ getDbStructure (cs $ configSchema cfg)
|
||||
db <- either (fail . show) return dbOrError
|
||||
|
||||
perform $ middle $ \req resp -> do
|
||||
body <- strictRequestBody req
|
||||
result <- liftIO $ H.session pool $ H.tx txSettings
|
||||
$ authenticated cfg (app dbstructure cfg body) req
|
||||
$ runWithClaims cfg (app db cfg body) req
|
||||
either (resp . errResponse) resp result
|
||||
|
||||
where middle = defaultMiddle False
|
||||
where middle = defaultMiddle
|
||||
|
||||
|
||||
resetDb :: IO ()
|
||||
@@ -88,7 +72,7 @@ resetDb = do
|
||||
<- H.acquirePool pgSettings testPoolOpts
|
||||
void . liftIO $ H.session pool $
|
||||
H.tx Nothing $ do
|
||||
H.unitEx [H.stmt| drop schema if exists "1" cascade |]
|
||||
H.unitEx [H.stmt| drop schema if exists test cascade |]
|
||||
H.unitEx [H.stmt| drop schema if exists private cascade |]
|
||||
H.unitEx [H.stmt| drop schema if exists postgrest cascade |]
|
||||
|
||||
@@ -129,7 +113,14 @@ clearTable :: Text -> IO ()
|
||||
clearTable table = do
|
||||
pool <- testPool
|
||||
void . liftIO $ H.session pool $ H.tx Nothing $
|
||||
H.unitEx $ B.Stmt ("delete from \"1\"."<>table) V.empty True
|
||||
H.unitEx $ B.Stmt ("delete from test."<>table) V.empty True
|
||||
|
||||
clearProjectsTable :: IO ()
|
||||
clearProjectsTable = do
|
||||
pool <- testPool
|
||||
void . liftIO $ H.session pool $ H.tx Nothing $
|
||||
H.unitEx $ B.Stmt "delete from test.projects where id > 4" V.empty True
|
||||
|
||||
|
||||
createItems :: Int -> IO ()
|
||||
createItems n = do
|
||||
@@ -137,7 +128,7 @@ createItems n = do
|
||||
void . liftIO $ H.session pool $ H.tx Nothing txn
|
||||
where
|
||||
txn = mapM_ H.unitEx stmts
|
||||
stmts = map [H.stmt|insert into "1".items (id) values (?)|] [1..n]
|
||||
stmts = map [H.stmt|insert into test.items (id) values (?)|] [1..n]
|
||||
|
||||
createComplexItems :: IO ()
|
||||
createComplexItems = do
|
||||
@@ -145,11 +136,12 @@ createComplexItems = do
|
||||
void . liftIO $ H.session pool $ H.tx Nothing txn
|
||||
where
|
||||
txn = mapM_ H.unitEx stmts
|
||||
stmts = getZipList $ [H.stmt|insert into "1".complex_items (id, name, settings) values (?,?,?)|]
|
||||
stmts = getZipList $ [H.stmt|insert into test.complex_items (id, name, settings, arr_data) values (?,?,?,?)|]
|
||||
<$> ZipList ([1..3]::[Int])
|
||||
<*> ZipList (["One", "Two", "Three"]::[Text])
|
||||
<*> ZipList ([jobj,jobj,jobj])
|
||||
jobj = (J.object [("foo", J.object [("int", J.Number 1),("bar", J.String "baz")])])
|
||||
<*> ZipList [jobj,jobj,jobj]
|
||||
<*> ZipList ([[1], [1,2], [1,2,3]]::[[Int]])
|
||||
jobj = J.object [("foo", J.object [("int", J.Number 1),("bar", J.String "baz")])]
|
||||
|
||||
createNulls :: Int -> IO ()
|
||||
createNulls n = do
|
||||
@@ -157,14 +149,14 @@ createNulls n = do
|
||||
void . liftIO $ H.session pool $ H.tx Nothing txn
|
||||
where
|
||||
txn = mapM_ H.unitEx (stmt':stmts)
|
||||
stmt' = [H.stmt|insert into "1".no_pk (a,b) values (null,null)|]
|
||||
stmts = map [H.stmt|insert into "1".no_pk (a,b) values (?,0)|] [1..n]
|
||||
stmt' = [H.stmt|insert into test.no_pk (a,b) values (null,null)|]
|
||||
stmts = map [H.stmt|insert into test.no_pk (a,b) values (?,0)|] [1..n]
|
||||
|
||||
createNullInteger :: IO ()
|
||||
createNullInteger = do
|
||||
pool <- testPool
|
||||
void . liftIO $ H.session pool $ H.tx Nothing $
|
||||
H.unitEx $ [H.stmt| insert into "1".nullable_integer (a) values (null) |]
|
||||
H.unitEx $ [H.stmt| insert into "test".nullable_integer (a) values (null) |]
|
||||
|
||||
createLikableStrings :: IO ()
|
||||
createLikableStrings = do
|
||||
@@ -174,7 +166,7 @@ createLikableStrings = do
|
||||
H.unitEx $ insertSimplePk "xYYx" "v"
|
||||
where
|
||||
insertSimplePk :: Text -> Text -> H.Stmt P.Postgres
|
||||
insertSimplePk = [H.stmt|insert into "1".simple_pk (k, extra) values (?,?)|]
|
||||
insertSimplePk = [H.stmt|insert into test.simple_pk (k, extra) values (?,?)|]
|
||||
|
||||
createJsonData :: IO ()
|
||||
createJsonData = do
|
||||
@@ -182,7 +174,7 @@ createJsonData = do
|
||||
void . liftIO $ H.session pool $ H.tx Nothing $
|
||||
H.unitEx $
|
||||
[H.stmt|
|
||||
insert into "1".json (data) values (?)
|
||||
insert into test.json (data) values (?)
|
||||
|]
|
||||
(J.object [("id", J.Number 1)
|
||||
,("foo", J.object [("bar", J.String "baz")])
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module Unit.PgStructureSpec where
|
||||
module Unit.DbStructureSpec where
|
||||
|
||||
import Test.Hspec
|
||||
import PgStructure (Table(..), tables, Column(..), columns, ForeignKey(..),
|
||||
import DbStructure (Table(..), tables, Column(..), columns, ForeignKey(..),
|
||||
foreignKeys)
|
||||
|
||||
import Database.HDBC (quickQuery)
|
||||
@@ -12,25 +12,25 @@ spec :: Spec
|
||||
spec = around dbWithSchema $ beforeWith setRole $ do
|
||||
describe "tables" $
|
||||
it "shows all the tables" $ \conn -> do
|
||||
ts <- tables "1" conn
|
||||
ts <- tables "test" conn
|
||||
map tableName ts `shouldBe` ["authors_only","auto_incrementing_pk",
|
||||
"compound_pk","has_fk","insertable_view_with_join","items","menagerie","no_pk", "simple_pk"]
|
||||
|
||||
describe "columns" $ do
|
||||
it "responds with each column for the table" $ \conn -> do
|
||||
cs <- columns "1" "auto_incrementing_pk" conn
|
||||
cs <- columns "test" "auto_incrementing_pk" conn
|
||||
map colName cs `shouldBe` ["id","nullable_string","non_nullable_string",
|
||||
"inserted_at"]
|
||||
|
||||
it "includes foreign key data" $ \conn -> do
|
||||
cs <- columns "1" "has_fk" conn
|
||||
cs <- columns "test" "has_fk" conn
|
||||
map colFK cs `shouldBe` [Nothing,
|
||||
Just $ ForeignKey "auto_incrementing_pk" "id",
|
||||
Just $ ForeignKey "simple_pk" "k"]
|
||||
|
||||
describe "foreignKeys" $
|
||||
it "has a description of the foreign key columns" $ \conn ->
|
||||
foreignKeys "1" "has_fk" conn `shouldReturn` M.fromList [
|
||||
foreignKeys "test" "has_fk" conn `shouldReturn` M.fromList [
|
||||
("auto_inc_fk", ForeignKey {fkTable="auto_incrementing_pk", fkCol="id"}),
|
||||
("simple_fk", ForeignKey { fkTable="simple_pk", fkCol="k"})]
|
||||
|
||||
@@ -32,7 +32,7 @@ spec = around dbWithSchema $ do
|
||||
describe "insert" $
|
||||
describe "with an auto-increment key" $ do
|
||||
it "inserts and responds with a full object description" $ \conn -> do
|
||||
r <- insert "1" "auto_incrementing_pk" (SqlRow [
|
||||
r <- insert "test" "auto_incrementing_pk" (SqlRow [
|
||||
("non_nullable_string", toSql ("a string"::String))]) conn
|
||||
let returnRow = incFromList . toList $ r
|
||||
incStr returnRow `shouldBe` "a string"
|
||||
@@ -43,19 +43,19 @@ spec = around dbWithSchema $ do
|
||||
[returnRow] `shouldBe` map incFromList tRows
|
||||
|
||||
it "throws an exception if the PK is not unique" $ \conn -> do
|
||||
r <- insert "1" "auto_incrementing_pk" (SqlRow [
|
||||
r <- insert "test" "auto_incrementing_pk" (SqlRow [
|
||||
("non_nullable_string", toSql ("a string"::String))]) conn
|
||||
let row = SqlRow . map (Control.Arrow.first cs) . toList $ r
|
||||
insert "1" "auto_incrementing_pk" row conn `shouldThrow` \e ->
|
||||
insert "test" "auto_incrementing_pk" row conn `shouldThrow` \e ->
|
||||
seState e == "23505" -- uniqueness violation code
|
||||
|
||||
it "throws an exception if a required value is missing" $ \conn ->
|
||||
insert "1" "auto_incrementing_pk" (SqlRow [
|
||||
insert "test" "auto_incrementing_pk" (SqlRow [
|
||||
("nullable_string", toSql ("a string"::String))]) conn
|
||||
`shouldThrow` \e -> seState e == "23502"
|
||||
|
||||
it "generates a default values query if no data is provided" $ \c -> do
|
||||
r <- insert "1" "items" (SqlRow []) c
|
||||
r <- insert "test" "items" (SqlRow []) c
|
||||
let [row] = toList r
|
||||
quickALQuery c "select * from \"1\".items where id = ?" [snd row]
|
||||
`shouldReturn` [[row]]
|
||||
|
||||
Vendored
+117
-112
@@ -5,10 +5,10 @@ SET check_function_bodies = false;
|
||||
SET client_min_messages = warning;
|
||||
|
||||
|
||||
CREATE SCHEMA "1";
|
||||
CREATE SCHEMA test;
|
||||
|
||||
|
||||
ALTER SCHEMA "1" OWNER TO postgrest_test;
|
||||
ALTER SCHEMA test OWNER TO postgrest_test;
|
||||
|
||||
|
||||
CREATE SCHEMA postgrest;
|
||||
@@ -30,7 +30,7 @@ CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
|
||||
COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
|
||||
|
||||
|
||||
SET search_path = "1", pg_catalog;
|
||||
SET search_path = test, pg_catalog;
|
||||
|
||||
|
||||
CREATE TYPE enum_menagerie_type AS ENUM (
|
||||
@@ -39,7 +39,7 @@ CREATE TYPE enum_menagerie_type AS ENUM (
|
||||
);
|
||||
|
||||
|
||||
ALTER TYPE "1".enum_menagerie_type OWNER TO postgrest_test;
|
||||
ALTER TYPE test.enum_menagerie_type OWNER TO postgrest_test;
|
||||
|
||||
SET search_path = postgrest, pg_catalog;
|
||||
|
||||
@@ -76,25 +76,25 @@ CREATE FUNCTION set_authors_only_owner() RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
begin
|
||||
NEW.owner = current_setting('user_vars.user_id');
|
||||
NEW.owner = current_setting('postgrest.claims.id');
|
||||
RETURN NEW;
|
||||
end
|
||||
$$;
|
||||
|
||||
ALTER FUNCTION postgrest.set_authors_only_owner() OWNER TO postgrest_test;
|
||||
|
||||
CREATE FUNCTION "1".insert_insertable_view_with_join() RETURNS trigger
|
||||
CREATE FUNCTION test.insert_insertable_view_with_join() RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
begin
|
||||
INSERT INTO "1".auto_incrementing_pk (nullable_string, non_nullable_string) VALUES (NEW.nullable_string, NEW.non_nullable_string);
|
||||
INSERT INTO test.auto_incrementing_pk (nullable_string, non_nullable_string) VALUES (NEW.nullable_string, NEW.non_nullable_string);
|
||||
RETURN NEW;
|
||||
end;
|
||||
$$;
|
||||
|
||||
ALTER FUNCTION "1".insert_insertable_view_with_join() OWNER TO postgrest_test;
|
||||
ALTER FUNCTION test.insert_insertable_view_with_join() OWNER TO postgrest_test;
|
||||
|
||||
SET search_path = "1", pg_catalog;
|
||||
SET search_path = test, pg_catalog;
|
||||
|
||||
SET default_tablespace = '';
|
||||
|
||||
@@ -107,7 +107,7 @@ CREATE TABLE authors_only (
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE "1".authors_only OWNER TO postgrest_test_author;
|
||||
ALTER TABLE test.authors_only OWNER TO postgrest_test_author;
|
||||
|
||||
|
||||
CREATE TABLE auto_incrementing_pk (
|
||||
@@ -118,7 +118,7 @@ CREATE TABLE auto_incrementing_pk (
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE "1".auto_incrementing_pk OWNER TO postgrest_test;
|
||||
ALTER TABLE test.auto_incrementing_pk OWNER TO postgrest_test;
|
||||
|
||||
|
||||
CREATE SEQUENCE auto_incrementing_pk_id_seq
|
||||
@@ -129,7 +129,7 @@ CREATE SEQUENCE auto_incrementing_pk_id_seq
|
||||
CACHE 1;
|
||||
|
||||
|
||||
ALTER TABLE "1".auto_incrementing_pk_id_seq OWNER TO postgrest_test;
|
||||
ALTER TABLE test.auto_incrementing_pk_id_seq OWNER TO postgrest_test;
|
||||
|
||||
|
||||
ALTER SEQUENCE auto_incrementing_pk_id_seq OWNED BY auto_incrementing_pk.id;
|
||||
@@ -143,7 +143,7 @@ CREATE TABLE compound_pk (
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE "1".compound_pk OWNER TO postgrest_test;
|
||||
ALTER TABLE test.compound_pk OWNER TO postgrest_test;
|
||||
|
||||
|
||||
CREATE TABLE has_fk (
|
||||
@@ -153,7 +153,7 @@ CREATE TABLE has_fk (
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE "1".has_fk OWNER TO postgrest_test;
|
||||
ALTER TABLE test.has_fk OWNER TO postgrest_test;
|
||||
|
||||
|
||||
CREATE SEQUENCE has_fk_id_seq
|
||||
@@ -164,18 +164,18 @@ CREATE SEQUENCE has_fk_id_seq
|
||||
CACHE 1;
|
||||
|
||||
|
||||
ALTER TABLE "1".has_fk_id_seq OWNER TO postgrest_test;
|
||||
ALTER TABLE test.has_fk_id_seq OWNER TO postgrest_test;
|
||||
|
||||
|
||||
ALTER SEQUENCE has_fk_id_seq OWNED BY has_fk.id;
|
||||
|
||||
CREATE MATERIALIZED VIEW "1".materialized_view AS
|
||||
CREATE MATERIALIZED VIEW test.materialized_view AS
|
||||
SELECT
|
||||
version();
|
||||
|
||||
ALTER TABLE "1".materialized_view OWNER TO postgrest_test;
|
||||
ALTER TABLE test.materialized_view OWNER TO postgrest_test;
|
||||
|
||||
CREATE VIEW "1".insertable_view_with_join AS
|
||||
CREATE VIEW test.insertable_view_with_join AS
|
||||
SELECT has_fk.id,
|
||||
has_fk.auto_inc_fk,
|
||||
has_fk.simple_fk,
|
||||
@@ -186,12 +186,12 @@ CREATE VIEW "1".insertable_view_with_join AS
|
||||
JOIN auto_incrementing_pk USING (id));
|
||||
|
||||
|
||||
ALTER TABLE "1".insertable_view_with_join OWNER TO postgrest_test;
|
||||
ALTER TABLE test.insertable_view_with_join OWNER TO postgrest_test;
|
||||
|
||||
CREATE VIEW "1".has_count_column AS
|
||||
CREATE VIEW test.has_count_column AS
|
||||
SELECT 1 AS count;
|
||||
|
||||
ALTER TABLE "1".insertable_view_with_join OWNER TO postgrest_test;
|
||||
ALTER TABLE test.insertable_view_with_join OWNER TO postgrest_test;
|
||||
|
||||
|
||||
CREATE TABLE items (
|
||||
@@ -199,50 +199,51 @@ CREATE TABLE items (
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE "1".items OWNER TO postgrest_test;
|
||||
ALTER TABLE test.items OWNER TO postgrest_test;
|
||||
|
||||
CREATE TABLE complex_items (
|
||||
id bigint NOT NULL,
|
||||
name text,
|
||||
settings json
|
||||
settings json,
|
||||
arr_data INTEGER[]
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE "1".complex_items OWNER TO postgrest_test;
|
||||
ALTER TABLE test.complex_items OWNER TO postgrest_test;
|
||||
|
||||
--- Structure for testing table relations
|
||||
CREATE TABLE clients(
|
||||
id INT PRIMARY KEY NOT NULL,
|
||||
name TEXT NOT NULL
|
||||
);
|
||||
ALTER TABLE "1".clients OWNER TO postgrest_test;
|
||||
ALTER TABLE test.clients OWNER TO postgrest_test;
|
||||
|
||||
CREATE TABLE projects(
|
||||
id INT PRIMARY KEY NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
client_id INT REFERENCES clients(id)
|
||||
);
|
||||
ALTER TABLE "1".projects OWNER TO postgrest_test;
|
||||
ALTER TABLE test.projects OWNER TO postgrest_test;
|
||||
|
||||
CREATE TABLE tasks(
|
||||
id INT PRIMARY KEY NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
project_id INT REFERENCES projects(id)
|
||||
);
|
||||
ALTER TABLE "1".tasks OWNER TO postgrest_test;
|
||||
ALTER TABLE test.tasks OWNER TO postgrest_test;
|
||||
|
||||
CREATE TABLE users(
|
||||
id INT PRIMARY KEY NOT NULL,
|
||||
name TEXT NOT NULL
|
||||
);
|
||||
ALTER TABLE "1".users OWNER TO postgrest_test;
|
||||
ALTER TABLE test.users OWNER TO postgrest_test;
|
||||
|
||||
CREATE TABLE users_tasks(
|
||||
user_id INT REFERENCES users(id),
|
||||
task_id INT REFERENCES tasks(id),
|
||||
CONSTRAINT task_user PRIMARY KEY (task_id,user_id)
|
||||
);
|
||||
ALTER TABLE "1".users_tasks OWNER TO postgrest_test;
|
||||
ALTER TABLE test.users_tasks OWNER TO postgrest_test;
|
||||
|
||||
CREATE TABLE comments(
|
||||
id INT PRIMARY KEY NOT NULL,
|
||||
@@ -252,31 +253,22 @@ task_id INT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
FOREIGN KEY (task_id,user_id) REFERENCES users_tasks (task_id,user_id)
|
||||
);
|
||||
ALTER TABLE "1".comments OWNER TO postgrest_test;
|
||||
ALTER TABLE test.comments OWNER TO postgrest_test;
|
||||
|
||||
CREATE TABLE users_projects(
|
||||
user_id INT REFERENCES users(id),
|
||||
project_id INT REFERENCES projects(id),
|
||||
CONSTRAINT project_user PRIMARY KEY (project_id, user_id)
|
||||
);
|
||||
ALTER TABLE "1".users_projects OWNER TO postgrest_test;
|
||||
ALTER TABLE test.users_projects OWNER TO postgrest_test;
|
||||
|
||||
CREATE VIEW "1".projects_view AS
|
||||
CREATE VIEW test.projects_view AS
|
||||
SELECT
|
||||
projects.id,
|
||||
projects.name,
|
||||
projects.client_id
|
||||
FROM projects;
|
||||
ALTER TABLE "1".projects_view OWNER TO postgrest_test;
|
||||
------- SAMPLE DATA -----
|
||||
INSERT INTO clients VALUES (1, 'Microsoft'),(2, 'Apple');
|
||||
INSERT INTO projects VALUES (1,'Windows 7', 1),(2,'Windows 10', 1),(3,'IOS', 2),(4,'OSX', 2);
|
||||
INSERT INTO tasks VALUES (1,'Design w7',1),(2,'Code w7',1),(3,'Design w10',2),(4,'Code w10',2),(5,'Design IOS',3),(6,'Code IOS',3),(7,'Design OSX',4),(8,'Code OSX',4);
|
||||
INSERT INTO users VALUES (1, 'Angela Martin'),(2, 'Michael Scott'),(3, 'Dwight Schrute');
|
||||
INSERT INTO users_projects VALUES(1,1),(1,2),(2,3),(2,4),(3,1),(3,3);
|
||||
INSERT INTO users_tasks VALUES(1,1),(1,2),(1,3),(1,4),(2,5),(2,6),(2,7),(3,1),(3,5);
|
||||
INSERT INTO comments VALUES (1, 1, 2, 6, 'Needs to be delivered ASAP');
|
||||
----------------
|
||||
ALTER TABLE test.projects_view OWNER TO postgrest_test;
|
||||
|
||||
CREATE SEQUENCE items_id_seq
|
||||
START WITH 1
|
||||
@@ -286,27 +278,36 @@ CREATE SEQUENCE items_id_seq
|
||||
CACHE 1;
|
||||
|
||||
|
||||
ALTER TABLE "1".items_id_seq OWNER TO postgrest_test;
|
||||
ALTER TABLE test.items_id_seq OWNER TO postgrest_test;
|
||||
|
||||
|
||||
ALTER SEQUENCE items_id_seq OWNED BY items.id;
|
||||
|
||||
|
||||
|
||||
CREATE FUNCTION "1".getitemrange(min bigint, max bigint) RETURNS SETOF "1".items AS $$
|
||||
SELECT * FROM "1".items WHERE id > $1 AND id <= $2;
|
||||
CREATE FUNCTION test.getitemrange(min bigint, max bigint) RETURNS SETOF test.items AS $$
|
||||
SELECT * FROM test.items WHERE id > $1 AND id <= $2;
|
||||
$$ LANGUAGE SQL;
|
||||
|
||||
CREATE FUNCTION "1".test_empty_rowset() RETURNS SETOF int AS $$
|
||||
CREATE FUNCTION test_empty_rowset() RETURNS SETOF int AS $$
|
||||
SELECT null::int FROM (SELECT 1) a WHERE false;
|
||||
$$ LANGUAGE SQL;
|
||||
|
||||
CREATE FUNCTION "1".sayhello(name text) RETURNS text AS $$
|
||||
CREATE TYPE public.jwt_claims AS (role text, id text);
|
||||
|
||||
CREATE FUNCTION test.login(id text, pass text)
|
||||
RETURNS public.jwt_claims
|
||||
SECURITY DEFINER
|
||||
AS $$
|
||||
SELECT rolname::text, id::text FROM postgrest.auth WHERE id = id AND pass = pass;
|
||||
$$ LANGUAGE SQL;
|
||||
|
||||
CREATE FUNCTION test.sayhello(name text) RETURNS text AS $$
|
||||
SELECT 'Hello, ' || $1;
|
||||
$$ LANGUAGE SQL;
|
||||
|
||||
|
||||
CREATE FUNCTION "1".problem() RETURNS void LANGUAGE plpgsql AS
|
||||
CREATE FUNCTION test.problem() RETURNS void LANGUAGE plpgsql AS
|
||||
$$
|
||||
BEGIN
|
||||
RAISE 'bad thing';
|
||||
@@ -325,7 +326,7 @@ CREATE TABLE menagerie (
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE "1".menagerie OWNER TO postgrest_test;
|
||||
ALTER TABLE test.menagerie OWNER TO postgrest_test;
|
||||
|
||||
|
||||
CREATE TABLE no_pk (
|
||||
@@ -334,7 +335,7 @@ CREATE TABLE no_pk (
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE "1".no_pk OWNER TO postgrest_test;
|
||||
ALTER TABLE test.no_pk OWNER TO postgrest_test;
|
||||
|
||||
|
||||
CREATE TABLE nullable_integer (
|
||||
@@ -342,7 +343,7 @@ CREATE TABLE nullable_integer (
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE "1".nullable_integer OWNER TO postgrest_test;
|
||||
ALTER TABLE test.nullable_integer OWNER TO postgrest_test;
|
||||
|
||||
|
||||
CREATE TABLE simple_pk (
|
||||
@@ -351,7 +352,7 @@ CREATE TABLE simple_pk (
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE "1".simple_pk OWNER TO postgrest_test;
|
||||
ALTER TABLE test.simple_pk OWNER TO postgrest_test;
|
||||
|
||||
|
||||
CREATE TABLE json
|
||||
@@ -360,14 +361,14 @@ CREATE TABLE json
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE "1".json OWNER TO postgrest_test;
|
||||
ALTER TABLE test.json OWNER TO postgrest_test;
|
||||
|
||||
|
||||
CREATE TABLE tsearch (
|
||||
text_search_vector tsvector
|
||||
);
|
||||
|
||||
ALTER TABLE "1".tsearch OWNER TO postgrest_test;
|
||||
ALTER TABLE test.tsearch OWNER TO postgrest_test;
|
||||
|
||||
SET search_path = postgrest, pg_catalog;
|
||||
|
||||
@@ -385,8 +386,8 @@ SET search_path = private, pg_catalog;
|
||||
|
||||
|
||||
CREATE TABLE articles (
|
||||
id integer PRIMARY KEY NOT NULL,
|
||||
body text,
|
||||
id integer NOT NULL,
|
||||
owner name NOT NULL
|
||||
);
|
||||
|
||||
@@ -394,22 +395,32 @@ CREATE TABLE articles (
|
||||
ALTER TABLE private.articles OWNER TO postgrest_test;
|
||||
|
||||
|
||||
CREATE SEQUENCE articles_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
CREATE TABLE article_stars (
|
||||
article_id int REFERENCES articles(id),
|
||||
user_id int REFERENCES test.users(id),
|
||||
created_at timestamp NOT NULL DEFAULT now(),
|
||||
CONSTRAINT user_article PRIMARY KEY (article_id, user_id)
|
||||
);
|
||||
|
||||
ALTER TABLE private.article_stars OWNER TO postgrest_test;
|
||||
|
||||
|
||||
ALTER TABLE private.articles_id_seq OWNER TO postgrest_test;
|
||||
|
||||
SET search_path = test, pg_catalog;
|
||||
|
||||
|
||||
ALTER SEQUENCE articles_id_seq OWNED BY articles.id;
|
||||
|
||||
CREATE VIEW "articleStars" AS
|
||||
SELECT article_id AS "articleId", user_id AS "userId", created_at AS "createdAt"
|
||||
FROM private.article_stars;
|
||||
|
||||
SET search_path = "1", pg_catalog;
|
||||
ALTER TABLE test."articleStars" OWNER TO postgrest_test;
|
||||
|
||||
CREATE VIEW articles AS
|
||||
SELECT *
|
||||
FROM private.articles;
|
||||
|
||||
ALTER TABLE test.articles OWNER TO postgrest_test;
|
||||
|
||||
ALTER TABLE ONLY auto_incrementing_pk ALTER COLUMN id SET DEFAULT nextval('auto_incrementing_pk_id_seq'::regclass);
|
||||
|
||||
@@ -417,36 +428,10 @@ ALTER TABLE ONLY auto_incrementing_pk ALTER COLUMN id SET DEFAULT nextval('auto_
|
||||
|
||||
ALTER TABLE ONLY has_fk ALTER COLUMN id SET DEFAULT nextval('has_fk_id_seq'::regclass);
|
||||
|
||||
|
||||
|
||||
ALTER TABLE ONLY items ALTER COLUMN id SET DEFAULT nextval('items_id_seq'::regclass);
|
||||
|
||||
|
||||
SET search_path = private, pg_catalog;
|
||||
|
||||
|
||||
ALTER TABLE ONLY articles ALTER COLUMN id SET DEFAULT nextval('articles_id_seq'::regclass);
|
||||
|
||||
|
||||
SET search_path = "1", pg_catalog;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
SELECT pg_catalog.setval('auto_incrementing_pk_id_seq', 1, true);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
SELECT pg_catalog.setval('has_fk_id_seq', 1, false);
|
||||
|
||||
|
||||
@@ -469,24 +454,20 @@ SET search_path = private, pg_catalog;
|
||||
|
||||
|
||||
|
||||
SET search_path = test, pg_catalog;
|
||||
|
||||
SELECT pg_catalog.setval('articles_id_seq', 1, false);
|
||||
|
||||
|
||||
SET search_path = "1", pg_catalog;
|
||||
|
||||
CREATE FUNCTION public.always_true("1".items) RETURNS boolean
|
||||
CREATE FUNCTION public.always_true(test.items) RETURNS boolean
|
||||
LANGUAGE sql STABLE
|
||||
AS $$ SELECT true $$;
|
||||
|
||||
ALTER FUNCTION public.always_true("1".items) OWNER TO postgrest_test;
|
||||
ALTER FUNCTION public.always_true(test.items) OWNER TO postgrest_test;
|
||||
|
||||
|
||||
|
||||
ALTER TABLE ONLY authors_only
|
||||
ADD CONSTRAINT authors_only_pkey PRIMARY KEY (secret);
|
||||
|
||||
CREATE TRIGGER insert_insertable_view_with_join INSTEAD OF INSERT ON "1".insertable_view_with_join FOR EACH ROW EXECUTE PROCEDURE "1".insert_insertable_view_with_join();
|
||||
CREATE TRIGGER insert_insertable_view_with_join INSTEAD OF INSERT ON test.insertable_view_with_join FOR EACH ROW EXECUTE PROCEDURE test.insert_insertable_view_with_join();
|
||||
|
||||
|
||||
CREATE TRIGGER secrets_owner_track BEFORE INSERT OR UPDATE ON authors_only FOR EACH ROW EXECUTE PROCEDURE postgrest.set_authors_only_owner();
|
||||
@@ -533,10 +514,6 @@ ALTER TABLE ONLY auth
|
||||
SET search_path = private, pg_catalog;
|
||||
|
||||
|
||||
ALTER TABLE ONLY articles
|
||||
ADD CONSTRAINT articles_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
SET search_path = postgrest, pg_catalog;
|
||||
|
||||
|
||||
@@ -549,7 +526,7 @@ SET search_path = private, pg_catalog;
|
||||
CREATE TRIGGER articles_owner_track BEFORE INSERT OR UPDATE ON articles FOR EACH ROW EXECUTE PROCEDURE postgrest.update_owner();
|
||||
|
||||
|
||||
SET search_path = "1", pg_catalog;
|
||||
SET search_path = test, pg_catalog;
|
||||
|
||||
|
||||
ALTER TABLE ONLY has_fk
|
||||
@@ -562,11 +539,11 @@ ALTER TABLE ONLY has_fk
|
||||
|
||||
|
||||
|
||||
REVOKE ALL ON SCHEMA "1" FROM PUBLIC;
|
||||
REVOKE ALL ON SCHEMA "1" FROM postgrest_test;
|
||||
GRANT ALL ON SCHEMA "1" TO postgrest_test;
|
||||
GRANT USAGE ON SCHEMA "1" TO postgrest_anonymous;
|
||||
GRANT USAGE ON SCHEMA "1" TO postgrest_test_author;
|
||||
REVOKE ALL ON SCHEMA test FROM PUBLIC;
|
||||
REVOKE ALL ON SCHEMA test FROM postgrest_test;
|
||||
GRANT ALL ON SCHEMA test TO postgrest_test;
|
||||
GRANT USAGE ON SCHEMA test TO postgrest_anonymous;
|
||||
GRANT USAGE ON SCHEMA test TO postgrest_test_author;
|
||||
|
||||
|
||||
|
||||
@@ -657,6 +634,14 @@ REVOKE ALL ON TABLE projects_view FROM PUBLIC;
|
||||
REVOKE ALL ON TABLE projects_view FROM postgrest_test;
|
||||
GRANT ALL ON TABLE projects_view TO postgrest_test;
|
||||
GRANT ALL ON TABLE projects_view TO postgrest_anonymous;
|
||||
REVOKE ALL ON TABLE articles FROM PUBLIC;
|
||||
REVOKE ALL ON TABLE articles FROM postgrest_test;
|
||||
GRANT ALL ON TABLE articles TO postgrest_test;
|
||||
GRANT ALL ON TABLE articles TO postgrest_anonymous;
|
||||
REVOKE ALL ON TABLE "articleStars" FROM PUBLIC;
|
||||
REVOKE ALL ON TABLE "articleStars" FROM postgrest_test;
|
||||
GRANT ALL ON TABLE "articleStars" TO postgrest_test;
|
||||
GRANT ALL ON TABLE "articleStars" TO postgrest_anonymous;
|
||||
---------
|
||||
|
||||
|
||||
@@ -670,6 +655,11 @@ REVOKE ALL ON FUNCTION test_empty_rowset() FROM postgrest_test;
|
||||
GRANT EXECUTE ON FUNCTION test_empty_rowset() TO postgrest_test;
|
||||
GRANT EXECUTE ON FUNCTION test_empty_rowset() TO postgrest_anonymous;
|
||||
|
||||
REVOKE ALL ON FUNCTION login(text, text) FROM PUBLIC;
|
||||
REVOKE ALL ON FUNCTION login(text, text) FROM postgrest_test;
|
||||
GRANT EXECUTE ON FUNCTION login(text, text) TO postgrest_test;
|
||||
GRANT EXECUTE ON FUNCTION login(text, text) TO postgrest_anonymous;
|
||||
|
||||
REVOKE ALL ON FUNCTION sayhello(text) FROM PUBLIC;
|
||||
REVOKE ALL ON FUNCTION sayhello(text) FROM postgrest_test;
|
||||
GRANT EXECUTE ON FUNCTION sayhello(text) TO postgrest_test;
|
||||
@@ -743,10 +733,10 @@ REVOKE ALL ON TABLE has_count_column FROM postgrest_test;
|
||||
GRANT ALL ON TABLE has_count_column TO postgrest_test;
|
||||
GRANT ALL ON TABLE has_count_column TO postgrest_anonymous;
|
||||
|
||||
REVOKE ALL ON FUNCTION public.always_true("1".items) FROM PUBLIC;
|
||||
REVOKE ALL ON FUNCTION public.always_true("1".items) FROM postgrest_test;
|
||||
GRANT ALL ON FUNCTION public.always_true("1".items) TO postgrest_test;
|
||||
GRANT ALL ON FUNCTION public.always_true("1".items) TO postgrest_anonymous;
|
||||
REVOKE ALL ON FUNCTION public.always_true(test.items) FROM PUBLIC;
|
||||
REVOKE ALL ON FUNCTION public.always_true(test.items) FROM postgrest_test;
|
||||
GRANT ALL ON FUNCTION public.always_true(test.items) TO postgrest_test;
|
||||
GRANT ALL ON FUNCTION public.always_true(test.items) TO postgrest_anonymous;
|
||||
|
||||
|
||||
SET search_path = postgrest, pg_catalog;
|
||||
@@ -764,3 +754,18 @@ SET search_path = private, pg_catalog;
|
||||
REVOKE ALL ON TABLE articles FROM PUBLIC;
|
||||
REVOKE ALL ON TABLE articles FROM postgrest_test;
|
||||
GRANT ALL ON TABLE articles TO postgrest_test;
|
||||
|
||||
SET search_path = test, private, postgrest, public, pg_catalog;
|
||||
|
||||
------- SAMPLE DATA -----
|
||||
INSERT INTO clients VALUES (1, 'Microsoft'),(2, 'Apple');
|
||||
INSERT INTO projects VALUES (1,'Windows 7', 1),(2,'Windows 10', 1),(3,'IOS', 2),(4,'OSX', 2);
|
||||
INSERT INTO tasks VALUES (1,'Design w7',1),(2,'Code w7',1),(3,'Design w10',2),(4,'Code w10',2),(5,'Design IOS',3),(6,'Code IOS',3),(7,'Design OSX',4),(8,'Code OSX',4);
|
||||
INSERT INTO users VALUES (1, 'Angela Martin'),(2, 'Michael Scott'),(3, 'Dwight Schrute');
|
||||
INSERT INTO users_projects VALUES(1,1),(1,2),(2,3),(2,4),(3,1),(3,3);
|
||||
INSERT INTO users_tasks VALUES(1,1),(1,2),(1,3),(1,4),(2,5),(2,6),(2,7),(3,1),(3,5);
|
||||
INSERT INTO comments VALUES (1, 1, 2, 6, 'Needs to be delivered ASAP');
|
||||
INSERT INTO postgrest.auth (id, pass, rolname) VALUES ('jdoe', '1234', 'postgrest_test_author');
|
||||
INSERT INTO private.articles (id, body, owner) VALUES (1, 'No… It''s a thing; it''s like a plan, but with more greatness.', 2), (2, 'Stop talking, brain thinking. Hush.', 3), (3, 'It''s a fez. I wear a fez now. Fezes are cool.', 1);
|
||||
INSERT INTO private.article_stars (article_id, user_id) VALUES (1,1), (1,2), (2,3), (3,2), (1,3);
|
||||
----------------
|
||||
|
||||
Reference in New Issue
Block a user