Skip to content

Commit fee0c26

Browse files
authored
Merge pull request #483 from supabase/or/plug-view-function-type-hole
Functions returning view type must have pkey (et.al.)
2 parents 2bb35d5 + cab94f2 commit fee0c26

File tree

5 files changed

+202
-55
lines changed

5 files changed

+202
-55
lines changed

src/graphql.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1289,9 +1289,11 @@ fn function_fields(schema: &Arc<__Schema>, volatilities: &[FunctionVolatility])
12891289

12901290
// If the return type is a table type, it must be selectable
12911291
if !match &return_type {
1292-
__Type::Node(table_type) => table_type.table.permissions.is_selectable,
1292+
__Type::Node(table_type) => {
1293+
schema.graphql_table_select_types_are_valid(&table_type.table)
1294+
}
12931295
__Type::Connection(table_type) => {
1294-
table_type.table.permissions.is_selectable
1296+
schema.graphql_table_select_types_are_valid(&table_type.table)
12951297
}
12961298
_ => true,
12971299
} {

test/expected/function_calls.out

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2601,7 +2601,7 @@ begin;
26012601

26022602
rollback to savepoint a;
26032603
create table account(
2604-
id int,
2604+
id int primary key,
26052605
email varchar(255),
26062606
name text null
26072607
);
@@ -2611,18 +2611,13 @@ begin;
26112611
create function returns_one_column_null_account()
26122612
returns account language sql stable
26132613
as $$ select id, email, name from account where id = 2; $$;
2614-
create function returns_all_columns_null_account()
2615-
returns account language sql stable
2616-
as $$ select id, email, name from account where id is null; $$;
26172614
create function returns_null_account()
26182615
returns account language sql stable
26192616
as $$ select id, email, name from account where id = 9; $$;
26202617
insert into account(id, email, name)
26212618
values
26222619
(1, 'aardvark@x.com', 'aardvark'),--all columns non-null
2623-
(2, 'bat@x.com', null),--mixed: some null, some non-null
2624-
(null, null, null);--all columns null
2625-
-- comment on table account is e'@graphql({"totalCount": {"enabled": true}})';
2620+
(2, 'bat@x.com', null);--mixed: some null, some non-null
26262621
select jsonb_pretty(graphql.resolve($$
26272622
query {
26282623
returnsAllColumnsNonNullAccount {
@@ -2671,29 +2666,7 @@ begin;
26712666
}
26722667
(1 row)
26732668

2674-
-- With current implementation we can't distinguish between
2675-
-- when all columns of a composite type are null and when
2676-
-- the composite type itself is null. In both these cases
2677-
-- the result will be null for the top-level field.
2678-
select jsonb_pretty(graphql.resolve($$
2679-
query {
2680-
returnsAllColumnsNullAccount {
2681-
id
2682-
email
2683-
name
2684-
__typename
2685-
}
2686-
}
2687-
$$));
2688-
jsonb_pretty
2689-
----------------------------------------------
2690-
{ +
2691-
"data": { +
2692-
"returnsAllColumnsNullAccount": null+
2693-
} +
2694-
}
2695-
(1 row)
2696-
2669+
-- When no record is found, the top level field becomes null
26972670
select jsonb_pretty(graphql.resolve($$
26982671
query {
26992672
returnsNullAccount {
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
begin;
2+
create view account as
3+
select
4+
1 as foo,
5+
2 as bar;
6+
create function returns_account()
7+
returns account language sql stable
8+
as $$ select foo, bar from account; $$;
9+
-- Account should not be visible because the view has no primary key
10+
select jsonb_pretty(
11+
graphql.resolve($$
12+
{
13+
__type(name: "Account") {
14+
__typename
15+
}
16+
}
17+
$$)
18+
);
19+
jsonb_pretty
20+
------------------------
21+
{ +
22+
"data": { +
23+
"__type": null+
24+
} +
25+
}
26+
(1 row)
27+
28+
-- returnsAccount should also not be visible because account has no primary key
29+
select jsonb_pretty(
30+
graphql.resolve($$
31+
query IntrospectionQuery {
32+
__schema {
33+
queryType {
34+
fields {
35+
name
36+
}
37+
}
38+
}
39+
}
40+
$$)
41+
);
42+
jsonb_pretty
43+
----------------------------------------
44+
{ +
45+
"data": { +
46+
"__schema": { +
47+
"queryType": { +
48+
"fields": [ +
49+
{ +
50+
"name": "node"+
51+
} +
52+
] +
53+
} +
54+
} +
55+
} +
56+
}
57+
(1 row)
58+
59+
comment on view account is e'
60+
@graphql({
61+
"primary_key_columns": ["foo"]
62+
})';
63+
-- Account should be visible because the view is selectable and has a primary key
64+
select jsonb_pretty(
65+
graphql.resolve($$
66+
{
67+
__type(name: "Account") {
68+
__typename
69+
}
70+
}
71+
$$)
72+
);
73+
jsonb_pretty
74+
-------------------------------------
75+
{ +
76+
"data": { +
77+
"__type": { +
78+
"__typename": "Account"+
79+
} +
80+
} +
81+
}
82+
(1 row)
83+
84+
-- returnsAccount should also be visible because account has a primary key and is selectable
85+
select jsonb_pretty(
86+
graphql.resolve($$
87+
query IntrospectionQuery {
88+
__schema {
89+
queryType {
90+
fields {
91+
name
92+
}
93+
}
94+
}
95+
}
96+
$$)
97+
);
98+
jsonb_pretty
99+
-----------------------------------------------------
100+
{ +
101+
"data": { +
102+
"__schema": { +
103+
"queryType": { +
104+
"fields": [ +
105+
{ +
106+
"name": "accountCollection"+
107+
}, +
108+
{ +
109+
"name": "node" +
110+
}, +
111+
{ +
112+
"name": "returnsAccount" +
113+
} +
114+
] +
115+
} +
116+
} +
117+
} +
118+
}
119+
(1 row)
120+
121+
rollback;

test/sql/function_calls.sql

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -807,7 +807,7 @@ begin;
807807
rollback to savepoint a;
808808

809809
create table account(
810-
id int,
810+
id int primary key,
811811
email varchar(255),
812812
name text null
813813
);
@@ -820,21 +820,15 @@ begin;
820820
returns account language sql stable
821821
as $$ select id, email, name from account where id = 2; $$;
822822

823-
create function returns_all_columns_null_account()
824-
returns account language sql stable
825-
as $$ select id, email, name from account where id is null; $$;
826-
827823
create function returns_null_account()
828824
returns account language sql stable
829825
as $$ select id, email, name from account where id = 9; $$;
830826

831827
insert into account(id, email, name)
832828
values
833829
(1, 'aardvark@x.com', 'aardvark'),--all columns non-null
834-
(2, 'bat@x.com', null),--mixed: some null, some non-null
835-
(null, null, null);--all columns null
830+
(2, 'bat@x.com', null);--mixed: some null, some non-null
836831

837-
-- comment on table account is e'@graphql({"totalCount": {"enabled": true}})';
838832

839833
select jsonb_pretty(graphql.resolve($$
840834
query {
@@ -858,21 +852,7 @@ begin;
858852
}
859853
$$));
860854

861-
-- With current implementation we can't distinguish between
862-
-- when all columns of a composite type are null and when
863-
-- the composite type itself is null. In both these cases
864-
-- the result will be null for the top-level field.
865-
select jsonb_pretty(graphql.resolve($$
866-
query {
867-
returnsAllColumnsNullAccount {
868-
id
869-
email
870-
name
871-
__typename
872-
}
873-
}
874-
$$));
875-
855+
-- When no record is found, the top level field becomes null
876856
select jsonb_pretty(graphql.resolve($$
877857
query {
878858
returnsNullAccount {
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
begin;
2+
3+
create view account as
4+
select
5+
1 as foo,
6+
2 as bar;
7+
8+
create function returns_account()
9+
returns account language sql stable
10+
as $$ select foo, bar from account; $$;
11+
12+
-- Account should not be visible because the view has no primary key
13+
select jsonb_pretty(
14+
graphql.resolve($$
15+
{
16+
__type(name: "Account") {
17+
__typename
18+
}
19+
}
20+
$$)
21+
);
22+
23+
-- returnsAccount should also not be visible because account has no primary key
24+
select jsonb_pretty(
25+
graphql.resolve($$
26+
query IntrospectionQuery {
27+
__schema {
28+
queryType {
29+
fields {
30+
name
31+
}
32+
}
33+
}
34+
}
35+
$$)
36+
);
37+
38+
comment on view account is e'
39+
@graphql({
40+
"primary_key_columns": ["foo"]
41+
})';
42+
43+
-- Account should be visible because the view is selectable and has a primary key
44+
select jsonb_pretty(
45+
graphql.resolve($$
46+
{
47+
__type(name: "Account") {
48+
__typename
49+
}
50+
}
51+
$$)
52+
);
53+
54+
-- returnsAccount should also be visible because account has a primary key and is selectable
55+
select jsonb_pretty(
56+
graphql.resolve($$
57+
query IntrospectionQuery {
58+
__schema {
59+
queryType {
60+
fields {
61+
name
62+
}
63+
}
64+
}
65+
}
66+
$$)
67+
);
68+
69+
70+
71+
rollback;

0 commit comments

Comments
 (0)