Open3

サービス層とリポジトリ層の責務の切り分け

hoshitahoshita

要件

イベントを管理するシステムを作る。
そこでイベントテーブルとイベントヒストリーテーブルを作成する。

イベント作成時はイベントテーブルとイベントヒストリーテーブルにデータをインサートする
更新時はイベントテーブルの該当レコードを更新し、イベントヒストリーテーブルにデータを作成する

hoshitahoshita

リファクタ前

仕様・要件

イベントの更新処理

指定された eventId に対応するイベントを更新する。
操作ユーザー(operationUser)の情報を履歴(eventHistory)とイベント(event)に記録する。

履歴管理

eventHistory を suffixNumber でバージョン管理。
最新の履歴を取得し、更新前の状態を保存。

トランザクション管理

履歴作成とイベント更新はトランザクションで処理し、一貫性を保証。

戻り値

更新処理完了後、更新されたイベントの id を返す。

service.ts
public async updateEvent(
    id: number,
    input: UpdateEventInput
  ): Promise<number> {
    const data = await this.eventRepository
      .updateEvent(id, input)
      .catch(() => {
        throw new NotFoundException('event id or event history is not found');
      });
    return data.id;
  }

repository.ts
public async updateEvent(
    eventId: number,
    input: UpdateEventInput
  ): Promise<Prisma.Prisma__EventClient<Event>> {
    const baseInfo: Pick<Event, 'uniqueId' | 'name' | 'createdAddress'> = {
      uniqueId: input.uniqueId,
      name: input.name,
      createdAddress: input.operationUser,
    };

    return this.prisma.$transaction(async (tx) => {
      // 最新のイベントデータを取得
      const latestEventHistory = await tx.eventHistory.findFirst({
        where: { id: eventId },
        orderBy: { suffixNumber: 'desc' },
      });
      if (!latestEventHistory)
        throw new NotFoundException('Event History not found');

      await tx.eventHistory.create({
        data: {
          ...baseInfo,
          id: eventId,
          suffixNumber: latestEventHistory.suffixNumber + 1,
          createdAddress: input.operationUser,
        },
      });

      const eventData = await tx.event.findUnique({
        where: { id: eventId },
      });
      if (!eventData) throw new NotFoundException('Event not found');

      return tx.event.update({
        where: { id: eventId },
        data: {
          ...baseInfo,
          updatedAddress: input.operationUser,
        },
      });
    });
  }

hoshitahoshita

リファクタ後

  • サービス層とリポジトリ層の責務の分離
  • 404と500の使い分け