我想对 my_table 实现软删除。
问题是,如果我跑步,UPDATE "my_table" set delete_at = now() where id = ...
我会得到new row violates row-level security policy for table。
插入和删除(真正的删除)工作正常,所以我在这里跳过这个。
-- create table
CREATE TABLE "my_table" (
"id" SERIAL PRIMARY KEY
"user_id" int not null references "user"(id) on delete cascade,
deleted_at timestamp with time zone
);
-- enable row level security
ALTER TABLE "my_table" ENABLE ROW LEVEL SECURITY;
-- allow read own data and everything for admin
CREATE POLICY my_table_read_policy ON "my_table" FOR SELECT
USING (
current_setting('role') = 'app_admin'
or
(
current_setting('role') = 'app_user'
and user_id = get_current_user_id()
and (
deleted_at is null
)
)
);
-- update, e.g. set delete_at date
CREATE POLICY my_table_update_policy ON "my_table" FOR UPDATE
USING (true)
WITH CHECK (
current_setting('role') = 'app_admin'
or
(
current_setting('role') = 'app_user'
and user_id = get_current_user_id()
)
);
Run Code Online (Sandbox Code Playgroud)
将 SELECT 策略更改为以下解决方法后(delete_at is null OR "within the last second"),它就可以工作了。
-- allow read own data and everything for admin
CREATE POLICY my_table_read_policy ON "my_table" FOR SELECT
USING (
current_setting('role') = 'app_admin'
or
(
current_setting('role') = 'app_user'
and user_id = get_current_user_id()
-- workaround: /sf/answers/5201420591/
and (
deleted_at is null OR ABS(EXTRACT(EPOCH FROM (now() - deleted_at))) < 1
)
)
);
Run Code Online (Sandbox Code Playgroud)
根据Table 287(按命令类型应用的策略),当您执行UPDATE命令时,如果您的查询中有WHERE或,那么策略也会应用于现有行和新行。借助 RLS,您可以评估您的/政策,以判断是否发生任何条件。RETURNINGSELECTSELECTUSINGTRUEUPDATE
简而言之,为了更新特定的user_id,您必须能够读取该行user_id。否则,将更新 0 行。
您的更新查询功能where user_id = 。不仅如此,策略也被视为查询的一部分。因此,只要您引用了CHECK策略中的某个字段,UPDATE查询就会始终触发SELECT/USING策略。
从语义上讲,实现软删除引入了另一个逻辑层,它将行状态分为两个已删除状态。这是这种混乱交互的根源,处理它的最佳方法是不在 RLS 中使用软删除字段。
\n但是,如果您仍然想执行此操作,并且不喜欢< 1s在策略 \xe2\x80\x94 中包含该条件(这是有意义的),那么对于运行时间超过 1 秒的更新,这些条件将会失败 \xe2\x80\ x94 你仍然可以实现你想要的,但有一些干净的政策。
解决方案是创建一个特定的软删除函数,它将当前切换role到app_admin,软删除记录,然后将角色设置回app_user。当然,该函数必须检查 target 是否user_id与 current 匹配。user_id
尽管强烈不推荐,但沿着这些思路的东西会起作用
\ncreate or replace function soft_delete_user(del_id int)\n returns void as\n$$\nbegin\n if (del_id = get_current_user_id()) then\n set role = \'app_admin\';\n update my_table set deleted_at = now() where user_id = del_id;\n else\n raise exception \'mismatched IDs\';\n end if;\n set role = \'app_user\';\nend;\n\n$$ language \'plpgsql\';\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
707 次 |
| 最近记录: |