Search code examples
sqlpostgresqlpostgresql-12

Postgres SQL function and trigger to insert record in another table


I need help to complete the following requirements:

  • [x] Profile table with columns id, username, ...
  • [x] Comment table with columns id, content, ...
  • [x] CommentReference table with columns id, profile_id, comment_id, ...

When a new comment is created, before inserting:

  • [ ] Check if NEW.content have references to usernames, like @someusername
  • [ ] Check if each reference exists in the profile table
  • [ ] For references that exist, insert into CommentReferences the profile and comment

For now, what I have is the following code:

PS: the following code has errors, I need help to fix it. I'm using postgres version 12.

CREATE FUNCTION create_comment_usernames_references()
RETURNS trigger AS $$
DECLARE usernames TEXT[];
DECLARE username TEXT;
DECLARE profile_id TEXT; -- profile_id is of type uuid, is it correct to use TEXT here?
BEGIN
  -- verify if there are usernames in the comment.content with the username regex
  SELECT DISTINCT(
    regexp_matches(
      NEW.content,
      '@(([a-z0-9]*((?<=[a-z0-9])[-|_|\.](?=[a-z0-9]))[a-z0-9]*)*|[a-z0-9]*)',
      'g'
    )
  )[1]
  INTO usernames;

  FOREACH username IN ARRAY usernames LOOP
    SELECT (SELECT id FROM "public"."Profile" WHERE "username" = username) INTO profile_id
    INSERT INTO "public"."CommentReference" (comment_id, profile_id) VALUES (NEW.id, profile_id);
  END LOOP;

  -- return nothing
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER create_comment_usernames_references_trigger
  BEFORE INSERT OR UPDATE ON "public"."Comment"
  FOR EACH ROW
  EXECUTE PROCEDURE create_comment_usernames_references();

Solution

  • Solve it myself.

    Final code:

    CREATE OR REPLACE FUNCTION find_profile_ids_by_usernames_in_text(_value TEXT)
        RETURNS TABLE (profile_id   uuid) AS
    $func$
    BEGIN
        RETURN QUERY
        SELECT
            id
        FROM
            "public"."Profile"
        WHERE
            username IN (
                SELECT DISTINCT(
                regexp_matches(
                    _value,
                    '@(([a-z0-9]*((?<=[a-z0-9])[-|_|\.](?=[a-z0-9]))[a-z0-9]*)*|[a-z0-9]*)',
                    'g')
                )[1]
            );
    END
    $func$  LANGUAGE plpgsql;
    
    
    CREATE OR REPLACE FUNCTION create_comment_reference(_comment_id UUID, _content TEXT)
    RETURNS integer AS $$
    DECLARE
        row RECORD;
    BEGIN
        FOR row IN
           SELECT * FROM find_profile_ids_by_usernames_in_text(_content)
        LOOP
            INSERT INTO
                "public"."CommentReference" (comment_id, profile_id)
            VALUES
                (_comment_id, row.profile_id)
            ON CONFLICT DO NOTHING;
        END LOOP;
        RETURN 1;
    END;
    $$ LANGUAGE plpgsql;
    
    
    CREATE OR REPLACE FUNCTION create_comment_reference_trigger_func()
    RETURNS trigger AS $$
    DECLARE someval integer;
    BEGIN
      select * from create_comment_reference(NEW.id, NEW.content) into someval;
      RETURN NULL;
    END;
    $$ LANGUAGE plpgsql;
    
    
    CREATE TRIGGER create_comment_usernames_references_trigger
      AFTER INSERT OR UPDATE ON "public"."Comment"
      FOR EACH ROW
      EXECUTE PROCEDURE create_comment_reference_trigger_func();