In my app, there are organizations that can create tasks. Instead of having a serial task ID, I would like to have an incrementing task ID for each organization ID. Just like in GitHub, where repo + issue number identifies the issue. Tasks look like this:
create table "Tasks" (
"organizationId" int references "Organizations"(id),
id int check (id > 0),
description text not null,
primary key ("organizationId", id)
);
Users should not "know" the ID when creating a task. How to set the ID automatically for each task?
I'm using PostgreSQL with PostgREST as an API. The solution ideally allows me to use PostgREST's CRUD APIs as is.
I've tried a before insert
trigger like this.
create function increment_task_id() returns trigger language
plpgsql security definer as $$
declare
next_id integer := 1;
begin
select coalesce(max("id") + 1, 1)
from "Tasks"
where "organizationId" = new."organizationId"
into next_id;
new.id = next_id;
return new;
end;$$;
create trigger task_insert
before insert on "Tasks"
for each row execute function increment_task_id();
This works fine until I run multiple insertions in parallel. The triggers seem to be executed in parallel, leading to some tasks failing the primary key constraint.
How can I avoid this? Is there a better way?