프리스마2의transaction 질문을 Active Record 스타일로 쓰고 싶어요.

Activer Record 및 Eloquent에 익숙하면 거래 가능👇이렇게 써.
mysql2의 예.
import * as mysql2 from 'mysql2/promise';

const db = await mysql.createConnection({
  host: 'localhost',
  user: 'root',
  database: 'test'
});

await db.begin();

if(//何らかのロジック処理) {
 
   //何らかのデータベースアクセス
 
   await db.commit();

} else {

   await db.rollback();

}

만약 이것이 Prism이라면 현 버전 3.2.1은 안 된다.
대체로 공식적으로 몇 가지 거래 방법이 있다.( transactions )Primse.All에 배열된 데이터 접근 처리를 실행하고 그 중 하나가 실패하면 다른 접근도 굴러갑니다.

const [posts, totalPosts] = await prisma.$transaction([
  prisma.post.findMany({ where: { title: { contains: 'prisma' } } }),
  prisma.post.count(),
])

그 배열에prisma 이외의 상업 논리를 넣으면 안 되는 것과 (틀릴 가능성도 있다) 첫 번째 성공한 값은 두 번째Promise에서 사용할 때 복잡해진다.
그리고 하나는 관련 표에 데이터를 동시에 입력하는 거예요.

// Create a new user with two posts in a
// single transaction
const newUser: User = await prisma.user.create({
  data: {
    email: '[email protected]',
    posts: {
      create: [
        { title: 'Join the Prisma Slack on https://slack.prisma.io' },
        { title: 'Follow @prisma on Twitter' },
      ],
    },
  },
})

이것도 내가 직면한 문제를 해결할 수 없다.
다만, 버전 2.29.0에서 「Interactive Transactions」까지의 미리보기 기능이 설치된 것 같습니다.👇이렇게 쓰면
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()

async function transfer(from: string, to: string, amount: number) {
  return await prisma.$transaction(async (prisma) => {
    // 1. Decrement amount from the sender.
    const sender = await prisma.account.update({
      data: {
        balance: {
          decrement: amount,
        },
      },
      where: {
        email: from,
      },
    })
    // 2. Verify that the sender's balance didn't go below zero.
    if (sender.balance < 0) {
      throw new Error(`${from} doesn't have enough to send ${amount}`)
    }
    // 3. Increment the recipient's balance by amount
    const recipient = prisma.account.update({
      data: {
        balance: {
          increment: amount,
        },
      },
      where: {
        email: to,
      },
    })
    return recipient
  })
}

async function main() {
  // This transfer is successful
  await transfer('[email protected]', '[email protected]', 100)
  // This transfer fails because Alice doesn't have enough funds in her account
  await transfer('[email protected]', '[email protected]', 100)
}

main()
  .catch(console.error)
  .finally(() => {
    prisma.$disconnect()
  })


우선 ASync function에서 예외가 발생한 경우 롤백이 자동으로 뛰는 것 같아서 괜찮은 것 같다.
미리 보기 기능이기 때문에 prisma.schema을 사용하려면 파일에 설명을 추가해야 합니다.
prisma.schema

generator client {
  provider = "prisma-client-js"
  previewFeatures = ["interactiveTransactions"]
}

상관은 없지만 거래하는 동안 모델의 함수로 컨트롤러로부터 거래를 하면서 사업 논리와 다른 처리를 하고 싶어서 제가 직접 포장을 해서 적어보려고요.
userModel.ts

//...省略...

async createUser(
    user: User,
    callback?: (newUser?: User) => Promise<void>,
  ): Promise<User> {
  
    const createNewUser = (db?: PrismaTransactionCallBackInstance) => {
      const connection = db || this.db;
      return connection.user.create({
        data: {
          ...user
        },
        select: {
          email: true,
          id: true,
        },
      });
    };

    try {
      if (callback && typeof callback === 'function') {
        const resultUser = await this.db.$transaction(async (db) => {
          const result = await createNewUser(db);
          await callback(result);

          return result;
        });
      } else {
        const resultUser = await createNewUser();
      }

      return resultUser;
    } catch (error) {
      throw error;
    }
  }
  
  //...省略...

authController.ts
 //...省略...
	
  async signUp() {
    try {
      //承認用のランダムの文字列作成
      const confirmationCode = this.authService.generateConfirmationCode();

      //userオブジェクト作成
      const user = new User({//user情報登録});

      //usecaseの呼び出し
      await this.userModel.createUser(user, async (newUser: User) => {
        //承認メールの送信
        await this.mailer.sendVerification({
          email: newUser.email,
          confirmationCode,
        });
      });

      return 'success';
    } catch (error) {
      console.log('outside catch');
      throw error;
    }
  }
	
 //...省略...
이렇게 하면 메일을 모델에 보내지 않고 실행할 수 있다.

좋은 웹페이지 즐겨찾기