🗽

Drizzleの relations() と references() の使い分け

2024/06/15に公開

こんにちは、合同会社Stegの keigo です。今回は、Drrizleでテーブルの関係性を定義する方法を紹介します。
Drizzle ORMは、テーブル間の関係性を定義するために、 relations()references()という2つの関数を提供しています。
これらの関数は役割が異なるため、注意が必要です。

今回のソースコードは、一部Drizzle公式ドキュメントから引用しています。
https://orm.drizzle.team/docs/rqb#declaring-relations

relations()references()の違い

Drizzle ORMにおいて、relations()references()はテーブル間の関係を定義するための同じ目的を持つ関数です。しかし、動作するレベルが異なります。

  • relations(): アプリケーションレベルで動作し、データベースには影響しない依存関係を設定する
  • references(): データベースレベルで動作し、外部キー制約を設定する

したがって、relations()のみを使用してテーブル間の関係を定義した場合、drizzle-kit generateでmigrationファイルを生成しようとしても、スキーマは変更が生じていないと判定されます。そのため、migrationファイルは生成されません。

https://orm.drizzle.team/docs/rqb#foreign-keys

relations()を使用したテーブル間の関係性定義

relations() 関数では、アプリケーションレベルでの依存関係を定義し、データベース側には影響しません。そのため、外部キーに対応していないDBでも、テーブルの関係性を定義することができます。
また、テーブル間の1対1や1対多、多対多といった関係性を宣言するために、one()関数やmany()関数を使用します。

次のコードは、以下の条件を表しています。

  • usersテーブルとpostsが1対多 (postsがnullの可能性あり)
  • postsテーブルとusersが1対1 (posts.author_idusers.idが紐づいている)
import { pgTable, serial, text, integer } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';
export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: text('name'),
});
export const usersRelations = relations(users, ({ many }) => ({
  posts: many(posts),
}));
export const posts = pgTable('posts', {
  id: serial('id').primaryKey(),
  content: text('content'),
  authorId: integer('author_id'),
});
export const postsRelations = relations(posts, ({ one }) => ({
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
  }),
}));

references()を使用したテーブル間の関係性定義

references()関数を使用することで、外部キーを設定することができます。

以下のコードでは、usersテーブルのidとprofile_infoテーブルのuser_idの関係性を表しています。

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: text('name'),
});

export const profileInfo = pgTable('profile_info', {
  id: serial('id').primaryKey(),
  userId: integer("user_id").references(() => users.id),
  metadata: jsonb("metadata"),
});

上記の定義により、users.idprofile_info.user_idに対して外部キー制約が設定されます。
生成されたSQLは以下のとおりです。

CREATE TABLE IF NOT EXISTS "profile_info" (
	"id" serial PRIMARY KEY NOT NULL,
	"user_id" integer,
	"metadata" jsonb
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "users" (
	"id" serial PRIMARY KEY NOT NULL,
	"name" text
);
--> statement-breakpoint
DO $$ BEGIN
 ALTER TABLE "profile_info" ADD CONSTRAINT "profile_info_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
 WHEN duplicate_object THEN null;
END $$;

おわりに

今回は、Drizzle ORMを使用してテーブル間の関連を定義する方法を紹介しました。

relations()references()に関する詳細は、Drizzle ORM公式ドキュメントをご覧ください。

https://orm.drizzle.team/docs/rqb#declaring-relations

Steg Inc.

Discussion