tests for table relations & bugfix for not detecting child relations of view
This commit is contained in:
@@ -94,34 +94,49 @@ allTables = do
|
||||
allRelations :: H.Tx P.Postgres s [Relation]
|
||||
allRelations = do
|
||||
rels <- H.listEx $ [H.stmt|
|
||||
WITH table_fk AS (
|
||||
SELECT DISTINCT
|
||||
tc.table_schema, tc.table_name, kcu.column_name,
|
||||
ccu.table_name AS foreign_table_name,
|
||||
ccu.column_name AS foreign_column_name
|
||||
FROM information_schema.table_constraints AS tc
|
||||
JOIN information_schema.key_column_usage AS kcu on tc.constraint_name = kcu.constraint_name
|
||||
JOIN information_schema.constraint_column_usage AS ccu on ccu.constraint_name = tc.constraint_name
|
||||
WHERE constraint_type = 'FOREIGN KEY'
|
||||
AND tc.table_schema NOT IN ('pg_catalog', 'information_schema')
|
||||
ORDER BY tc.table_schema, tc.table_name, kcu.column_name
|
||||
)
|
||||
SELECT * FROM table_fk
|
||||
UNION
|
||||
(
|
||||
SELECT DISTINCT
|
||||
vcu.table_schema, vcu.view_name AS table_name, vcu.column_name,
|
||||
table_fk.foreign_table_name,
|
||||
table_fk.foreign_column_name
|
||||
FROM information_schema.view_column_usage as vcu
|
||||
JOIN table_fk ON
|
||||
table_fk.table_schema = vcu.view_schema AND
|
||||
table_fk.table_name = vcu.table_name AND
|
||||
table_fk.column_name = vcu.column_name
|
||||
WHERE vcu.view_schema NOT IN ('pg_catalog', 'information_schema')
|
||||
ORDER BY vcu.table_schema, vcu.view_name, vcu.column_name
|
||||
)
|
||||
|
||||
WITH table_fk AS (
|
||||
SELECT
|
||||
tc.table_schema, tc.table_name, kcu.column_name,
|
||||
ccu.table_name AS foreign_table_name,
|
||||
ccu.column_name AS foreign_column_name
|
||||
FROM information_schema.table_constraints AS tc
|
||||
JOIN information_schema.key_column_usage AS kcu on tc.constraint_name = kcu.constraint_name
|
||||
JOIN information_schema.constraint_column_usage AS ccu on ccu.constraint_name = tc.constraint_name
|
||||
WHERE constraint_type = 'FOREIGN KEY'
|
||||
AND tc.table_schema NOT IN ('pg_catalog', 'information_schema')
|
||||
ORDER BY tc.table_schema, tc.table_name, kcu.column_name
|
||||
)
|
||||
SELECT * FROM table_fk
|
||||
UNION
|
||||
(
|
||||
SELECT
|
||||
vcu.table_schema, vcu.view_name AS table_name, vcu.column_name,
|
||||
table_fk.foreign_table_name,
|
||||
table_fk.foreign_column_name
|
||||
FROM information_schema.view_column_usage as vcu
|
||||
JOIN table_fk ON
|
||||
table_fk.table_schema = vcu.view_schema AND
|
||||
table_fk.table_name = vcu.table_name AND
|
||||
table_fk.column_name = vcu.column_name
|
||||
WHERE vcu.view_schema NOT IN ('pg_catalog', 'information_schema')
|
||||
ORDER BY vcu.table_schema, vcu.view_name, vcu.column_name
|
||||
)
|
||||
UNION
|
||||
(
|
||||
SELECT
|
||||
vcu.view_schema as table_schema,
|
||||
table_fk.table_name,
|
||||
table_fk.column_name,
|
||||
vcu.view_name as foreign_table_name,
|
||||
vcu.column_name as foreign_column_name
|
||||
FROM information_schema.view_column_usage as vcu
|
||||
JOIN table_fk ON
|
||||
table_fk.table_schema = vcu.view_schema AND
|
||||
table_fk.foreign_table_name = vcu.table_name AND
|
||||
table_fk.foreign_column_name = vcu.column_name
|
||||
WHERE vcu.view_schema NOT IN ('pg_catalog', 'information_schema')
|
||||
ORDER BY vcu.table_schema, vcu.view_name, vcu.column_name
|
||||
)
|
||||
|]
|
||||
let simpleRelations = foldr (addParentRelation.relationFromRow) [] rels
|
||||
let links = filter ((==2).length) $ groupWith groupFn $ filter ( (==Child). relType) simpleRelations
|
||||
|
||||
@@ -130,6 +130,10 @@ spec =
|
||||
get "/items?always_true=eq.true" `shouldRespondWith`
|
||||
[json| [{"id":1},{"id":2},{"id":3},{"id":4},{"id":5},{"id":6},{"id":7},{"id":8},{"id":9},{"id":10},{"id":11},{"id":12},{"id":13},{"id":14},{"id":15}] |]
|
||||
|
||||
it "matches filtering nested items" $
|
||||
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\"}]}]}]"
|
||||
|
||||
describe "Shaping response with select parameter" $ do
|
||||
|
||||
it "selectStar works in absense of parameter" $
|
||||
@@ -178,6 +182,22 @@ spec =
|
||||
get "/complex_items?id=eq.1&select=settings->foo->>int::integer" `shouldRespondWith`
|
||||
[json| [{"int":1}] |] -- the value in the db is an int, but here we expect a string for now
|
||||
|
||||
it "requesting parents and children" $
|
||||
get "/projects?id=eq.1&select=id, name, clients(*), tasks(id, name)" `shouldRespondWith`
|
||||
"[{\"id\":1,\"name\":\"Windows 7\",\"clients\":{\"id\":1,\"name\":\"Microsoft\"},\"tasks\":[{\"id\":1,\"name\":\"Design w7\"},{\"id\":2,\"name\":\"Code w7\"}]}]"
|
||||
|
||||
it "requesting children 2 levels" $
|
||||
get "/clients?id=eq.1&select=id,projects(id,tasks(id))" `shouldRespondWith`
|
||||
"[{\"id\":1,\"projects\":[{\"id\":1,\"tasks\":[{\"id\":1},{\"id\":2}]},{\"id\":2,\"tasks\":[{\"id\":3},{\"id\":4}]}]}]"
|
||||
|
||||
it "requesting many<->many relation" $
|
||||
get "/tasks?select=id,users(id)" `shouldRespondWith`
|
||||
"[{\"id\":1,\"users\":[{\"id\":1},{\"id\":3}]},{\"id\":2,\"users\":[{\"id\":1}]},{\"id\":3,\"users\":[{\"id\":1}]},{\"id\":4,\"users\":[{\"id\":1}]},{\"id\":5,\"users\":[{\"id\":2},{\"id\":3}]},{\"id\":6,\"users\":[{\"id\":2}]},{\"id\":7,\"users\":[{\"id\":2}]},{\"id\":8,\"users\":null}]"
|
||||
|
||||
it "requesting parents and children on views" $
|
||||
get "/projects_view?id=eq.1&select=id, name, clients(*), tasks(id, name)" `shouldRespondWith`
|
||||
"[{\"id\":1,\"name\":\"Windows 7\",\"clients\":{\"id\":1,\"name\":\"Microsoft\"},\"tasks\":[{\"id\":1,\"name\":\"Design w7\"},{\"id\":2,\"name\":\"Code w7\"}]}]"
|
||||
|
||||
|
||||
describe "ordering response" $ do
|
||||
it "by a column asc" $
|
||||
|
||||
@@ -15,6 +15,7 @@ spec = around withApp $ do
|
||||
request methodGet "/" [] ""
|
||||
`shouldRespondWith` [json| [
|
||||
{"schema":"1","name":"auto_incrementing_pk","insertable":true}
|
||||
, {"schema":"1","name":"clients","insertable":true}
|
||||
, {"schema":"1","name":"complex_items","insertable":true}
|
||||
, {"schema":"1","name":"compound_pk","insertable":true}
|
||||
, {"schema":"1","name":"has_count_column","insertable":false}
|
||||
@@ -26,8 +27,14 @@ spec = around withApp $ do
|
||||
, {"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}
|
||||
] |]
|
||||
{matchStatus = 200}
|
||||
|
||||
|
||||
Vendored
+87
@@ -210,6 +210,62 @@ CREATE TABLE complex_items (
|
||||
|
||||
ALTER TABLE "1".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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
CREATE TABLE users(
|
||||
id INT PRIMARY KEY NOT NULL,
|
||||
name TEXT NOT NULL
|
||||
);
|
||||
ALTER TABLE "1".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;
|
||||
|
||||
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;
|
||||
|
||||
CREATE VIEW "1".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);
|
||||
----------------
|
||||
|
||||
CREATE SEQUENCE items_id_seq
|
||||
START WITH 1
|
||||
@@ -555,6 +611,37 @@ REVOKE ALL ON TABLE complex_items FROM postgrest_test;
|
||||
GRANT ALL ON TABLE complex_items TO postgrest_test;
|
||||
GRANT ALL ON TABLE complex_items TO postgrest_anonymous;
|
||||
|
||||
---------
|
||||
REVOKE ALL ON TABLE clients FROM PUBLIC;
|
||||
REVOKE ALL ON TABLE clients FROM postgrest_test;
|
||||
GRANT ALL ON TABLE clients TO postgrest_test;
|
||||
GRANT ALL ON TABLE clients TO postgrest_anonymous;
|
||||
REVOKE ALL ON TABLE projects FROM PUBLIC;
|
||||
REVOKE ALL ON TABLE projects FROM postgrest_test;
|
||||
GRANT ALL ON TABLE projects TO postgrest_test;
|
||||
GRANT ALL ON TABLE projects TO postgrest_anonymous;
|
||||
REVOKE ALL ON TABLE tasks FROM PUBLIC;
|
||||
REVOKE ALL ON TABLE tasks FROM postgrest_test;
|
||||
GRANT ALL ON TABLE tasks TO postgrest_test;
|
||||
GRANT ALL ON TABLE tasks TO postgrest_anonymous;
|
||||
REVOKE ALL ON TABLE users FROM PUBLIC;
|
||||
REVOKE ALL ON TABLE users FROM postgrest_test;
|
||||
GRANT ALL ON TABLE users TO postgrest_test;
|
||||
GRANT ALL ON TABLE users TO postgrest_anonymous;
|
||||
REVOKE ALL ON TABLE users_tasks FROM PUBLIC;
|
||||
REVOKE ALL ON TABLE users_tasks FROM postgrest_test;
|
||||
GRANT ALL ON TABLE users_tasks TO postgrest_test;
|
||||
GRANT ALL ON TABLE users_tasks TO postgrest_anonymous;
|
||||
REVOKE ALL ON TABLE users_projects FROM PUBLIC;
|
||||
REVOKE ALL ON TABLE users_projects FROM postgrest_test;
|
||||
GRANT ALL ON TABLE users_projects TO postgrest_test;
|
||||
GRANT ALL ON TABLE users_projects TO postgrest_anonymous;
|
||||
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 FUNCTION getitemrange(bigint, bigint) FROM PUBLIC;
|
||||
REVOKE ALL ON FUNCTION getitemrange(bigint, bigint) FROM postgrest_test;
|
||||
|
||||
Reference in New Issue
Block a user