I'm trying to do a single implicit JOIN inside of an RLS expression. I get a syntax error and have a "hacky" solution using a subquery, but would love to know if there is a better way.
So assuming two tables, projects
and objects
:
CREATE TABLE app_pub.projects (
id uuid DEFAULT public.uuid_generate_v4 () NOT NULL,
owner_id uuid
);
CREATE TABLE app_pub.objects (
id uuid DEFAULT public.uuid_generate_v4 () NOT NULL,
project_id uuid
);
The ownership is expressed on the project.owner_id
, but the policy of interest will check against objects.project_id
. The procedure app_pub.get_current_role_ids ()
returns an array of role ids for access.
Specifically this query's boolean result tells us if the user has access:
SELECT (p.owner_id = ANY (app_pub.get_current_role_ids ()))
FROM app_pub.projects p, objects o
WHERE (p.id = o.project_id)
I'd like to write a policy like so:
CREATE POLICY authenticated_can_select_on_objects
ON app_pub.objects
FOR SELECT
TO authenticated
USING (
SELECT (p.owner_id = ANY (app_pub.get_current_role_ids ()))
FROM app_pub.projects p
WHERE (p.id = project_id)
);
But this obviously fails due to syntax error, hence my question...
So I do have my "hacky" solution is to use a subquery and do TRUE IN (subquery)
:
CREATE POLICY authenticated_can_select_on_objects
ON app_pub.objects
FOR SELECT
TO authenticated
USING (
(TRUE IN (
SELECT (p.owner_id = ANY (app_pub.get_current_role_ids ()))
FROM app_pub.projects p
WHERE (p.id = project_id)
)
)
);
And YaY "it works!", with this TRUE IN (subquery)
which feels wrong. I know I could write a procedure and use that, but was hoping to do something inline in hopes the query planner would be happier.
So, with all that context:
- is this "hacky" solution the only/best way?
- can I do a clean select or join like my first attempt was trying to accomplish?