create table public.grp_usr
  ( grp int not null references public.grp(id)
  , usr int not null references public.usr(id)
  , primary key (grp, usr)
  );

create function public.grp_add_member(to_grp int, add_usr int)
  returns void
  volatile
  language plpgsql
  as $$
begin
  insert into public.grp_usr (grp, usr) values (to_grp, add_usr);
end;
$$;

create function public.grp_add_members(to_grp int, add_usrs int[])
  returns void
  volatile
  language plpgsql
  as $$
begin
  insert into public.grp_usr (grp, usr)
  select grp, usr_id
  from unnest(add_usrs) usr_id
  left join public.grp_usr gu on gu.usr = usr_id and gu.grp = to_grp
  where gu is null;
end;
$$;

create function public.grp_members(of_grp int)
  returns setof public.usr
  stable
  language plpgsql
  as $$
begin
  return query select u.*
               from public.usr u
               inner join public.grp_usr gu
                 on gu.usr = u.id and gu.grp = of_grp;
end;
$$;

create function public.grp_members_admins()
  returns setof public.usr
  stable
  language plpgsql
  as $$
declare
  gid int;
begin
  select g.id
  from public.grp g
  where g.tag = public.grp_tag_of_string('admins')
  into gid;

  return query select * from public.grp_members(gid);
end;
$$;

create function public.grp_rm_member(from_grp int, rm_usr int)
  returns void
  volatile
  language plpgsql
  as $$
begin
  delete from public.grp_usr gu
  where gu.grp = from_grp and gu.usr = rm_usr;
end;
$$;
