3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

PostgreSQL トリガー関数を Prisma + Supabase でうまく使う方法

Last updated at Posted at 2022-11-01

ある開発案件における、prismaでトリガー関数をうまくGitバージョン管理に含めたかったので、実践したその方法の紹介です。

トリガー関数をマイグレーション履歴に含めて開発が👍

Supabaseではダッシュボード上で、PostgreSQLのファンクションやトリガーを設定できます。

便利ですが、Git/Githubなどで開発を進めている場合、何もしないとソースコードに載ってこないのは不便です。

例えば開発用と本番用でデータベースを分けている場合、両方とも手動で設定しないといけないですし、

開発用などで頻繁にデータベースをリセットする場合は特に大変です。

Prismaは便利なORMサービスです。

マイグレーションもしっかりできるので、データベーススキーマ(モデル)定義は変更の都度、SQLファイルとして残っていきます。

プロジェクトでPrismaを使用している場合はこのマイグレーション履歴にトリガー関数のSQL文を含めることで、開発をスムーズに進めることが可能です。

前提

  • 今回はNext.jsのプロジェクトで使ってみたいと思いますが、Next.jsに限らず応用できる内容です。
  • DBについても今回はSupabaseですが、他でも問題ないと思います。
  • Supabaseの初期設定などについては解説しませんので、ググってみてください。

サンプルプロジェクトの準備

Next.jsはサンプルなので Create Next App で作成したいと思います。

npx create-next-app@latest --ts

prismaをインストールします。

yarn add -D prisma
yarn add @prisma/client

prismaを初期化します。

npx prisma init

プロジェクトに prisma ディレクトリが作成されます。

image.png

supabaseとの接続は詳細は省きますが、.envや.env.localなどのファイルに下記のように記載します。

それぞれの項目はご自身のsupabaseの情報に置き換えてください。

.env
DATABASE_URL=xxx
SUPABASE_URL=xxx
SUPABASE_KEY=xxx

Prismaスキーマ定義

prismaディレクトリの中のshema.prismaファイルにモデルを定義します。

今回はシンプルに下記のような例で定義します。

prisma/shema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model post {
  id    Int    @id @default(autoincrement())
  title String
}

model notification {
  id    Int    @id @default(autoincrement())
  title String
}

postテーブルは投稿を、 notificationテーブルはトリガー関数が実行された時に挿入される役目とします。

はじめのマイグレーション

それではまずはここで初めのマイグレーションを行なってみます。

npx prisma migrate dev

マイグレーション履歴の名前(フォルダ名)を求められますが、ここでは first_migration と入力しておきます。入力せずにエンターでも大丈夫です。

完了すると、次のように migrations フォルダや sql文が記載されたファイル(migration.sql)などが作成されます。

image.png

PrismaStudioを立ち上げてテーブルを確認してみます。

npx prisma studio

image.png

テーブルができています。

一応supabaseダッシュボードからも確認すると次のように作成されています。

image.png

サンプルとして投稿機能を実装

簡単に投稿機能をつけてみます。

pages/api 直下に posts.ts ファイルを作成し、postを作成するエンドポイントとします。

pages/api/posts.ts
import { PrismaClient } from "@prisma/client";
import { NextApiRequest, NextApiResponse } from "next";

const prisma = new PrismaClient();

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method === "POST") {
    const post = await prisma.post.create({
      data: {
        title: req.body.postTitle,
      },
    });
    if (!post) throw Error("not created");
    res.status(200).json(post);
  } else {
    res.setHeader("Allow", "POST");
    res.status(405).end("Method Not Allowed");
  }
}

次にpages直下のindex.tsxファイルを次のようにします。

pages/index.tsx
import type { NextPage } from "next";

const Home: NextPage = () => {
  const handleSubmit: React.FormEventHandler<HTMLFormElement> = async (e) => {
    e.preventDefault();
    const response = await fetch("/api/posts", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        postTitle: e.currentTarget.post_title.value,
      }),
    });
    const createdPost = await response.json();
    console.log(createdPost);
  };
  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input type="text" name="post_title" placeholder="post title" />
        <button type="submit">Submit</button>
      </form>
    </div>
  );
};

export default Home;

この状態で yarn dev でサーバーを立ち上げて確認してみます。

見にくいですがフォームが設置できています。

image.png

試しに TITLE 1 と入力して送信してみます。

うまくいけばコンソールに作成された post が表示されます。

image.png

Prisma Studio でも確認しておきます。

image.png

トリガー関数をマイグレーション履歴に含める

ここから本題のトリガー関数の作成です。

今回はサンプルとして、postテーブルに新しくレコードが挿入(INSERT)されたら、それをトリガーとして notificationテーブルにもレコードを挿入するようにします。

トリガー関数は shema.prisma に記載するわけではないので、sqlファイルを用意する必要があります。

prismaでは次のようにするとファイルのみ生成可能です。

npx prisma migrate dev --create-only

またまた名前を聞かれるので仮に trigger_function と入力しておきます。

image.png

xxx_trigger_function フォルダの中の migration.sql ファイルを編集します。

prisma/migrations/xxx_trigger_function/migration.sql
create or replace function public.insert_notification()
  returns trigger as $$
begin
  insert into public.notification(title) 
  values (new.title || ' was created');
  return new;
end;
$$ language plpgsql;

create trigger on_insert_post
  after insert
  on public.post
  for each row
  execute procedure public.insert_notification();
  • 関数名: insert_notification
  • トリガー名: on_insert_post

上記は post テーブルに新しくレコードが挿入された場合に発動し、

notificationテーブルにもレコードを生成します。

このとき、postレコードの title フィールドの値を使用して、

[その挿入されるレコードのタイトル] + " was created" という文字列とし、

notificationレコードのタイトルとします。

それではこれを適用するためにマイグレートを行います。

npx prisma migrate dev

supabaseを確認すると、Database > Functions のところに insert_notification という関数が作成されています。トリガーについても同様に作成されています。

image.png

では想定通り機能するか、試してみます。

まずはトップページで今度は TITLE 2 と入力して送信してみます。

image.png

これは通常通り postに追加されています。

image.png

合わせてトリガー関数がうまくいっているか、notificationテーブルを確認します。

image.png

notificationにもしっかりとデータが登録されていることが確認できました。

PrismaとSupabaseでトリガー関数を使う方法については以上です!

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?