Transactions in supabase – Transactions

by
Ali Hasan
postgresql supabase transactions

The Problem:

In a relational database, sometimes it is necessary to create or update multiple tables simultaneously while maintaining data integrity. For example, in a blogging application, creating a new blog post may require the creation of a new post record in the Posts table and a new comment record in the Comments table. Is there a way to execute these operations as a single atomic transaction using Supabase, a popular PostgreSQL-based database-as-a-service platform?

The Solutions:

Solution 1: Using Postgres Function and RPC

This solution involves defining a PostgreSQL function that encapsulates the logic for creating a new post and a new comment, and then calling this function using Supabase’s RPC (Remote Procedure Call) feature:

  1. Define a Postgres Function:
CREATE OR REPLACE FUNCTION create_post_and_comment(
    post_title TEXT,
    post_body TEXT,
    comment_body TEXT
) RETURNS VOID AS $$
BEGIN
    -- Insert a new post into the "posts" table
    INSERT INTO posts (title, body)
    VALUES (post_title, post_body)
    RETURNING id INTO id;

    -- Insert a new comment into the "comments" table
    INSERT INTO comments (post_id, body)
    VALUES (id, comment_body);
END;
$$ LANGUAGE plpgsql;

This function takes three parameters: post_title, post_body, and comment_body. It inserts a new post into the posts table, returning the generated id of the post. It then uses this id to insert a new comment into the comments table.

  1. Call the Postgres Function Using Supabase RPC:
// Create a new post and comment using RPC
const { data, error } = await supabase.rpc('create_post_and_comment', {
  post_title: 'New Post Title',
  post_body: 'Body of the New Post',
  comment_body: 'Comment on the New Post',
});

This code calls the create_post_and_comment Postgres function using Supabase’s rpc() method. It passes the necessary parameters to the function and handles the response. If the function execution is successful, the data variable will contain the result (void in this case), and error will be null. Otherwise, error will contain information about the error.

Solution 2: Using Trigger and Default Comment

This solution involves creating a trigger on the posts table that automatically inserts a default comment into the comments table whenever a new post is created:

  1. Create a Postgres Function for Inserting Comments:
-- Create a function that inserts a comment
CREATE OR REPLACE FUNCTION insert_comment()
RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO comments (post_id, body)
    VALUES (NEW.id, 'Default comment text'); -- You can change the default comment text as needed
    RETURN NULL; -- Returning NULL because we are only inserting into "comments" and not modifying the "posts" table
END;
$$ LANGUAGE plpgsql;

This function is responsible for inserting a new comment into the comments table. It takes the post_id from the newly inserted post and inserts a default comment.

  1. Create a Trigger to Execute the Function:
-- Create a trigger that fires after inserting into "posts"
CREATE TRIGGER after_insert_post
AFTER INSERT ON posts
FOR EACH ROW
EXECUTE FUNCTION insert_comment();

This trigger is executed after each insert operation on the posts table. When a new post is created, it calls the insert_comment() function, which automatically inserts a default comment for the new post.

Using this solution, you can ensure that every newly created post has at least one comment by utilizing the power of triggers and default values in PostgreSQL.

Q&A

How to create a Post and a related Comment in a single transaction?

Use a PostgreSQL function or trigger to encapsulate the logic.

How to encapsulate the logic in a Postgres function?

Use CREATE OR REPLACE FUNCTION to create a Postgres function.

How to create a trigger on the post table?

Use CREATE OR REPLACE FUNCTION and CREATE TRIGGER to create a PostgreSQL trigger.

Video Explanation:

The following video, titled "Scaling Postgres Episode 195 Aurora vs. Postgres, Surprising ...", provides additional insights and in-depth exploration related to the topics discussed in this post.

Play video

... transactions 08:23 - Taking Advantage of write-only and read-only Connections with pgBouncer in Django 10:26 - Some indexing best practices ...